diff --git a/importlib_resources/_compat.py b/importlib_resources/_compat.py index a93a882..d7e9f0d 100644 --- a/importlib_resources/_compat.py +++ b/importlib_resources/_compat.py @@ -4,6 +4,7 @@ import os import sys import pathlib +import warnings from contextlib import suppress from typing import Union @@ -107,3 +108,19 @@ def wrap_spec(package): else: # PathLike is only subscriptable at runtime in 3.9+ StrPath = Union[str, "os.PathLike[str]"] + + +def ensure_traversable(path): + """ + Convert deprecated string arguments to traversables (pathlib.Path). + """ + if not isinstance(path, str): + return path + + warnings.warn( + "String arguments are deprecated. Pass a Traversable instead.", + DeprecationWarning, + stacklevel=3, + ) + + return pathlib.Path(path) diff --git a/importlib_resources/readers.py b/importlib_resources/readers.py index 51d030a..dc1ec94 100644 --- a/importlib_resources/readers.py +++ b/importlib_resources/readers.py @@ -6,7 +6,7 @@ from . import abc from ._itertools import only -from ._compat import ZipPath +from ._compat import ZipPath, ensure_traversable def remove_duplicates(items): @@ -62,7 +62,7 @@ class MultiplexedPath(abc.Traversable): """ def __init__(self, *paths): - self._paths = list(map(pathlib.Path, remove_duplicates(paths))) + self._paths = list(map(ensure_traversable, remove_duplicates(paths))) if not self._paths: message = 'MultiplexedPath must contain at least one path' raise FileNotFoundError(message) diff --git a/importlib_resources/tests/test_reader.py b/importlib_resources/tests/test_reader.py index e2bdf19..a1eadb2 100644 --- a/importlib_resources/tests/test_reader.py +++ b/importlib_resources/tests/test_reader.py @@ -10,8 +10,7 @@ class MultiplexedPathTest(unittest.TestCase): @classmethod def setUpClass(cls): - path = pathlib.Path(__file__).parent / 'namespacedata01' - cls.folder = str(path) + cls.folder = pathlib.Path(__file__).parent / 'namespacedata01' def test_init_no_paths(self): with self.assertRaises(FileNotFoundError): @@ -19,7 +18,7 @@ def test_init_no_paths(self): def test_init_file(self): with self.assertRaises(NotADirectoryError): - MultiplexedPath(os.path.join(self.folder, 'binary.file')) + MultiplexedPath(self.folder / 'binary.file') def test_iterdir(self): contents = {path.name for path in MultiplexedPath(self.folder).iterdir()} @@ -30,7 +29,7 @@ def test_iterdir(self): self.assertEqual(contents, {'binary.file', 'utf-16.file', 'utf-8.file'}) def test_iterdir_duplicate(self): - data01 = os.path.abspath(os.path.join(__file__, '..', 'data01')) + data01 = pathlib.Path(__file__).parent.joinpath('data01') contents = { path.name for path in MultiplexedPath(self.folder, data01).iterdir() } @@ -60,8 +59,8 @@ def test_open_file(self): path.open() def test_join_path(self): - prefix = os.path.abspath(os.path.join(__file__, '..')) - data01 = os.path.join(prefix, 'data01') + data01 = pathlib.Path(__file__).parent.joinpath('data01') + prefix = str(data01.parent) path = MultiplexedPath(self.folder, data01) self.assertEqual( str(path.joinpath('binary.file'))[len(prefix) + 1 :], @@ -82,9 +81,9 @@ def test_join_path_compound(self): assert not path.joinpath('imaginary/foo.py').exists() def test_join_path_common_subdir(self): - prefix = os.path.abspath(os.path.join(__file__, '..')) - data01 = os.path.join(prefix, 'data01') - data02 = os.path.join(prefix, 'data02') + data01 = pathlib.Path(__file__).parent.joinpath('data01') + data02 = pathlib.Path(__file__).parent.joinpath('data02') + prefix = str(data01.parent) path = MultiplexedPath(data01, data02) self.assertIsInstance(path.joinpath('subdirectory'), MultiplexedPath) self.assertEqual( diff --git a/importlib_resources/tests/test_resource.py b/importlib_resources/tests/test_resource.py index 4036805..850d029 100644 --- a/importlib_resources/tests/test_resource.py +++ b/importlib_resources/tests/test_resource.py @@ -3,6 +3,8 @@ import importlib_resources as resources import pathlib +import pytest + from . import data01 from . import util from importlib import import_module @@ -209,5 +211,14 @@ def tearDownClass(cls): sys.path.remove(cls.site_dir) +@pytest.mark.xfail +class ResourceFromNamespaceZipTests( + util.ZipSetupBase, + ResourceFromNamespaceTests, + unittest.TestCase, +): + ZIP_MODULE = 'namespacedata01' + + if __name__ == '__main__': unittest.main() diff --git a/newsfragments/+13deb64a.feature.rst b/newsfragments/+13deb64a.feature.rst new file mode 100644 index 0000000..a765911 --- /dev/null +++ b/newsfragments/+13deb64a.feature.rst @@ -0,0 +1 @@ +MultiplexedPath now expects Traversable paths. String arguments to MultiplexedPath are now deprecated. \ No newline at end of file