Skip to content

Commit 7659681

Browse files
authored
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.
1 parent 67712e7 commit 7659681

File tree

4 files changed

+42
-16
lines changed

4 files changed

+42
-16
lines changed

Lib/importlib/resources/abc.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import abc
2-
from typing import BinaryIO, Iterable, Text
2+
import io
3+
import os
4+
from typing import Any, BinaryIO, Iterable, Iterator, NoReturn, Text, Optional
35
from typing import runtime_checkable, Protocol
6+
from typing import Union
7+
8+
9+
StrPath = Union[str, os.PathLike[str]]
10+
11+
__all__ = ["ResourceReader", "Traversable", "TraversableResources"]
412

513

614
class ResourceReader(metaclass=abc.ABCMeta):
@@ -50,22 +58,25 @@ class Traversable(Protocol):
5058
"""
5159
An object with a subset of pathlib.Path methods suitable for
5260
traversing directories and opening files.
61+
62+
Any exceptions that occur when accessing the backing resource
63+
may propagate unaltered.
5364
"""
5465

5566
@abc.abstractmethod
56-
def iterdir(self):
67+
def iterdir(self) -> Iterator["Traversable"]:
5768
"""
5869
Yield Traversable objects in self
5970
"""
6071

61-
def read_bytes(self):
72+
def read_bytes(self) -> bytes:
6273
"""
6374
Read contents of self as bytes
6475
"""
6576
with self.open('rb') as strm:
6677
return strm.read()
6778

68-
def read_text(self, encoding=None):
79+
def read_text(self, encoding: Optional[str] = None) -> str:
6980
"""
7081
Read contents of self as text
7182
"""
@@ -85,12 +96,16 @@ def is_file(self) -> bool:
8596
"""
8697

8798
@abc.abstractmethod
88-
def joinpath(self, child):
99+
def joinpath(self, *descendants: StrPath) -> "Traversable":
89100
"""
90-
Return Traversable child in self
101+
Return Traversable resolved with any descendants applied.
102+
103+
Each descendant should be a path segment relative to self
104+
and each may contain multiple levels separated by
105+
``posixpath.sep`` (``/``).
91106
"""
92107

93-
def __truediv__(self, child):
108+
def __truediv__(self, child: StrPath) -> "Traversable":
94109
"""
95110
Return Traversable child in self
96111
"""
@@ -120,17 +135,17 @@ class TraversableResources(ResourceReader):
120135
"""
121136

122137
@abc.abstractmethod
123-
def files(self):
138+
def files(self) -> "Traversable":
124139
"""Return a Traversable object for the loaded package."""
125140

126-
def open_resource(self, resource):
141+
def open_resource(self, resource: StrPath) -> io.BufferedReader:
127142
return self.files().joinpath(resource).open('rb')
128143

129-
def resource_path(self, resource):
144+
def resource_path(self, resource: Any) -> NoReturn:
130145
raise FileNotFoundError(resource)
131146

132-
def is_resource(self, path):
147+
def is_resource(self, path: StrPath) -> bool:
133148
return self.files().joinpath(path).is_file()
134149

135-
def contents(self):
150+
def contents(self) -> Iterator[str]:
136151
return (item.name for item in self.files().iterdir())

Lib/importlib/resources/simple.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,19 @@ def iterdir(self):
9999
def open(self, *args, **kwargs):
100100
raise IsADirectoryError()
101101

102-
def joinpath(self, name):
102+
@staticmethod
103+
def _flatten(compound_names):
104+
for name in compound_names:
105+
yield from name.split('/')
106+
107+
def joinpath(self, *descendants):
108+
if not descendants:
109+
return self
110+
names = self._flatten(descendants)
111+
target = next(names)
103112
return next(
104-
traversable for traversable in self.iterdir() if traversable.name == name
105-
)
113+
traversable for traversable in self.iterdir() if traversable.name == target
114+
).joinpath(*names)
106115

107116

108117
class TraversableReader(TraversableResources, SimpleReader):

Lib/test/test_importlib/update-zips.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def generate(suffix):
4242

4343
def walk(datapath):
4444
for dirpath, dirnames, filenames in os.walk(datapath):
45-
with contextlib.suppress(KeyError):
45+
with contextlib.suppress(ValueError):
4646
dirnames.remove('__pycache__')
4747
for filename in filenames:
4848
res = pathlib.Path(dirpath) / filename
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
In ``importlib.resources.abc``, refined the documentation of the Traversable
2+
Protocol, applying changes from importlib_resources 5.7.1.

0 commit comments

Comments
 (0)