Python’s importlib.abc module defines the Abstract Base Classes that form the import system protocol — subclass these to build custom finders and loaders. import importlib.abc. Key ABCs: MetaPathFinder — add to sys.meta_path; override find_spec(fullname, path, target) → ModuleSpec | None. PathEntryFinder — returned by a callable on sys.path_hooks; override find_spec(fullname, target). Loader — override create_module(spec) (return None for default) and exec_module(module). SourceLoader — for Python source; override get_data(path) → bytes and get_filename(name) → str; enables bytecode caching automatically. InspectLoader — adds get_source(fullname), is_package(fullname), get_code(fullname). ResourceLoader — adds get_data(path) → bytes (deprecated, use importlib.resources). Register: sys.meta_path.insert(0, MyFinder()) — intercepts imports before the default finders. Claude Code generates in-memory importers, encrypted module loaders, namespace packages, database-backed modules, and import auditing hooks.
CLAUDE.md for importlib.abc
## importlib.abc Stack
- Stdlib: import importlib.abc, importlib.machinery, sys
- Finder: class F(importlib.abc.MetaPathFinder):
- def find_spec(self, fullname, path, target): ...
- Loader: class L(importlib.abc.Loader):
- def create_module(self, spec): return None # default
- def exec_module(self, module): exec(code, module.__dict__)
- Install: sys.meta_path.insert(0, MyFinder())
- Spec: importlib.machinery.ModuleSpec(name, loader, origin=...)
- Remove: sys.meta_path[:] = [f for f in sys.meta_path if not isinstance(f, MyFinder)]
importlib.abc Custom Import Pipeline
# app/importabcutil.py — in-memory, dict, audit hook, namespace, encrypted
from __future__ import annotations
import importlib.abc
import importlib.machinery
import importlib.util
import sys
from types import ModuleType
from typing import Any
# ─────────────────────────────────────────────────────────────────────────────
# 1. In-memory module loader
# ─────────────────────────────────────────────────────────────────────────────
class InMemoryLoader(importlib.abc.Loader):
"""
Load a Python module from a source string in memory.
Example:
loader = InMemoryLoader("x = 42\ndef greet(name): return f'hi {name}'")
spec = importlib.machinery.ModuleSpec("mymod", loader, origin="<memory>")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
print(mod.greet("world"))
"""
def __init__(self, source: str, origin: str = "<memory>") -> None:
self._source = source
self._origin = origin
def create_module(self, spec: importlib.machinery.ModuleSpec) -> None:
return None # use default module creation
def exec_module(self, module: ModuleType) -> None:
code = compile(self._source, self._origin, "exec")
exec(code, module.__dict__)
def get_source(self, fullname: str) -> str:
return self._source
def is_package(self, fullname: str) -> bool:
return False
def load_from_string(name: str, source: str) -> ModuleType:
"""
Create and execute a module from a source string, registered in sys.modules.
Example:
mod = load_from_string("calc", "def add(a, b): return a + b")
print(mod.add(2, 3)) # 5
"""
loader = InMemoryLoader(source, origin=f"<string:{name}>")
spec = importlib.machinery.ModuleSpec(name, loader, origin=loader._origin)
mod = importlib.util.module_from_spec(spec)
sys.modules[name] = mod
loader.exec_module(mod)
return mod
# ─────────────────────────────────────────────────────────────────────────────
# 2. Dict-backed finder — intercepts specific module names
# ─────────────────────────────────────────────────────────────────────────────
class DictFinder(importlib.abc.MetaPathFinder):
"""
A meta path finder backed by a dict mapping module names to source strings.
Only handles modules whose names appear in the dict.
Example:
finder = DictFinder({
"hello_world": "MESSAGE = 'Hello, World!'",
"math_utils": "def double(x): return x * 2",
})
sys.meta_path.insert(0, finder)
import hello_world
print(hello_world.MESSAGE)
finder.uninstall()
"""
def __init__(self, modules: dict[str, str]) -> None:
self._modules = modules
self._installed = False
def find_spec(
self,
fullname: str,
path: Any,
target: Any = None,
) -> "importlib.machinery.ModuleSpec | None":
if fullname in self._modules:
loader = InMemoryLoader(self._modules[fullname], origin=f"<dict:{fullname}>")
return importlib.machinery.ModuleSpec(fullname, loader)
return None
def install(self) -> "DictFinder":
"""Install this finder as the first entry in sys.meta_path."""
if not self._installed:
sys.meta_path.insert(0, self)
self._installed = True
return self
def uninstall(self) -> None:
"""Remove this finder from sys.meta_path and clear cached modules."""
if self in sys.meta_path:
sys.meta_path.remove(self)
for name in self._modules:
sys.modules.pop(name, None)
self._installed = False
def add(self, name: str, source: str) -> None:
"""Add or update a module in the dict."""
self._modules[name] = source
sys.modules.pop(name, None) # invalidate cached version
# ─────────────────────────────────────────────────────────────────────────────
# 3. Import audit hook (non-finder)
# ─────────────────────────────────────────────────────────────────────────────
class ImportAuditor(importlib.abc.MetaPathFinder):
"""
A passthrough meta path finder that records every find_spec call
without intercepting any imports.
Example:
auditor = ImportAuditor()
auditor.install()
import json
print(auditor.log) # [("json", None)]
auditor.uninstall()
"""
def __init__(self) -> None:
self.log: list[tuple[str, Any]] = []
def find_spec(
self,
fullname: str,
path: Any,
target: Any = None,
) -> None:
self.log.append((fullname, path))
return None # let normal finders take over
def install(self) -> "ImportAuditor":
sys.meta_path.insert(0, self)
return self
def uninstall(self) -> None:
if self in sys.meta_path:
sys.meta_path.remove(self)
def clear(self) -> None:
self.log.clear()
def was_imported(self, name: str) -> bool:
return any(n == name for n, _ in self.log)
# ─────────────────────────────────────────────────────────────────────────────
# 4. SourceLoader stub for custom source origins
# ─────────────────────────────────────────────────────────────────────────────
class StringSourceLoader(importlib.abc.SourceLoader):
"""
A SourceLoader backed by an in-memory string.
SourceLoader automatically handles get_code() and is_package() based on
get_data() and get_filename().
Example:
loader = StringSourceLoader("mymod", "x = 99", origin="<test>")
spec = importlib.machinery.ModuleSpec("mymod", loader, origin="<test>")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
print(mod.x) # 99
"""
def __init__(self, name: str, source: str, origin: str = "<string>") -> None:
self._name = name
self._source = source
self._origin = origin
def get_data(self, path: str) -> bytes:
return self._source.encode("utf-8")
def get_filename(self, name: str) -> str:
return self._origin
def is_package(self, fullname: str) -> bool:
return False
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== importlib.abc demo ===")
# ── load_from_string ──────────────────────────────────────────────────────
print("\n--- load_from_string ---")
calc = load_from_string(
"_demo_calc",
"def add(a, b): return a + b\nPI = 3.14159",
)
print(f" add(10, 32) = {calc.add(10, 32)}")
print(f" PI = {calc.PI}")
sys.modules.pop("_demo_calc", None)
# ── DictFinder ────────────────────────────────────────────────────────────
print("\n--- DictFinder ---")
finder = DictFinder({
"_demo_greet": 'def hi(name): return f"Hello, {name}!"',
"_demo_math": "square = lambda x: x * x\ncube = lambda x: x ** 3",
})
finder.install()
import _demo_greet # type: ignore[import]
import _demo_math # type: ignore[import]
print(f" greet.hi('World') = {_demo_greet.hi('World')!r}")
print(f" math.square(7) = {_demo_math.square(7)}")
print(f" math.cube(3) = {_demo_math.cube(3)}")
finder.uninstall()
# ── ImportAuditor ─────────────────────────────────────────────────────────
print("\n--- ImportAuditor ---")
auditor = ImportAuditor()
auditor.install()
import json as _json_test # noqa: F401
import os.path as _osp_test # noqa: F401
auditor.uninstall()
print(f" logged {len(auditor.log)} find_spec calls")
print(f" was 'json' queried: {auditor.was_imported('json')}")
print(f" first 5 modules queried: {[n for n,_ in auditor.log[:5]]}")
# ── StringSourceLoader ────────────────────────────────────────────────────
print("\n--- StringSourceLoader ---")
loader = StringSourceLoader("_demo_ssl", "ANSWER = 42\nversion = '1.0'")
spec = importlib.machinery.ModuleSpec("_demo_ssl_mod", loader, origin="<test>")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
print(f" ANSWER = {mod.ANSWER}")
print(f" version = {mod.version!r}")
print("\n=== done ===")
For the importlib.util.spec_from_file_location() alternative — importlib.util.spec_from_file_location("name", path) creates a ModuleSpec from a filesystem path using the standard file loaders provided by importlib.machinery — use spec_from_file_location for file-based dynamic imports; use importlib.abc.MetaPathFinder + Loader when you need to intercept imports system-wide, load modules from non-filesystem sources (databases, network, encrypted containers), or redirect entire module hierarchies. For the pkgutil.get_importer() legacy alternative — pkgutil.get_importer(path) and pkgutil.iter_importers() expose the old find_module/load_module API that predates find_spec/exec_module — always implement the new find_spec/exec_module API when writing custom finders and loaders; the old find_module/load_module interface is deprecated since Python 3.4. The Claude Skills 360 bundle includes importlib.abc skill sets covering InMemoryLoader with exec_module()/get_source(), load_from_string() helper, DictFinder with install()/uninstall()/add(), ImportAuditor passthrough with was_imported(), and StringSourceLoader SourceLoader subclass. Start with the free tier to try custom import patterns and importlib.abc pipeline code generation.