• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
18from .resources import abc as _resources_abc
19
20
21__all__ = [
22    'Loader', 'MetaPathFinder', 'PathEntryFinder',
23    'ResourceLoader', 'InspectLoader', 'ExecutionLoader',
24    'FileLoader', 'SourceLoader',
25]
26
27
28def __getattr__(name):
29    """
30    For backwards compatibility, continue to make names
31    from _resources_abc available through this module. #93963
32    """
33    if name in _resources_abc.__all__:
34        obj = getattr(_resources_abc, name)
35        warnings._deprecated(f"{__name__}.{name}", remove=(3, 14))
36        globals()[name] = obj
37        return obj
38    raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
39
40
41def _register(abstract_cls, *classes):
42    for cls in classes:
43        abstract_cls.register(cls)
44        if _frozen_importlib is not None:
45            try:
46                frozen_cls = getattr(_frozen_importlib, cls.__name__)
47            except AttributeError:
48                frozen_cls = getattr(_frozen_importlib_external, cls.__name__)
49            abstract_cls.register(frozen_cls)
50
51
52class MetaPathFinder(metaclass=abc.ABCMeta):
53
54    """Abstract base class for import finders on sys.meta_path."""
55
56    # We don't define find_spec() here since that would break
57    # hasattr checks we do to support backward compatibility.
58
59    def invalidate_caches(self):
60        """An optional method for clearing the finder's cache, if any.
61        This method is used by importlib.invalidate_caches().
62        """
63
64_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
65          machinery.PathFinder, machinery.WindowsRegistryFinder)
66
67
68class PathEntryFinder(metaclass=abc.ABCMeta):
69
70    """Abstract base class for path entry finders used by PathFinder."""
71
72    def invalidate_caches(self):
73        """An optional method for clearing the finder's cache, if any.
74        This method is used by PathFinder.invalidate_caches().
75        """
76
77_register(PathEntryFinder, machinery.FileFinder)
78
79
80class ResourceLoader(Loader):
81
82    """Abstract base class for loaders which can return data from their
83    back-end storage.
84
85    This ABC represents one of the optional protocols specified by PEP 302.
86
87    """
88
89    @abc.abstractmethod
90    def get_data(self, path):
91        """Abstract method which when implemented should return the bytes for
92        the specified path.  The path must be a str."""
93        raise OSError
94
95
96class InspectLoader(Loader):
97
98    """Abstract base class for loaders which support inspection about the
99    modules they can load.
100
101    This ABC represents one of the optional protocols specified by PEP 302.
102
103    """
104
105    def is_package(self, fullname):
106        """Optional method which when implemented should return whether the
107        module is a package.  The fullname is a str.  Returns a bool.
108
109        Raises ImportError if the module cannot be found.
110        """
111        raise ImportError
112
113    def get_code(self, fullname):
114        """Method which returns the code object for the module.
115
116        The fullname is a str.  Returns a types.CodeType if possible, else
117        returns None if a code object does not make sense
118        (e.g. built-in module). Raises ImportError if the module cannot be
119        found.
120        """
121        source = self.get_source(fullname)
122        if source is None:
123            return None
124        return self.source_to_code(source)
125
126    @abc.abstractmethod
127    def get_source(self, fullname):
128        """Abstract method which should return the source code for the
129        module.  The fullname is a str.  Returns a str.
130
131        Raises ImportError if the module cannot be found.
132        """
133        raise ImportError
134
135    @staticmethod
136    def source_to_code(data, path='<string>'):
137        """Compile 'data' into a code object.
138
139        The 'data' argument can be anything that compile() can handle. The'path'
140        argument should be where the data was retrieved (when applicable)."""
141        return compile(data, path, 'exec', dont_inherit=True)
142
143    exec_module = _bootstrap_external._LoaderBasics.exec_module
144    load_module = _bootstrap_external._LoaderBasics.load_module
145
146_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.NamespaceLoader)
147
148
149class ExecutionLoader(InspectLoader):
150
151    """Abstract base class for loaders that wish to support the execution of
152    modules as scripts.
153
154    This ABC represents one of the optional protocols specified in PEP 302.
155
156    """
157
158    @abc.abstractmethod
159    def get_filename(self, fullname):
160        """Abstract method which should return the value that __file__ is to be
161        set to.
162
163        Raises ImportError if the module cannot be found.
164        """
165        raise ImportError
166
167    def get_code(self, fullname):
168        """Method to return the code object for fullname.
169
170        Should return None if not applicable (e.g. built-in module).
171        Raise ImportError if the module cannot be found.
172        """
173        source = self.get_source(fullname)
174        if source is None:
175            return None
176        try:
177            path = self.get_filename(fullname)
178        except ImportError:
179            return self.source_to_code(source)
180        else:
181            return self.source_to_code(source, path)
182
183_register(
184    ExecutionLoader,
185    machinery.ExtensionFileLoader,
186    machinery.AppleFrameworkLoader,
187)
188
189
190class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):
191
192    """Abstract base class partially implementing the ResourceLoader and
193    ExecutionLoader ABCs."""
194
195_register(FileLoader, machinery.SourceFileLoader,
196            machinery.SourcelessFileLoader)
197
198
199class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader):
200
201    """Abstract base class for loading source code (and optionally any
202    corresponding bytecode).
203
204    To support loading from source code, the abstractmethods inherited from
205    ResourceLoader and ExecutionLoader need to be implemented. To also support
206    loading from bytecode, the optional methods specified directly by this ABC
207    is required.
208
209    Inherited abstractmethods not implemented in this ABC:
210
211        * ResourceLoader.get_data
212        * ExecutionLoader.get_filename
213
214    """
215
216    def path_mtime(self, path):
217        """Return the (int) modification time for the path (str)."""
218        if self.path_stats.__func__ is SourceLoader.path_stats:
219            raise OSError
220        return int(self.path_stats(path)['mtime'])
221
222    def path_stats(self, path):
223        """Return a metadata dict for the source pointed to by the path (str).
224        Possible keys:
225        - 'mtime' (mandatory) is the numeric timestamp of last source
226          code modification;
227        - 'size' (optional) is the size in bytes of the source code.
228        """
229        if self.path_mtime.__func__ is SourceLoader.path_mtime:
230            raise OSError
231        return {'mtime': self.path_mtime(path)}
232
233    def set_data(self, path, data):
234        """Write the bytes to the path (if possible).
235
236        Accepts a str path and data as bytes.
237
238        Any needed intermediary directories are to be created. If for some
239        reason the file cannot be written because of permissions, fail
240        silently.
241        """
242
243_register(SourceLoader, machinery.SourceFileLoader)
244