xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/importlib/resources/abc.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1import abc
2import io
3import os
4from typing import Any, BinaryIO, Iterable, Iterator, NoReturn, Text, Optional
5from typing import runtime_checkable, Protocol
6from typing import Union
7
8
9StrPath = Union[str, os.PathLike[str]]
10
11__all__ = ["ResourceReader", "Traversable", "TraversableResources"]
12
13
14class ResourceReader(metaclass=abc.ABCMeta):
15    """Abstract base class for loaders to provide resource reading support."""
16
17    @abc.abstractmethod
18    def open_resource(self, resource: Text) -> BinaryIO:
19        """Return an opened, file-like object for binary reading.
20
21        The 'resource' argument is expected to represent only a file name.
22        If the resource cannot be found, FileNotFoundError is raised.
23        """
24        # This deliberately raises FileNotFoundError instead of
25        # NotImplementedError so that if this method is accidentally called,
26        # it'll still do the right thing.
27        raise FileNotFoundError
28
29    @abc.abstractmethod
30    def resource_path(self, resource: Text) -> Text:
31        """Return the file system path to the specified resource.
32
33        The 'resource' argument is expected to represent only a file name.
34        If the resource does not exist on the file system, raise
35        FileNotFoundError.
36        """
37        # This deliberately raises FileNotFoundError instead of
38        # NotImplementedError so that if this method is accidentally called,
39        # it'll still do the right thing.
40        raise FileNotFoundError
41
42    @abc.abstractmethod
43    def is_resource(self, path: Text) -> bool:
44        """Return True if the named 'path' is a resource.
45
46        Files are resources, directories are not.
47        """
48        raise FileNotFoundError
49
50    @abc.abstractmethod
51    def contents(self) -> Iterable[str]:
52        """Return an iterable of entries in `package`."""
53        raise FileNotFoundError
54
55
56@runtime_checkable
57class Traversable(Protocol):
58    """
59    An object with a subset of pathlib.Path methods suitable for
60    traversing directories and opening files.
61
62    Any exceptions that occur when accessing the backing resource
63    may propagate unaltered.
64    """
65
66    @abc.abstractmethod
67    def iterdir(self) -> Iterator["Traversable"]:
68        """
69        Yield Traversable objects in self
70        """
71
72    def read_bytes(self) -> bytes:
73        """
74        Read contents of self as bytes
75        """
76        with self.open('rb') as strm:
77            return strm.read()
78
79    def read_text(self, encoding: Optional[str] = None) -> str:
80        """
81        Read contents of self as text
82        """
83        with self.open(encoding=encoding) as strm:
84            return strm.read()
85
86    @abc.abstractmethod
87    def is_dir(self) -> bool:
88        """
89        Return True if self is a directory
90        """
91
92    @abc.abstractmethod
93    def is_file(self) -> bool:
94        """
95        Return True if self is a file
96        """
97
98    @abc.abstractmethod
99    def joinpath(self, *descendants: StrPath) -> "Traversable":
100        """
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`` (``/``).
106        """
107
108    def __truediv__(self, child: StrPath) -> "Traversable":
109        """
110        Return Traversable child in self
111        """
112        return self.joinpath(child)
113
114    @abc.abstractmethod
115    def open(self, mode='r', *args, **kwargs):
116        """
117        mode may be 'r' or 'rb' to open as text or binary. Return a handle
118        suitable for reading (same as pathlib.Path.open).
119
120        When opening as text, accepts encoding parameters such as those
121        accepted by io.TextIOWrapper.
122        """
123
124    @abc.abstractproperty
125    def name(self) -> str:
126        """
127        The base name of this object without any parent references.
128        """
129
130
131class TraversableResources(ResourceReader):
132    """
133    The required interface for providing traversable
134    resources.
135    """
136
137    @abc.abstractmethod
138    def files(self) -> "Traversable":
139        """Return a Traversable object for the loaded package."""
140
141    def open_resource(self, resource: StrPath) -> io.BufferedReader:
142        return self.files().joinpath(resource).open('rb')
143
144    def resource_path(self, resource: Any) -> NoReturn:
145        raise FileNotFoundError(resource)
146
147    def is_resource(self, path: StrPath) -> bool:
148        return self.files().joinpath(path).is_file()
149
150    def contents(self) -> Iterator[str]:
151        return (item.name for item in self.files().iterdir())
152