Skip to content
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
39 changes: 27 additions & 12 deletions Lib/importlib/resources/abc.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down Expand Up @@ -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
"""
Expand All @@ -85,12 +96,16 @@ def is_file(self) -> bool:
"""

@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
"""
Expand Down Expand Up @@ -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())
15 changes: 12 additions & 3 deletions Lib/importlib/resources/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,19 @@ def iterdir(self):
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):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_importlib/update-zips.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
In ``importlib.resources.abc``, refined the documentation of the Traversable
Protocol, applying changes from importlib_resources 5.7.1.