summaryrefslogtreecommitdiffstats
path: root/Lib/importlib/abc.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/importlib/abc.py')
-rw-r--r--Lib/importlib/abc.py80
1 files changed, 59 insertions, 21 deletions
diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
index fa343f8..c171da3 100644
--- a/Lib/importlib/abc.py
+++ b/Lib/importlib/abc.py
@@ -1,18 +1,28 @@
"""Abstract base classes related to import."""
from . import _bootstrap
from . import machinery
-from . import util
+try:
+ import _frozen_importlib
+except ImportError as exc:
+ if exc.name != '_frozen_importlib':
+ raise
+ _frozen_importlib = None
import abc
import imp
-import io
import marshal
-import os.path
import sys
import tokenize
-import types
import warnings
+def _register(abstract_cls, *classes):
+ for cls in classes:
+ abstract_cls.register(cls)
+ if _frozen_importlib is not None:
+ frozen_cls = getattr(_frozen_importlib, cls.__name__)
+ abstract_cls.register(frozen_cls)
+
+
class Loader(metaclass=abc.ABCMeta):
"""Abstract base class for import loaders."""
@@ -36,9 +46,8 @@ class Finder(metaclass=abc.ABCMeta):
"""
raise NotImplementedError
-Finder.register(machinery.BuiltinImporter)
-Finder.register(machinery.FrozenImporter)
-Finder.register(machinery.PathFinder)
+_register(Finder, machinery.BuiltinImporter, machinery.FrozenImporter,
+ machinery.PathFinder, machinery.FileFinder)
class ResourceLoader(Loader):
@@ -84,8 +93,8 @@ class InspectLoader(Loader):
module. The fullname is a str. Returns a str."""
raise NotImplementedError
-InspectLoader.register(machinery.BuiltinImporter)
-InspectLoader.register(machinery.FrozenImporter)
+_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter,
+ machinery.ExtensionFileLoader)
class ExecutionLoader(InspectLoader):
@@ -104,6 +113,15 @@ class ExecutionLoader(InspectLoader):
raise NotImplementedError
+class FileLoader(_bootstrap.FileLoader, ResourceLoader, ExecutionLoader):
+
+ """Abstract base class partially implementing the ResourceLoader and
+ ExecutionLoader ABCs."""
+
+_register(FileLoader, machinery.SourceFileLoader,
+ machinery.SourcelessFileLoader)
+
+
class SourceLoader(_bootstrap.SourceLoader, ResourceLoader, ExecutionLoader):
"""Abstract base class for loading source code (and optionally any
@@ -123,7 +141,20 @@ class SourceLoader(_bootstrap.SourceLoader, ResourceLoader, ExecutionLoader):
def path_mtime(self, path):
"""Return the (int) modification time for the path (str)."""
- raise NotImplementedError
+ if self.path_stats.__func__ is SourceLoader.path_stats:
+ raise NotImplementedError
+ return int(self.path_stats(path)['mtime'])
+
+ def path_stats(self, path):
+ """Return a metadata dict for the source pointed to by the path (str).
+ Possible keys:
+ - 'mtime' (mandatory) is the numeric timestamp of last source
+ code modification;
+ - 'size' (optional) is the size in bytes of the source code.
+ """
+ if self.path_mtime.__func__ is SourceLoader.path_mtime:
+ raise NotImplementedError
+ return {'mtime': self.path_mtime(path)}
def set_data(self, path, data):
"""Write the bytes to the path (if possible).
@@ -137,6 +168,7 @@ class SourceLoader(_bootstrap.SourceLoader, ResourceLoader, ExecutionLoader):
"""
raise NotImplementedError
+_register(SourceLoader, machinery.SourceFileLoader)
class PyLoader(SourceLoader):
@@ -195,10 +227,10 @@ class PyLoader(SourceLoader):
"use SourceLoader instead. "
"See the importlib documentation on how to be "
"compatible with Python 3.1 onwards.",
- PendingDeprecationWarning)
+ DeprecationWarning)
path = self.source_path(fullname)
if path is None:
- raise ImportError
+ raise ImportError(name=fullname)
else:
return path
@@ -226,7 +258,7 @@ class PyPycLoader(PyLoader):
if path is not None:
return path
raise ImportError("no source or bytecode path available for "
- "{0!r}".format(fullname))
+ "{0!r}".format(fullname), name=fullname)
def get_code(self, fullname):
"""Get a code object from source or bytecode."""
@@ -234,7 +266,7 @@ class PyPycLoader(PyLoader):
"removal in Python 3.4; use SourceLoader instead. "
"If Python 3.1 compatibility is required, see the "
"latest documentation for PyLoader.",
- PendingDeprecationWarning)
+ DeprecationWarning)
source_timestamp = self.source_mtime(fullname)
# Try to use bytecode if it is available.
bytecode_path = self.bytecode_path(fullname)
@@ -243,20 +275,25 @@ class PyPycLoader(PyLoader):
try:
magic = data[:4]
if len(magic) < 4:
- raise ImportError("bad magic number in {}".format(fullname))
+ raise ImportError(
+ "bad magic number in {}".format(fullname),
+ name=fullname, path=bytecode_path)
raw_timestamp = data[4:8]
if len(raw_timestamp) < 4:
raise EOFError("bad timestamp in {}".format(fullname))
- pyc_timestamp = marshal._r_long(raw_timestamp)
+ pyc_timestamp = _bootstrap._r_long(raw_timestamp)
bytecode = data[8:]
# Verify that the magic number is valid.
if imp.get_magic() != magic:
- raise ImportError("bad magic number in {}".format(fullname))
+ raise ImportError(
+ "bad magic number in {}".format(fullname),
+ name=fullname, path=bytecode_path)
# Verify that the bytecode is not stale (only matters when
# there is source to fall back on.
if source_timestamp:
if pyc_timestamp < source_timestamp:
- raise ImportError("bytecode is stale")
+ raise ImportError("bytecode is stale", name=fullname,
+ path=bytecode_path)
except (ImportError, EOFError):
# If source is available give it a shot.
if source_timestamp is not None:
@@ -268,18 +305,19 @@ class PyPycLoader(PyLoader):
return marshal.loads(bytecode)
elif source_timestamp is None:
raise ImportError("no source or bytecode available to create code "
- "object for {0!r}".format(fullname))
+ "object for {0!r}".format(fullname),
+ name=fullname)
# Use the source.
source_path = self.source_path(fullname)
if source_path is None:
message = "a source path must exist to load {0}".format(fullname)
- raise ImportError(message)
+ raise ImportError(message, name=fullname)
source = self.get_data(source_path)
code_object = compile(source, source_path, 'exec', dont_inherit=True)
# Generate bytecode and write it out.
if not sys.dont_write_bytecode:
data = bytearray(imp.get_magic())
- data.extend(marshal._w_long(source_timestamp))
+ data.extend(_bootstrap._w_long(source_timestamp))
data.extend(marshal.dumps(code_object))
self.write_bytecode(fullname, data)
return code_object