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