summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2022-04-17 15:10:36 (GMT)
committerGitHub <noreply@github.com>2022-04-17 15:10:36 (GMT)
commit7659681556977fe3a19d9f4c5dd93362b9eae25c (patch)
tree863d22344a00d1bd1ceb5e34a020680f54812385
parent67712e71b3f20541326d57a475f4bd369a98d918 (diff)
downloadcpython-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.py39
-rw-r--r--Lib/importlib/resources/simple.py15
-rwxr-xr-xLib/test/test_importlib/update-zips.py2
-rw-r--r--Misc/NEWS.d/next/Documentation/2022-04-17-03-19-51.gh-issue-91298.NT9qHi.rst2
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.