diff --git a/importlib_resources/_adapters.py b/importlib_resources/_adapters.py index 9907b148..4f898a50 100644 --- a/importlib_resources/_adapters.py +++ b/importlib_resources/_adapters.py @@ -55,11 +55,19 @@ def __init__(self, spec, reader): self._spec = spec self._reader = reader + @classmethod + def new(cls, spec, reader): + try: + fspath = reader.resource_path(None) + except (FileNotFoundError, AttributeError): + return cls(spec, reader) + return CompatibilityFiles.PathLikeSpecPath(spec, reader, fspath) + def iterdir(self): if not self._reader: return iter(()) return iter( - CompatibilityFiles.ChildPath(self._reader, path) + CompatibilityFiles.ChildPath.new(self._reader, path) for path in self._reader.contents() ) @@ -71,7 +79,7 @@ def is_file(self): def joinpath(self, other): if not self._reader: return CompatibilityFiles.OrphanPath(other) - return CompatibilityFiles.ChildPath(self._reader, other) + return CompatibilityFiles.ChildPath.new(self._reader, other) @property def name(self): @@ -80,6 +88,16 @@ def name(self): def open(self, mode='r', *args, **kwargs): return _io_wrapper(self._reader.open_resource(None), mode, *args, **kwargs) + class PathLikeSpecPath(SpecPath): + """SpecPath but os.PathLike""" + + def __init__(self, spec, reader, fspath): + super().__init__(spec, reader) + self._fspath = fspath + + def __fspath__(self): + return self._fspath + class ChildPath(abc.Traversable): """ Path tied to a resource reader child. @@ -90,6 +108,14 @@ def __init__(self, reader, name): self._reader = reader self._name = name + @classmethod + def new(cls, reader, name): + try: + fspath = reader.resource_path(name) + except (FileNotFoundError, AttributeError): + return cls(reader, name) + return CompatibilityFiles.PathLikeChildPath(reader, name, fspath) + def iterdir(self): return iter(()) @@ -111,6 +137,16 @@ def open(self, mode='r', *args, **kwargs): self._reader.open_resource(self.name), mode, *args, **kwargs ) + class PathLikeChildPath(ChildPath): + """ChildPath but os.PathLike""" + + def __init__(self, reader, name, fspath): + super().__init__(reader, name) + self._fspath = fspath + + def __fspath__(self): + return self._fspath + class OrphanPath(abc.Traversable): """ Orphan path, not tied to a module spec or resource reader. @@ -159,7 +195,7 @@ def __getattr__(self, attr): return getattr(self._reader, attr) def files(self): - return CompatibilityFiles.SpecPath(self.spec, self._reader) + return CompatibilityFiles.SpecPath.new(self.spec, self._reader) def wrap_spec(package): diff --git a/importlib_resources/tests/test_compatibilty_files.py b/importlib_resources/tests/test_compatibilty_files.py index d92c7c56..6742804f 100644 --- a/importlib_resources/tests/test_compatibilty_files.py +++ b/importlib_resources/tests/test_compatibilty_files.py @@ -1,4 +1,5 @@ import io +import os import unittest import importlib_resources as resources @@ -88,6 +89,10 @@ def test_wrap_spec(self): spec = wrap_spec(self.package) self.assertIsInstance(spec.loader.get_resource_reader(None), CompatibilityFiles) + def test_fspath(self): + self.assertEqual(os.fspath(self.files), 'some_path') + self.assertEqual(os.fspath(self.files / 'a'), 'some_path') + class CompatibilityFilesNoReaderTests(unittest.TestCase): @property