Skip to content

Add support for Traversables in MultiplexedPath #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 19, 2023
Merged
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
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.