diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2022-04-17 15:10:36 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-17 15:10:36 (GMT) |
commit | 7659681556977fe3a19d9f4c5dd93362b9eae25c (patch) | |
tree | 863d22344a00d1bd1ceb5e34a020680f54812385 | |
parent | 67712e71b3f20541326d57a475f4bd369a98d918 (diff) | |
download | cpython-7659681556977fe3a19d9f4c5dd93362b9eae25c.zip cpython-7659681556977fe3a19d9f4c5dd93362b9eae25c.tar.gz cpython-7659681556977fe3a19d9f4c5dd93362b9eae25c.tar.bz2 |
gh-91298: Refine traversable (apply changes from importlib_resources 5.7.1) (#91623)
* bpo-47142: Refine traversable (apply changes from importlib_resources 5.7.1)
* Replace changelog referencing github issue.
-rw-r--r-- | Lib/importlib/resources/abc.py | 39 | ||||
-rw-r--r-- | Lib/importlib/resources/simple.py | 15 | ||||
-rwxr-xr-x | Lib/test/test_importlib/update-zips.py | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Documentation/2022-04-17-03-19-51.gh-issue-91298.NT9qHi.rst | 2 |
4 files changed, 42 insertions, 16 deletions
diff --git a/Lib/importlib/resources/abc.py b/Lib/importlib/resources/abc.py index e9efdab..0b7bfdc 100644 --- a/Lib/importlib/resources/abc.py +++ b/Lib/importlib/resources/abc.py @@ -1,6 +1,14 @@ import abc -from typing import BinaryIO, Iterable, Text +import io +import os +from typing import Any, BinaryIO, Iterable, Iterator, NoReturn, Text, Optional from typing import runtime_checkable, Protocol +from typing import Union + + +StrPath = Union[str, os.PathLike[str]] + +__all__ = ["ResourceReader", "Traversable", "TraversableResources"] class ResourceReader(metaclass=abc.ABCMeta): @@ -50,22 +58,25 @@ class Traversable(Protocol): """ An object with a subset of pathlib.Path methods suitable for traversing directories and opening files. + + Any exceptions that occur when accessing the backing resource + may propagate unaltered. """ @abc.abstractmethod - def iterdir(self): + def iterdir(self) -> Iterator["Traversable"]: """ Yield Traversable objects in self """ - def read_bytes(self): + def read_bytes(self) -> bytes: """ Read contents of self as bytes """ with self.open('rb') as strm: return strm.read() - def read_text(self, encoding=None): + def read_text(self, encoding: Optional[str] = None) -> str: """ Read contents of self as text """ @@ -85,12 +96,16 @@ class Traversable(Protocol): """ @abc.abstractmethod - def joinpath(self, child): + def joinpath(self, *descendants: StrPath) -> "Traversable": """ - Return Traversable child in self + Return Traversable resolved with any descendants applied. + + Each descendant should be a path segment relative to self + and each may contain multiple levels separated by + ``posixpath.sep`` (``/``). """ - def __truediv__(self, child): + def __truediv__(self, child: StrPath) -> "Traversable": """ Return Traversable child in self """ @@ -120,17 +135,17 @@ class TraversableResources(ResourceReader): """ @abc.abstractmethod - def files(self): + def files(self) -> "Traversable": """Return a Traversable object for the loaded package.""" - def open_resource(self, resource): + def open_resource(self, resource: StrPath) -> io.BufferedReader: return self.files().joinpath(resource).open('rb') - def resource_path(self, resource): + def resource_path(self, resource: Any) -> NoReturn: raise FileNotFoundError(resource) - def is_resource(self, path): + def is_resource(self, path: StrPath) -> bool: return self.files().joinpath(path).is_file() - def contents(self): + def contents(self) -> Iterator[str]: return (item.name for item in self.files().iterdir()) diff --git a/Lib/importlib/resources/simple.py b/Lib/importlib/resources/simple.py index da073cb..d0fbf23 100644 --- a/Lib/importlib/resources/simple.py +++ b/Lib/importlib/resources/simple.py @@ -99,10 +99,19 @@ class ResourceContainer(Traversable): def open(self, *args, **kwargs): raise IsADirectoryError() - def joinpath(self, name): + @staticmethod + def _flatten(compound_names): + for name in compound_names: + yield from name.split('/') + + def joinpath(self, *descendants): + if not descendants: + return self + names = self._flatten(descendants) + target = next(names) return next( - traversable for traversable in self.iterdir() if traversable.name == name - ) + traversable for traversable in self.iterdir() if traversable.name == target + ).joinpath(*names) class TraversableReader(TraversableResources, SimpleReader): diff --git a/Lib/test/test_importlib/update-zips.py b/Lib/test/test_importlib/update-zips.py index 9ef0224..231334a 100755 --- a/Lib/test/test_importlib/update-zips.py +++ b/Lib/test/test_importlib/update-zips.py @@ -42,7 +42,7 @@ def generate(suffix): def walk(datapath): for dirpath, dirnames, filenames in os.walk(datapath): - with contextlib.suppress(KeyError): + with contextlib.suppress(ValueError): dirnames.remove('__pycache__') for filename in filenames: res = pathlib.Path(dirpath) / filename diff --git a/Misc/NEWS.d/next/Documentation/2022-04-17-03-19-51.gh-issue-91298.NT9qHi.rst b/Misc/NEWS.d/next/Documentation/2022-04-17-03-19-51.gh-issue-91298.NT9qHi.rst new file mode 100644 index 0000000..471a7ce --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-04-17-03-19-51.gh-issue-91298.NT9qHi.rst @@ -0,0 +1,2 @@ +In ``importlib.resources.abc``, refined the documentation of the Traversable +Protocol, applying changes from importlib_resources 5.7.1. |