Skip to main content

Lib/importlib/abc.py

cpython 3.14 @ ab2d84fe1023/Lib/importlib/abc.py

importlib.abc is the public surface for the import system's ABC layer. It defines the abstract classes that any custom finder or loader must subclass (or register against), and re-exports Loader from the internal _abc helper so that callers need only import from one place.

Map

LinesSymbolRole
25-33_registerRegisters concrete classes with an ABC and its frozen mirror
36-49MetaPathFinderABC for finders on sys.meta_path; registers BuiltinImporter, FrozenImporter, PathFinder, WindowsRegistryFinder
52-61PathEntryFinderABC for path-entry finders used by PathFinder; registers FileFinder
64-80ResourceLoaderLoader ABC that adds get_data(path) for raw bytes access
83-133InspectLoaderLoader ABC with get_source, get_code, source_to_code, and exec_module / load_module wired from _LoaderBasics
136-174ExecutionLoaderExtends InspectLoader with get_filename; overrides get_code to pass the filename to source_to_code
177-183FileLoaderThin mixin combining _bootstrap_external.FileLoader with ResourceLoader and ExecutionLoader
186-234SourceLoaderFull source-loading ABC; adds path_mtime (deprecated), path_stats, and set_data on top of ResourceLoader + ExecutionLoader

Reading

MetaPathFinder and PathEntryFinder

These two ABCs sit at the top of the finder hierarchy. Neither declares find_spec() as an abstract method: doing so would break hasattr duck-typing that the import machinery relies on to detect old-style finders.

# CPython: Lib/importlib/abc.py:36 MetaPathFinder
class MetaPathFinder(metaclass=abc.ABCMeta):
"""Abstract base class for import finders on sys.meta_path."""

def invalidate_caches(self):
"""An optional method for clearing the finder's cache, if any."""

_register then wires in the frozen-module mirrors so that isinstance(machinery.BuiltinImporter, MetaPathFinder) is true even before any user code runs:

# CPython: Lib/importlib/abc.py:48 _register call
_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
machinery.PathFinder, machinery.WindowsRegistryFinder)

exec_module / create_module protocol

InspectLoader wires exec_module and load_module directly from _bootstrap_external._LoaderBasics, making those methods available on any subclass without requiring the subclass to re-implement them.

# CPython: Lib/importlib/abc.py:130 InspectLoader exec_module binding
exec_module = _bootstrap_external._LoaderBasics.exec_module
load_module = _bootstrap_external._LoaderBasics.load_module

The load_module binding is kept solely for backward compatibility. New loaders should implement exec_module (and create_module when non-default module creation is needed). exec_module is the current canonical entry point: the import machinery calls create_module first, then exec_module.

SourceLoader.path_stats and deprecation of path_mtime

SourceLoader.path_mtime and path_stats have a mutual-override relationship: each detects whether the other has been overridden and forwards or raises accordingly. path_mtime is formally deprecated in favour of path_stats.

# CPython: Lib/importlib/abc.py:203 SourceLoader.path_mtime
def path_mtime(self, path):
"""Return the (int) modification time for the path (str)."""
import warnings
warnings.warn('SourceLoader.path_mtime is deprecated in favour of '
'SourceLoader.path_stats().',
DeprecationWarning, stacklevel=2)
if self.path_stats.__func__ is SourceLoader.path_stats:
raise OSError
return int(self.path_stats(path)['mtime'])

ExecutionLoader.get_code

ExecutionLoader overrides InspectLoader.get_code to pass the physical file path as the path argument to source_to_code (which calls compile()). This sets __file__ correctly in tracebacks.

# CPython: Lib/importlib/abc.py:154 ExecutionLoader.get_code
def get_code(self, fullname):
source = self.get_source(fullname)
if source is None:
return None
try:
path = self.get_filename(fullname)
except ImportError:
return self.source_to_code(source)
else:
return self.source_to_code(source, path)

gopy notes

  • Loader itself lives in importlib._abc (a C extension in CPython) and is re-exported here; gopy's equivalent will need to provide that base in the objects layer before wiring the ABC hierarchy.
  • The _register helper calls abstract_cls.register() which is pure Python ABC machinery; no C involvement. gopy can replicate this with its own type registration step at module init time.
  • SourceLoader.set_data intentionally has an empty body (write failure is silenced). gopy should preserve the no-op rather than raising.
  • exec_module / create_module is the only protocol gopy needs to implement for the loader side; load_module wrappers exist only for legacy callers.