blob: 97d5afa3001930d0f115eae99f3bb39a0c4c14d9 [file] [log] [blame]
Brett Cannon2a922ed2009-03-09 03:35:50 +00001"""Abstract base classes related to import."""
Eric Snow183a9412015-05-15 21:54:59 -06002from . import _bootstrap
Eric Snow32439d62015-05-02 19:15:18 -06003from . import _bootstrap_external
Brett Cannon2a922ed2009-03-09 03:35:50 +00004from . import machinery
Brett Cannon938d44d2012-04-22 19:58:33 -04005try:
6 import _frozen_importlib
Brett Cannoncd171c82013-07-04 17:43:24 -04007except ImportError as exc:
Brett Cannon938d44d2012-04-22 19:58:33 -04008 if exc.name != '_frozen_importlib':
9 raise
10 _frozen_importlib = None
Eric Snow32439d62015-05-02 19:15:18 -060011try:
12 import _frozen_importlib_external
Pablo Galindo293dd232019-11-19 21:34:03 +000013except ImportError:
Eric Snow32439d62015-05-02 19:15:18 -060014 _frozen_importlib_external = _bootstrap_external
Victor Stinner9e098492020-06-17 23:15:59 +020015from ._abc import Loader
Brett Cannon2a922ed2009-03-09 03:35:50 +000016import abc
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -080017import warnings
Jason R. Coombs7f7e7062020-05-08 19:20:26 -040018from typing import Protocol, runtime_checkable
Brett Cannon2a922ed2009-03-09 03:35:50 +000019
20
Brett Cannon938d44d2012-04-22 19:58:33 -040021def _register(abstract_cls, *classes):
22 for cls in classes:
23 abstract_cls.register(cls)
24 if _frozen_importlib is not None:
Eric Snow32439d62015-05-02 19:15:18 -060025 try:
26 frozen_cls = getattr(_frozen_importlib, cls.__name__)
27 except AttributeError:
28 frozen_cls = getattr(_frozen_importlib_external, cls.__name__)
Brett Cannon938d44d2012-04-22 19:58:33 -040029 abstract_cls.register(frozen_cls)
30
31
Nick Coghlan8a9080f2012-08-02 21:26:03 +100032class Finder(metaclass=abc.ABCMeta):
33
Brett Cannonf4dc9202012-08-10 12:21:12 -040034 """Legacy abstract base class for import finders.
Nick Coghlan8a9080f2012-08-02 21:26:03 +100035
Brett Cannonf4dc9202012-08-10 12:21:12 -040036 It may be subclassed for compatibility with legacy third party
37 reimplementations of the import system. Otherwise, finder
38 implementations should derive from the more specific MetaPathFinder
39 or PathEntryFinder ABCs.
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -080040
41 Deprecated since Python 3.3
Nick Coghlan8a9080f2012-08-02 21:26:03 +100042 """
43
Brett Cannonf4dc9202012-08-10 12:21:12 -040044 @abc.abstractmethod
Nick Coghlan8a9080f2012-08-02 21:26:03 +100045 def find_module(self, fullname, path=None):
Brett Cannonf4dc9202012-08-10 12:21:12 -040046 """An abstract method that should find a module.
Nick Coghlan8a9080f2012-08-02 21:26:03 +100047 The fullname is a str and the optional path is a str or None.
Brett Cannon100883f2013-04-09 16:59:39 -040048 Returns a Loader object or None.
Nick Coghlan8a9080f2012-08-02 21:26:03 +100049 """
Nick Coghlan8a9080f2012-08-02 21:26:03 +100050
Nick Coghlan8a9080f2012-08-02 21:26:03 +100051
52class MetaPathFinder(Finder):
53
54 """Abstract base class for import finders on sys.meta_path."""
55
Eric Snowb523f842013-11-22 09:05:39 -070056 # We don't define find_spec() here since that would break
57 # hasattr checks we do to support backward compatibility.
58
Nick Coghlan8a9080f2012-08-02 21:26:03 +100059 def find_module(self, fullname, path):
Eric Snowb523f842013-11-22 09:05:39 -070060 """Return a loader for the module.
61
62 If no module is found, return None. The fullname is a str and
63 the path is a list of strings or None.
64
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -080065 This method is deprecated since Python 3.4 in favor of
66 finder.find_spec(). If find_spec() exists then backwards-compatible
67 functionality is provided for this method.
Eric Snow1500d492014-01-06 20:49:04 -070068
Nick Coghlan8a9080f2012-08-02 21:26:03 +100069 """
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -080070 warnings.warn("MetaPathFinder.find_module() is deprecated since Python "
Serhiy Storchaka34fd4c22018-11-05 16:20:25 +020071 "3.4 in favor of MetaPathFinder.find_spec() "
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -080072 "(available since 3.4)",
73 DeprecationWarning,
74 stacklevel=2)
Brett Cannon8d942292014-01-07 15:52:42 -050075 if not hasattr(self, 'find_spec'):
76 return None
77 found = self.find_spec(fullname, path)
78 return found.loader if found is not None else None
Nick Coghlan8a9080f2012-08-02 21:26:03 +100079
Brett Cannonf4dc9202012-08-10 12:21:12 -040080 def invalidate_caches(self):
81 """An optional method for clearing the finder's cache, if any.
82 This method is used by importlib.invalidate_caches().
83 """
Brett Cannonf4dc9202012-08-10 12:21:12 -040084
Nick Coghlan8a9080f2012-08-02 21:26:03 +100085_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
Nick Coghlanff794862012-08-02 21:45:24 +100086 machinery.PathFinder, machinery.WindowsRegistryFinder)
Nick Coghlan8a9080f2012-08-02 21:26:03 +100087
88
89class PathEntryFinder(Finder):
90
91 """Abstract base class for path entry finders used by PathFinder."""
92
Eric Snowb523f842013-11-22 09:05:39 -070093 # We don't define find_spec() here since that would break
94 # hasattr checks we do to support backward compatibility.
95
Nick Coghlan8a9080f2012-08-02 21:26:03 +100096 def find_loader(self, fullname):
Eric Snowb523f842013-11-22 09:05:39 -070097 """Return (loader, namespace portion) for the path entry.
98
99 The fullname is a str. The namespace portion is a sequence of
100 path entries contributing to part of a namespace package. The
101 sequence may be empty. If loader is not None, the portion will
102 be ignored.
103
104 The portion will be discarded if another path entry finder
105 locates the module as a normal module or package.
106
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -0800107 This method is deprecated since Python 3.4 in favor of
108 finder.find_spec(). If find_spec() is provided than backwards-compatible
109 functionality is provided.
Nick Coghlan8a9080f2012-08-02 21:26:03 +1000110 """
Matthias Bussonnier1d4601c2017-02-15 18:00:32 -0800111 warnings.warn("PathEntryFinder.find_loader() is deprecated since Python "
112 "3.4 in favor of PathEntryFinder.find_spec() "
113 "(available since 3.4)",
114 DeprecationWarning,
115 stacklevel=2)
Brett Cannon8d942292014-01-07 15:52:42 -0500116 if not hasattr(self, 'find_spec'):
117 return None, []
118 found = self.find_spec(fullname)
119 if found is not None:
120 if not found.submodule_search_locations:
121 portions = []
122 else:
123 portions = found.submodule_search_locations
124 return found.loader, portions
125 else:
126 return None, []
Nick Coghlan8a9080f2012-08-02 21:26:03 +1000127
Eric Snow32439d62015-05-02 19:15:18 -0600128 find_module = _bootstrap_external._find_module_shim
Brett Cannonf4dc9202012-08-10 12:21:12 -0400129
130 def invalidate_caches(self):
131 """An optional method for clearing the finder's cache, if any.
132 This method is used by PathFinder.invalidate_caches().
133 """
Brett Cannonf4dc9202012-08-10 12:21:12 -0400134
Nick Coghlan8a9080f2012-08-02 21:26:03 +1000135_register(PathEntryFinder, machinery.FileFinder)
136
137
Brett Cannon2a922ed2009-03-09 03:35:50 +0000138class ResourceLoader(Loader):
139
Brett Cannon7aa21f72009-03-15 00:53:05 +0000140 """Abstract base class for loaders which can return data from their
141 back-end storage.
Brett Cannon2a922ed2009-03-09 03:35:50 +0000142
143 This ABC represents one of the optional protocols specified by PEP 302.
144
145 """
146
147 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000148 def get_data(self, path):
Brett Cannon7aa21f72009-03-15 00:53:05 +0000149 """Abstract method which when implemented should return the bytes for
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000150 the specified path. The path must be a str."""
Serhiy Storchaka55fe1ae2017-04-16 10:46:38 +0300151 raise OSError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000152
153
154class InspectLoader(Loader):
155
Brett Cannon7aa21f72009-03-15 00:53:05 +0000156 """Abstract base class for loaders which support inspection about the
157 modules they can load.
Brett Cannon2a922ed2009-03-09 03:35:50 +0000158
159 This ABC represents one of the optional protocols specified by PEP 302.
160
161 """
162
Raymond Hettingercd92f372011-01-13 02:31:25 +0000163 def is_package(self, fullname):
Eric Snowb523f842013-11-22 09:05:39 -0700164 """Optional method which when implemented should return whether the
Brett Cannon100883f2013-04-09 16:59:39 -0400165 module is a package. The fullname is a str. Returns a bool.
166
Eric Snowb523f842013-11-22 09:05:39 -0700167 Raises ImportError if the module cannot be found.
Brett Cannon100883f2013-04-09 16:59:39 -0400168 """
169 raise ImportError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000170
Raymond Hettingercd92f372011-01-13 02:31:25 +0000171 def get_code(self, fullname):
Brett Cannon3b62ca82013-05-27 21:11:04 -0400172 """Method which returns the code object for the module.
Brett Cannon100883f2013-04-09 16:59:39 -0400173
Brett Cannon3b62ca82013-05-27 21:11:04 -0400174 The fullname is a str. Returns a types.CodeType if possible, else
175 returns None if a code object does not make sense
176 (e.g. built-in module). Raises ImportError if the module cannot be
177 found.
Brett Cannon100883f2013-04-09 16:59:39 -0400178 """
Brett Cannon3b62ca82013-05-27 21:11:04 -0400179 source = self.get_source(fullname)
180 if source is None:
181 return None
182 return self.source_to_code(source)
Brett Cannon2a922ed2009-03-09 03:35:50 +0000183
184 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000185 def get_source(self, fullname):
Brett Cannon7aa21f72009-03-15 00:53:05 +0000186 """Abstract method which should return the source code for the
Brett Cannon100883f2013-04-09 16:59:39 -0400187 module. The fullname is a str. Returns a str.
188
189 Raises ImportError if the module cannot be found.
190 """
191 raise ImportError
Brett Cannon2a922ed2009-03-09 03:35:50 +0000192
Brett Cannon6eaac132014-05-09 12:28:22 -0400193 @staticmethod
194 def source_to_code(data, path='<string>'):
Brett Cannon9ffe85e2013-05-26 16:45:10 -0400195 """Compile 'data' into a code object.
196
197 The 'data' argument can be anything that compile() can handle. The'path'
198 argument should be where the data was retrieved (when applicable)."""
199 return compile(data, path, 'exec', dont_inherit=True)
200
Eric Snow32439d62015-05-02 19:15:18 -0600201 exec_module = _bootstrap_external._LoaderBasics.exec_module
202 load_module = _bootstrap_external._LoaderBasics.load_module
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400203
Eric Snowb523f842013-11-22 09:05:39 -0700204_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter)
Brett Cannona113ac52009-03-15 01:41:33 +0000205
Brett Cannon2a922ed2009-03-09 03:35:50 +0000206
Brett Cannon69194272009-07-20 04:23:48 +0000207class ExecutionLoader(InspectLoader):
208
209 """Abstract base class for loaders that wish to support the execution of
210 modules as scripts.
211
212 This ABC represents one of the optional protocols specified in PEP 302.
213
214 """
215
216 @abc.abstractmethod
Raymond Hettingercd92f372011-01-13 02:31:25 +0000217 def get_filename(self, fullname):
Brett Cannon69194272009-07-20 04:23:48 +0000218 """Abstract method which should return the value that __file__ is to be
Brett Cannon100883f2013-04-09 16:59:39 -0400219 set to.
220
221 Raises ImportError if the module cannot be found.
222 """
223 raise ImportError
Brett Cannon69194272009-07-20 04:23:48 +0000224
Brett Cannon3b62ca82013-05-27 21:11:04 -0400225 def get_code(self, fullname):
226 """Method to return the code object for fullname.
227
228 Should return None if not applicable (e.g. built-in module).
229 Raise ImportError if the module cannot be found.
230 """
231 source = self.get_source(fullname)
232 if source is None:
233 return None
234 try:
235 path = self.get_filename(fullname)
236 except ImportError:
237 return self.source_to_code(source)
238 else:
239 return self.source_to_code(source, path)
240
Eric Snow7e70fa52013-10-04 20:28:52 -0600241_register(ExecutionLoader, machinery.ExtensionFileLoader)
Eric Snow51794452013-10-03 12:08:55 -0600242
Brett Cannon69194272009-07-20 04:23:48 +0000243
Eric Snow32439d62015-05-02 19:15:18 -0600244class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):
Brett Cannon938d44d2012-04-22 19:58:33 -0400245
246 """Abstract base class partially implementing the ResourceLoader and
247 ExecutionLoader ABCs."""
248
249_register(FileLoader, machinery.SourceFileLoader,
Marc-Andre Lemburg4fe29c92012-04-25 02:31:37 +0200250 machinery.SourcelessFileLoader)
Brett Cannon938d44d2012-04-22 19:58:33 -0400251
252
Eric Snow32439d62015-05-02 19:15:18 -0600253class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader):
Brett Cannon2a922ed2009-03-09 03:35:50 +0000254
Brett Cannonf23e3742010-06-27 23:57:46 +0000255 """Abstract base class for loading source code (and optionally any
256 corresponding bytecode).
Brett Cannon2a922ed2009-03-09 03:35:50 +0000257
Brett Cannonf23e3742010-06-27 23:57:46 +0000258 To support loading from source code, the abstractmethods inherited from
259 ResourceLoader and ExecutionLoader need to be implemented. To also support
260 loading from bytecode, the optional methods specified directly by this ABC
261 is required.
262
263 Inherited abstractmethods not implemented in this ABC:
264
265 * ResourceLoader.get_data
266 * ExecutionLoader.get_filename
267
268 """
269
Raymond Hettingercd92f372011-01-13 02:31:25 +0000270 def path_mtime(self, path):
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000271 """Return the (int) modification time for the path (str)."""
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100272 if self.path_stats.__func__ is SourceLoader.path_stats:
Serhiy Storchaka55fe1ae2017-04-16 10:46:38 +0300273 raise OSError
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100274 return int(self.path_stats(path)['mtime'])
275
276 def path_stats(self, path):
277 """Return a metadata dict for the source pointed to by the path (str).
278 Possible keys:
279 - 'mtime' (mandatory) is the numeric timestamp of last source
280 code modification;
281 - 'size' (optional) is the size in bytes of the source code.
282 """
283 if self.path_mtime.__func__ is SourceLoader.path_mtime:
Serhiy Storchaka55fe1ae2017-04-16 10:46:38 +0300284 raise OSError
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100285 return {'mtime': self.path_mtime(path)}
Brett Cannon8d189072010-08-22 20:38:47 +0000286
Raymond Hettingercd92f372011-01-13 02:31:25 +0000287 def set_data(self, path, data):
Brett Cannon8d189072010-08-22 20:38:47 +0000288 """Write the bytes to the path (if possible).
289
Raymond Hettingerd958ea72011-01-13 19:08:04 +0000290 Accepts a str path and data as bytes.
291
Brett Cannon8d189072010-08-22 20:38:47 +0000292 Any needed intermediary directories are to be created. If for some
293 reason the file cannot be written because of permissions, fail
294 silently.
Brett Cannon8d189072010-08-22 20:38:47 +0000295 """
Brett Cannon8d189072010-08-22 20:38:47 +0000296
Brett Cannon938d44d2012-04-22 19:58:33 -0400297_register(SourceLoader, machinery.SourceFileLoader)
Brett Cannon4ac51502017-12-15 16:29:35 -0800298
299
Barry Warsaw5ec0fee2018-01-15 15:07:11 -0800300class ResourceReader(metaclass=abc.ABCMeta):
Brett Cannon4ac51502017-12-15 16:29:35 -0800301
Brett Cannonbca42182018-01-12 15:08:59 -0800302 """Abstract base class to provide resource-reading support.
303
304 Loaders that support resource reading are expected to implement
305 the ``get_resource_reader(fullname)`` method and have it either return None
306 or an object compatible with this ABC.
307 """
Brett Cannon4ac51502017-12-15 16:29:35 -0800308
309 @abc.abstractmethod
310 def open_resource(self, resource):
311 """Return an opened, file-like object for binary reading.
312
313 The 'resource' argument is expected to represent only a file name
314 and thus not contain any subdirectory components.
315
316 If the resource cannot be found, FileNotFoundError is raised.
317 """
318 raise FileNotFoundError
319
320 @abc.abstractmethod
321 def resource_path(self, resource):
322 """Return the file system path to the specified resource.
323
324 The 'resource' argument is expected to represent only a file name
325 and thus not contain any subdirectory components.
326
327 If the resource does not exist on the file system, raise
328 FileNotFoundError.
329 """
330 raise FileNotFoundError
331
332 @abc.abstractmethod
333 def is_resource(self, name):
334 """Return True if the named 'name' is consider a resource."""
335 raise FileNotFoundError
336
337 @abc.abstractmethod
338 def contents(self):
Brett Cannon3ab93652018-04-30 11:31:45 -0700339 """Return an iterable of strings over the contents of the package."""
340 return []
Barry Warsaw5ec0fee2018-01-15 15:07:11 -0800341
342
343_register(ResourceReader, machinery.SourceFileLoader)
Jason R. Coombs7f7e7062020-05-08 19:20:26 -0400344
345
346@runtime_checkable
347class Traversable(Protocol):
348 """
349 An object with a subset of pathlib.Path methods suitable for
350 traversing directories and opening files.
351 """
352
353 @abc.abstractmethod
354 def iterdir(self):
355 """
356 Yield Traversable objects in self
357 """
358
359 @abc.abstractmethod
360 def read_bytes(self):
361 """
362 Read contents of self as bytes
363 """
364
365 @abc.abstractmethod
366 def read_text(self, encoding=None):
367 """
368 Read contents of self as bytes
369 """
370
371 @abc.abstractmethod
372 def is_dir(self):
373 """
374 Return True if self is a dir
375 """
376
377 @abc.abstractmethod
378 def is_file(self):
379 """
380 Return True if self is a file
381 """
382
383 @abc.abstractmethod
384 def joinpath(self, child):
385 """
386 Return Traversable child in self
387 """
388
389 @abc.abstractmethod
390 def __truediv__(self, child):
391 """
392 Return Traversable child in self
393 """
394
395 @abc.abstractmethod
396 def open(self, mode='r', *args, **kwargs):
397 """
398 mode may be 'r' or 'rb' to open as text or binary. Return a handle
399 suitable for reading (same as pathlib.Path.open).
400
401 When opening as text, accepts encoding parameters such as those
402 accepted by io.TextIOWrapper.
403 """
404
405 @abc.abstractproperty
406 def name(self):
407 # type: () -> str
408 """
409 The base name of this object without any parent references.
410 """
411
412
413class TraversableResources(ResourceReader):
414 @abc.abstractmethod
415 def files(self):
416 """Return a Traversable object for the loaded package."""
417
418 def open_resource(self, resource):
419 return self.files().joinpath(resource).open('rb')
420
421 def resource_path(self, resource):
422 raise FileNotFoundError(resource)
423
424 def is_resource(self, path):
Jason R. Coombs843c2772020-06-07 21:00:51 -0400425 return self.files().joinpath(path).is_file()
Jason R. Coombs7f7e7062020-05-08 19:20:26 -0400426
427 def contents(self):
428 return (item.name for item in self.files().iterdir())