Skip to content

Commit fe9dbf6

Browse files
authored
Merge pull request #289 from python/refactor/multiplexed-path-traversables
Add support for Traversables in MultiplexedPath
2 parents 0f89eb3 + f23b743 commit fe9dbf6

File tree

5 files changed

+39
-11
lines changed

5 files changed

+39
-11
lines changed

importlib_resources/_compat.py

+17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import sys
66
import pathlib
7+
import warnings
78
from contextlib import suppress
89
from typing import Union
910

@@ -107,3 +108,19 @@ def wrap_spec(package):
107108
else:
108109
# PathLike is only subscriptable at runtime in 3.9+
109110
StrPath = Union[str, "os.PathLike[str]"]
111+
112+
113+
def ensure_traversable(path):
114+
"""
115+
Convert deprecated string arguments to traversables (pathlib.Path).
116+
"""
117+
if not isinstance(path, str):
118+
return path
119+
120+
warnings.warn(
121+
"String arguments are deprecated. Pass a Traversable instead.",
122+
DeprecationWarning,
123+
stacklevel=3,
124+
)
125+
126+
return pathlib.Path(path)

importlib_resources/readers.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from . import abc
77

88
from ._itertools import only
9-
from ._compat import ZipPath
9+
from ._compat import ZipPath, ensure_traversable
1010

1111

1212
def remove_duplicates(items):
@@ -62,7 +62,7 @@ class MultiplexedPath(abc.Traversable):
6262
"""
6363

6464
def __init__(self, *paths):
65-
self._paths = list(map(pathlib.Path, remove_duplicates(paths)))
65+
self._paths = list(map(ensure_traversable, remove_duplicates(paths)))
6666
if not self._paths:
6767
message = 'MultiplexedPath must contain at least one path'
6868
raise FileNotFoundError(message)

importlib_resources/tests/test_reader.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@
1010
class MultiplexedPathTest(unittest.TestCase):
1111
@classmethod
1212
def setUpClass(cls):
13-
path = pathlib.Path(__file__).parent / 'namespacedata01'
14-
cls.folder = str(path)
13+
cls.folder = pathlib.Path(__file__).parent / 'namespacedata01'
1514

1615
def test_init_no_paths(self):
1716
with self.assertRaises(FileNotFoundError):
1817
MultiplexedPath()
1918

2019
def test_init_file(self):
2120
with self.assertRaises(NotADirectoryError):
22-
MultiplexedPath(os.path.join(self.folder, 'binary.file'))
21+
MultiplexedPath(self.folder / 'binary.file')
2322

2423
def test_iterdir(self):
2524
contents = {path.name for path in MultiplexedPath(self.folder).iterdir()}
@@ -30,7 +29,7 @@ def test_iterdir(self):
3029
self.assertEqual(contents, {'binary.file', 'utf-16.file', 'utf-8.file'})
3130

3231
def test_iterdir_duplicate(self):
33-
data01 = os.path.abspath(os.path.join(__file__, '..', 'data01'))
32+
data01 = pathlib.Path(__file__).parent.joinpath('data01')
3433
contents = {
3534
path.name for path in MultiplexedPath(self.folder, data01).iterdir()
3635
}
@@ -60,8 +59,8 @@ def test_open_file(self):
6059
path.open()
6160

6261
def test_join_path(self):
63-
prefix = os.path.abspath(os.path.join(__file__, '..'))
64-
data01 = os.path.join(prefix, 'data01')
62+
data01 = pathlib.Path(__file__).parent.joinpath('data01')
63+
prefix = str(data01.parent)
6564
path = MultiplexedPath(self.folder, data01)
6665
self.assertEqual(
6766
str(path.joinpath('binary.file'))[len(prefix) + 1 :],
@@ -82,9 +81,9 @@ def test_join_path_compound(self):
8281
assert not path.joinpath('imaginary/foo.py').exists()
8382

8483
def test_join_path_common_subdir(self):
85-
prefix = os.path.abspath(os.path.join(__file__, '..'))
86-
data01 = os.path.join(prefix, 'data01')
87-
data02 = os.path.join(prefix, 'data02')
84+
data01 = pathlib.Path(__file__).parent.joinpath('data01')
85+
data02 = pathlib.Path(__file__).parent.joinpath('data02')
86+
prefix = str(data01.parent)
8887
path = MultiplexedPath(data01, data02)
8988
self.assertIsInstance(path.joinpath('subdirectory'), MultiplexedPath)
9089
self.assertEqual(

importlib_resources/tests/test_resource.py

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import importlib_resources as resources
44
import pathlib
55

6+
import pytest
7+
68
from . import data01
79
from . import util
810
from importlib import import_module
@@ -209,5 +211,14 @@ def tearDownClass(cls):
209211
sys.path.remove(cls.site_dir)
210212

211213

214+
@pytest.mark.xfail
215+
class ResourceFromNamespaceZipTests(
216+
util.ZipSetupBase,
217+
ResourceFromNamespaceTests,
218+
unittest.TestCase,
219+
):
220+
ZIP_MODULE = 'namespacedata01'
221+
222+
212223
if __name__ == '__main__':
213224
unittest.main()

newsfragments/+13deb64a.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MultiplexedPath now expects Traversable paths. String arguments to MultiplexedPath are now deprecated.

0 commit comments

Comments
 (0)