Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions Lib/importlib/resources/_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,14 @@ def is_file(self):

is_dir = is_file

def joinpath(self, other):
def joinpath(self, *descendants):
if not descendants:
return self
if not self._reader:
return CompatibilityFiles.OrphanPath(other)
return CompatibilityFiles.ChildPath(self._reader, other)
return CompatibilityFiles.OrphanPath(*descendants)
first, *rest = descendants
child = CompatibilityFiles.ChildPath(self._reader, first)
return child.joinpath(*rest)

@property
def name(self):
Expand Down Expand Up @@ -97,8 +101,10 @@ def is_file(self):
def is_dir(self):
return not self.is_file()

def joinpath(self, other):
return CompatibilityFiles.OrphanPath(self.name, other)
def joinpath(self, *descendants):
if not descendants:
return self
return CompatibilityFiles.OrphanPath(self.name, *descendants)

@property
def name(self):
Expand Down Expand Up @@ -128,8 +134,10 @@ def is_file(self):

is_dir = is_file

def joinpath(self, other):
return CompatibilityFiles.OrphanPath(*self._path, other)
def joinpath(self, *descendants):
if not descendants:
return self
return CompatibilityFiles.OrphanPath(*self._path, *descendants)

@property
def name(self):
Expand Down
44 changes: 44 additions & 0 deletions Lib/test/test_importlib/resources/test_compatibilty_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
wrap_spec,
)

from test.support import warnings_helper

from . import util


Expand Down Expand Up @@ -79,6 +81,37 @@ def test_orphan_path_invalid(self):
with self.assertRaises(ValueError):
CompatibilityFiles.OrphanPath()

def test_spec_path_joinpath_no_descendants(self):
files = self.files
assert files.joinpath() is files

def test_child_path_joinpath_no_descendants(self):
child = self.files / 'a'
assert child.joinpath() is child

def test_orphan_path_joinpath_no_descendants(self):
orphan = self.files / 'a' / 'b'
assert orphan.joinpath() is orphan

def test_joinpath_multiple_descendants(self):
# Several descendants at once give the same result as applying them
# one at a time, as documented for Traversable.joinpath().
files = self.files
for path, expected in (
(files.joinpath('a', 'b'), files / 'a' / 'b'),
((files / 'a').joinpath('b', 'c'), files / 'a' / 'b' / 'c'),
((files / 'a' / 'b').joinpath('c', 'd'), files / 'a' / 'b' / 'c' / 'd'),
):
assert isinstance(path, CompatibilityFiles.OrphanPath)
assert path._path == expected._path

def test_functional_api_without_path_names(self):
# gh-127337: these call joinpath() with no descendants at all.
package = self.package
with warnings_helper.check_warnings((".*contents.*", DeprecationWarning)):
assert sorted(resources.contents(package)) == ['a', 'b', 'c']
assert not resources.is_resource(package)

def test_wrap_spec(self):
spec = wrap_spec(self.package)
assert isinstance(spec.loader.get_resource_reader(None), CompatibilityFiles)
Expand All @@ -95,3 +128,14 @@ def files(self):

def test_spec_path_joinpath(self):
assert isinstance(self.files / 'a', CompatibilityFiles.OrphanPath)

def test_spec_path_joinpath_no_descendants(self):
# Returns self rather than an OrphanPath with no parts, which would
# be rejected by OrphanPath.__init__().
files = self.files
assert files.joinpath() is files

def test_spec_path_joinpath_multiple_descendants(self):
path = self.files.joinpath('a', 'b')
assert isinstance(path, CompatibilityFiles.OrphanPath)
assert path._path == (self.files / 'a' / 'b')._path
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Fix a regression in :mod:`importlib.resources` where functions such as
:func:`~importlib.resources.is_resource` and
:func:`~importlib.resources.contents` raised :exc:`TypeError` for a package
whose loader provides only a legacy
:class:`~importlib.resources.abc.ResourceReader`. The internal
``CompatibilityFiles`` traversables wrapping such a reader now accept the
zero-or-more argument ``joinpath()`` signature specified by
:meth:`importlib.resources.abc.Traversable.joinpath`.
Patch by pikammmmm.
Loading