xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/importlib/abc.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1"""Abstract base classes related to import."""
2from . import _bootstrap_external
3from . import machinery
4try:
5    import _frozen_importlib
6except ImportError as exc:
7    if exc.name != '_frozen_importlib':
8        raise
9    _frozen_importlib = None
10try:
11    import _frozen_importlib_external
12except ImportError:
13    _frozen_importlib_external = _bootstrap_external
14from ._abc import Loader
15import abc
16import warnings
17
18# for compatibility with Python 3.10
19from .resources.abc import ResourceReader, Traversable, TraversableResources
20
21
22__all__ = [
23    'Loader', 'Finder', 'MetaPathFinder', 'PathEntryFinder',
24    'ResourceLoader', 'InspectLoader', 'ExecutionLoader',
25    'FileLoader', 'SourceLoader',
26
27    # for compatibility with Python 3.10
28    'ResourceReader', 'Traversable', 'TraversableResources',
29]
30
31
32def _register(abstract_cls, *classes):
33    for cls in classes:
34        abstract_cls.register(cls)
35        if _frozen_importlib is not None:
36            try:
37                frozen_cls = getattr(_frozen_importlib, cls.__name__)
38            except AttributeError:
39                frozen_cls = getattr(_frozen_importlib_external, cls.__name__)
40            abstract_cls.register(frozen_cls)
41
42
43class Finder(metaclass=abc.ABCMeta):
44
45    """Legacy abstract base class for import finders.
46
47    It may be subclassed for compatibility with legacy third party
48    reimplementations of the import system.  Otherwise, finder
49    implementations should derive from the more specific MetaPathFinder
50    or PathEntryFinder ABCs.
51
52    Deprecated since Python 3.3
53    """
54
55    def __init__(self):
56        warnings.warn("the Finder ABC is deprecated and "
57                       "slated for removal in Python 3.12; use MetaPathFinder "
58                       "or PathEntryFinder instead",
59                       DeprecationWarning)
60
61    @abc.abstractmethod
62    def find_module(self, fullname, path=None):
63        """An abstract method that should find a module.
64        The fullname is a str and the optional path is a str or None.
65        Returns a Loader object or None.
66        """
67        warnings.warn("importlib.abc.Finder along with its find_module() "
68                      "method are deprecated and "
69                       "slated for removal in Python 3.12; use "
70                       "MetaPathFinder.find_spec() or "
71                       "PathEntryFinder.find_spec() instead",
72                       DeprecationWarning)
73
74
75class MetaPathFinder(metaclass=abc.ABCMeta):
76
77    """Abstract base class for import finders on sys.meta_path."""
78
79    # We don't define find_spec() here since that would break
80    # hasattr checks we do to support backward compatibility.
81
82    def find_module(self, fullname, path):
83        """Return a loader for the module.
84
85        If no module is found, return None.  The fullname is a str and
86        the path is a list of strings or None.
87
88        This method is deprecated since Python 3.4 in favor of
89        finder.find_spec(). If find_spec() exists then backwards-compatible
90        functionality is provided for this method.
91
92        """
93        warnings.warn("MetaPathFinder.find_module() is deprecated since Python "
94                      "3.4 in favor of MetaPathFinder.find_spec() and is "
95                      "slated for removal in Python 3.12",
96                      DeprecationWarning,
97                      stacklevel=2)
98        if not hasattr(self, 'find_spec'):
99            return None
100        found = self.find_spec(fullname, path)
101        return found.loader if found is not None else None
102
103    def invalidate_caches(self):
104        """An optional method for clearing the finder's cache, if any.
105        This method is used by importlib.invalidate_caches().
106        """
107
108_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
109          machinery.PathFinder, machinery.WindowsRegistryFinder)
110
111
112class PathEntryFinder(metaclass=abc.ABCMeta):
113
114    """Abstract base class for path entry finders used by PathFinder."""
115
116    # We don't define find_spec() here since that would break
117    # hasattr checks we do to support backward compatibility.
118
119    def find_loader(self, fullname):
120        """Return (loader, namespace portion) for the path entry.
121
122        The fullname is a str.  The namespace portion is a sequence of
123        path entries contributing to part of a namespace package. The
124        sequence may be empty.  If loader is not None, the portion will
125        be ignored.
126
127        The portion will be discarded if another path entry finder
128        locates the module as a normal module or package.
129
130        This method is deprecated since Python 3.4 in favor of
131        finder.find_spec(). If find_spec() is provided than backwards-compatible
132        functionality is provided.
133        """
134        warnings.warn("PathEntryFinder.find_loader() is deprecated since Python "
135                      "3.4 in favor of PathEntryFinder.find_spec() "
136                      "(available since 3.4)",
137                      DeprecationWarning,
138                      stacklevel=2)
139        if not hasattr(self, 'find_spec'):
140            return None, []
141        found = self.find_spec(fullname)
142        if found is not None:
143            if not found.submodule_search_locations:
144                portions = []
145            else:
146                portions = found.submodule_search_locations
147            return found.loader, portions
148        else:
149            return None, []
150
151    find_module = _bootstrap_external._find_module_shim
152
153    def invalidate_caches(self):
154        """An optional method for clearing the finder's cache, if any.
155        This method is used by PathFinder.invalidate_caches().
156        """
157
158_register(PathEntryFinder, machinery.FileFinder)
159
160
161class ResourceLoader(Loader):
162
163    """Abstract base class for loaders which can return data from their
164    back-end storage.
165
166    This ABC represents one of the optional protocols specified by PEP 302.
167
168    """
169
170    @abc.abstractmethod
171    def get_data(self, path):
172        """Abstract method which when implemented should return the bytes for
173        the specified path.  The path must be a str."""
174        raise OSError
175
176
177class InspectLoader(Loader):
178
179    """Abstract base class for loaders which support inspection about the
180    modules they can load.
181
182    This ABC represents one of the optional protocols specified by PEP 302.
183
184    """
185
186    def is_package(self, fullname):
187        """Optional method which when implemented should return whether the
188        module is a package.  The fullname is a str.  Returns a bool.
189
190        Raises ImportError if the module cannot be found.
191        """
192        raise ImportError
193
194    def get_code(self, fullname):
195        """Method which returns the code object for the module.
196
197        The fullname is a str.  Returns a types.CodeType if possible, else
198        returns None if a code object does not make sense
199        (e.g. built-in module). Raises ImportError if the module cannot be
200        found.
201        """
202        source = self.get_source(fullname)
203        if source is None:
204            return None
205        return self.source_to_code(source)
206
207    @abc.abstractmethod
208    def get_source(self, fullname):
209        """Abstract method which should return the source code for the
210        module.  The fullname is a str.  Returns a str.
211
212        Raises ImportError if the module cannot be found.
213        """
214        raise ImportError
215
216    @staticmethod
217    def source_to_code(data, path='<string>'):
218        """Compile 'data' into a code object.
219
220        The 'data' argument can be anything that compile() can handle. The'path'
221        argument should be where the data was retrieved (when applicable)."""
222        return compile(data, path, 'exec', dont_inherit=True)
223
224    exec_module = _bootstrap_external._LoaderBasics.exec_module
225    load_module = _bootstrap_external._LoaderBasics.load_module
226
227_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.NamespaceLoader)
228
229
230class ExecutionLoader(InspectLoader):
231
232    """Abstract base class for loaders that wish to support the execution of
233    modules as scripts.
234
235    This ABC represents one of the optional protocols specified in PEP 302.
236
237    """
238
239    @abc.abstractmethod
240    def get_filename(self, fullname):
241        """Abstract method which should return the value that __file__ is to be
242        set to.
243
244        Raises ImportError if the module cannot be found.
245        """
246        raise ImportError
247
248    def get_code(self, fullname):
249        """Method to return the code object for fullname.
250
251        Should return None if not applicable (e.g. built-in module).
252        Raise ImportError if the module cannot be found.
253        """
254        source = self.get_source(fullname)
255        if source is None:
256            return None
257        try:
258            path = self.get_filename(fullname)
259        except ImportError:
260            return self.source_to_code(source)
261        else:
262            return self.source_to_code(source, path)
263
264_register(ExecutionLoader, machinery.ExtensionFileLoader)
265
266
267class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):
268
269    """Abstract base class partially implementing the ResourceLoader and
270    ExecutionLoader ABCs."""
271
272_register(FileLoader, machinery.SourceFileLoader,
273            machinery.SourcelessFileLoader)
274
275
276class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader):
277
278    """Abstract base class for loading source code (and optionally any
279    corresponding bytecode).
280
281    To support loading from source code, the abstractmethods inherited from
282    ResourceLoader and ExecutionLoader need to be implemented. To also support
283    loading from bytecode, the optional methods specified directly by this ABC
284    is required.
285
286    Inherited abstractmethods not implemented in this ABC:
287
288        * ResourceLoader.get_data
289        * ExecutionLoader.get_filename
290
291    """
292
293    def path_mtime(self, path):
294        """Return the (int) modification time for the path (str)."""
295        if self.path_stats.__func__ is SourceLoader.path_stats:
296            raise OSError
297        return int(self.path_stats(path)['mtime'])
298
299    def path_stats(self, path):
300        """Return a metadata dict for the source pointed to by the path (str).
301        Possible keys:
302        - 'mtime' (mandatory) is the numeric timestamp of last source
303          code modification;
304        - 'size' (optional) is the size in bytes of the source code.
305        """
306        if self.path_mtime.__func__ is SourceLoader.path_mtime:
307            raise OSError
308        return {'mtime': self.path_mtime(path)}
309
310    def set_data(self, path, data):
311        """Write the bytes to the path (if possible).
312
313        Accepts a str path and data as bytes.
314
315        Any needed intermediary directories are to be created. If for some
316        reason the file cannot be written because of permissions, fail
317        silently.
318        """
319
320_register(SourceLoader, machinery.SourceFileLoader)
321