Skip to content

Commit

Permalink
Merge pull request #289 from python/refactor/multiplexed-path-travers…
Browse files Browse the repository at this point in the history
…ables

Add support for Traversables in MultiplexedPath
  • Loading branch information
jaraco authored Sep 19, 2023
2 parents 0f89eb3 + f23b743 commit fe9dbf6
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 11 deletions.
17 changes: 17 additions & 0 deletions importlib_resources/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import sys
import pathlib
import warnings
from contextlib import suppress
from typing import Union

Expand Down Expand Up @@ -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)
4 changes: 2 additions & 2 deletions importlib_resources/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down
17 changes: 8 additions & 9 deletions importlib_resources/tests/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@
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):
MultiplexedPath()

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()}
Expand All @@ -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()
}
Expand Down Expand Up @@ -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 :],
Expand All @@ -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(
Expand Down
11 changes: 11 additions & 0 deletions importlib_resources/tests/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import importlib_resources as resources
import pathlib

import pytest

from . import data01
from . import util
from importlib import import_module
Expand Down Expand Up @@ -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()
1 change: 1 addition & 0 deletions newsfragments/+13deb64a.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MultiplexedPath now expects Traversable paths. String arguments to MultiplexedPath are now deprecated.

0 comments on commit fe9dbf6

Please sign in to comment.