Claude Code for importlib.util: Python Import System Utilities — Claude Skills 360 Blog
Blog / AI / Claude Code for importlib.util: Python Import System Utilities
AI

Claude Code for importlib.util: Python Import System Utilities

Published: December 31, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s importlib.util module exposes the building blocks of the import system for dynamically loading modules and inspecting import machinery. import importlib.util. Load any file: spec = importlib.util.spec_from_file_location("name", "/path/to/file.py")ModuleSpec; mod = importlib.util.module_from_spec(spec) → new module object; spec.loader.exec_module(mod) — execute the module code. Find without importing: importlib.util.find_spec("json")ModuleSpec | None. Cache paths: importlib.util.cache_from_source("/src/foo.py").pyc path; importlib.util.source_from_cache("/src/__pycache__/foo.cpython-312.pyc") → source path. Lazy loading: loader = importlib.util.LazyLoader(spec.loader); spec.loader = loader — defers exec_module until first attribute access. Source hash: importlib.util.source_hash(source_bytes) → 8-byte hash for hash-based pyc files. Claude Code generates plugin loaders, dynamic module executors, sandboxed import contexts, and path-based module discovery tools.

CLAUDE.md for importlib.util

## importlib.util Stack
- Stdlib: import importlib.util
- Load file: spec = importlib.util.spec_from_file_location("name", path)
-            mod = importlib.util.module_from_spec(spec)
-            spec.loader.exec_module(mod)
- Find:     importlib.util.find_spec("json")   # ModuleSpec or None
- Cache:    importlib.util.cache_from_source("foo.py")   # → .pyc path
- Lazy:     importlib.util.LazyLoader(spec.loader)
- Note:     register mod in sys.modules BEFORE exec_module to handle circular imports

importlib.util Dynamic Import Pipeline

# app/importutil.py — loader, finder, plugin, cache, lazy, discovery
from __future__ import annotations

import importlib
import importlib.util
import sys
from dataclasses import dataclass, field
from pathlib import Path
from types import ModuleType
from typing import Any


# ─────────────────────────────────────────────────────────────────────────────
# 1. Dynamic file loading
# ─────────────────────────────────────────────────────────────────────────────

def load_module_from_file(
    name: str,
    path: "str | Path",
    register: bool = True,
) -> ModuleType:
    """
    Load a Python source file as a module.
    If register=True (default) the module is added to sys.modules under name,
    which is required for modules that import from themselves (circular imports).

    Example:
        plugin = load_module_from_file("myplugin", "/opt/plugins/myplugin.py")
        plugin.run()
    """
    path = Path(path)
    spec = importlib.util.spec_from_file_location(name, path)
    if spec is None or spec.loader is None:
        raise ImportError(f"Cannot create spec for {path}")
    mod = importlib.util.module_from_spec(spec)
    if register:
        sys.modules[name] = mod
    spec.loader.exec_module(mod)  # type: ignore[union-attr]
    return mod


def load_module_from_file_lazy(
    name: str,
    path: "str | Path",
) -> ModuleType:
    """
    Load a module lazily — code executes on first attribute access.
    Useful for optional heavyweight modules.

    Example:
        heavy = load_module_from_file_lazy("heavy", "/opt/heavy.py")
        # No code executed yet
        heavy.process()  # executes now
    """
    path = Path(path)
    spec = importlib.util.spec_from_file_location(name, path)
    if spec is None or spec.loader is None:
        raise ImportError(f"Cannot create spec for {path}")
    spec.loader = importlib.util.LazyLoader(spec.loader)  # type: ignore[assignment]
    mod = importlib.util.module_from_spec(spec)
    sys.modules[name] = mod
    spec.loader.exec_module(mod)  # type: ignore[union-attr]
    return mod


def reload_module(mod: ModuleType) -> ModuleType:
    """
    Reload a previously imported module in place.

    Example:
        import mymodule
        # edit mymodule.py on disk
        reload_module(mymodule)
    """
    return importlib.reload(mod)


# ─────────────────────────────────────────────────────────────────────────────
# 2. Module lookup / introspection
# ─────────────────────────────────────────────────────────────────────────────

def module_exists(name: str) -> bool:
    """
    Return True if the named module can be found without importing it.

    Example:
        module_exists("json")          # True
        module_exists("nonexistent")   # False
    """
    return importlib.util.find_spec(name) is not None


def module_path(name: str) -> "Path | None":
    """
    Return the filesystem path of the named module without importing it.
    Returns None if the module is not found or is a built-in.

    Example:
        print(module_path("email"))          # PosixPath('/usr/lib/.../email/__init__.py')
        print(module_path("sys"))            # None (built-in)
        print(module_path("nonexistent"))    # None
    """
    spec = importlib.util.find_spec(name)
    if spec is None or spec.origin is None:
        return None
    return Path(spec.origin)


def is_package(name: str) -> bool:
    """
    Return True if the named module is a package (has subpackages).

    Example:
        is_package("email")   # True
        is_package("json")    # True
        is_package("sys")     # False
    """
    spec = importlib.util.find_spec(name)
    if spec is None:
        return False
    return spec.submodule_search_locations is not None


@dataclass
class ModuleInfo:
    """Summary info about an importable module."""
    name:     str
    found:    bool
    path:     "Path | None"
    is_pkg:   bool
    origin:   "str | None"
    is_builtin: bool

    def __str__(self) -> str:
        if not self.found:
            return f"ModuleInfo({self.name!r} NOT FOUND)"
        kind = "package" if self.is_pkg else ("built-in" if self.is_builtin else "module")
        return f"ModuleInfo({self.name!r}  {kind}  path={self.path})"


def inspect_module(name: str) -> ModuleInfo:
    """
    Return ModuleInfo for a named module without importing it.

    Example:
        print(inspect_module("json"))
        print(inspect_module("sys"))
        print(inspect_module("nonexistent"))
    """
    spec = importlib.util.find_spec(name)
    if spec is None:
        return ModuleInfo(name=name, found=False, path=None, is_pkg=False, origin=None, is_builtin=False)
    origin = spec.origin
    is_builtin = origin == "built-in" or (spec.loader is not None and
                                           type(spec.loader).__name__ == "BuiltinImporter")
    path = Path(spec.origin) if origin and origin != "built-in" else None
    is_pkg = spec.submodule_search_locations is not None
    return ModuleInfo(name=name, found=True, path=path, is_pkg=is_pkg, origin=origin, is_builtin=is_builtin)


# ─────────────────────────────────────────────────────────────────────────────
# 3. Plugin loader
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class Plugin:
    """A loaded plugin module with metadata."""
    name:   str
    path:   Path
    module: ModuleType
    ok:     bool
    error:  str = ""

    def get(self, attr: str, default: Any = None) -> Any:
        return getattr(self.module, attr, default)

    def has(self, attr: str) -> bool:
        return hasattr(self.module, attr)


def load_plugins_from_dir(
    directory: "str | Path",
    pattern: str = "*.py",
    name_prefix: str = "plugin",
    api_attrs: "list[str] | None" = None,
) -> list[Plugin]:
    """
    Load all Python files matching pattern from directory as plugins.
    If api_attrs is given, only files that define all listed attributes are kept.

    Example:
        plugins = load_plugins_from_dir("/opt/plugins", api_attrs=["run", "NAME"])
        for p in plugins:
            print(p.name, p.get("NAME"), p.module.run())
    """
    plugins: list[Plugin] = []
    for path in sorted(Path(directory).glob(pattern)):
        if path.name.startswith("_"):
            continue
        name = f"{name_prefix}.{path.stem}"
        try:
            mod = load_module_from_file(name, path)
            if api_attrs and not all(hasattr(mod, a) for a in api_attrs):
                continue
            plugins.append(Plugin(name=name, path=path, module=mod, ok=True))
        except Exception as e:
            plugins.append(Plugin(
                name=name, path=path, module=ModuleType(name),
                ok=False, error=str(e),
            ))
    return plugins


# ─────────────────────────────────────────────────────────────────────────────
# 4. Cache path utilities
# ─────────────────────────────────────────────────────────────────────────────

def pyc_path(source: "str | Path") -> Path:
    """
    Return the expected .pyc cache path for a source file.

    Example:
        print(pyc_path("myapp/utils.py"))
        # myapp/__pycache__/utils.cpython-312.pyc
    """
    return Path(importlib.util.cache_from_source(str(source)))


def source_from_pyc(pyc: "str | Path") -> Path:
    """
    Return the source path that corresponds to a .pyc cache file.

    Example:
        print(source_from_pyc("myapp/__pycache__/utils.cpython-312.pyc"))
        # myapp/utils.py
    """
    return Path(importlib.util.source_from_cache(str(pyc)))


def pyc_is_stale(source: "str | Path") -> bool:
    """
    Return True if the source file is newer than its cached .pyc, or if no .pyc exists.

    Example:
        if pyc_is_stale("myapp/utils.py"):
            print("cache is outdated")
    """
    src = Path(source)
    try:
        cache = pyc_path(src)
        if not cache.exists():
            return True
        return src.stat().st_mtime > cache.stat().st_mtime
    except Exception:
        return True


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import tempfile

    print("=== importlib.util demo ===")

    # ── inspect_module ────────────────────────────────────────────────────────
    print("\n--- inspect_module ---")
    for name in ["json", "sys", "email", "nonexistent_xyz", "os.path"]:
        print(f"  {inspect_module(name)}")

    # ── module_exists / module_path / is_package ──────────────────────────────
    print("\n--- module_exists / module_path ---")
    for name in ["json", "pathlib", "sys", "nonexistent_xyz"]:
        print(f"  {name:15s}  exists={module_exists(name)}  is_pkg={is_package(name)}  path={module_path(name)}")

    # ── load_module_from_file ─────────────────────────────────────────────────
    print("\n--- load_module_from_file ---")
    with tempfile.NamedTemporaryFile(suffix=".py", mode="w", delete=False) as f:
        f.write('NAME = "demo_module"\n\ndef greet(name):\n    return f"Hello, {name}!"\n')
        tmp_path = f.name

    try:
        demo = load_module_from_file("_demo_dynamic", tmp_path)
        print(f"  NAME:     {demo.NAME!r}")
        print(f"  greet():  {demo.greet('World')!r}")
    finally:
        import os
        os.unlink(tmp_path)
        sys.modules.pop("_demo_dynamic", None)

    # ── load_plugins_from_dir ─────────────────────────────────────────────────
    print("\n--- load_plugins_from_dir ---")
    with tempfile.TemporaryDirectory() as tmpdir:
        (Path(tmpdir) / "alpha.py").write_text('NAME="alpha"\ndef run(): return "alpha-result"')
        (Path(tmpdir) / "beta.py").write_text('NAME="beta"\ndef run(): return "beta-result"')
        (Path(tmpdir) / "gamma.py").write_text('# no NAME or run\nfoo = 1')

        plugins = load_plugins_from_dir(tmpdir, api_attrs=["NAME", "run"])
        for p in plugins:
            print(f"  {p.name:25s}  ok={p.ok}  NAME={p.get('NAME')!r}  run()={p.module.run()!r}")

    # ── pyc_path / source_from_pyc ────────────────────────────────────────────
    print("\n--- pyc_path / source_from_pyc ---")
    src = Path(__file__)
    cache = pyc_path(src)
    print(f"  source: {src.name}")
    print(f"  cache:  {cache.name}")
    print(f"  stale:  {pyc_is_stale(src)}")

    print("\n=== done ===")

For the importlib.import_module() alternative — importlib.import_module("json") is the standard way to import a module by string name when you have the module name but not a file path — use importlib.import_module() for name-based imports (plugins registered in config files); use importlib.util.spec_from_file_location() when you have a file path on disk that is not on sys.path. For the __import__() built-in alternative — __import__("json") is the low-level hook that import statements compile to; it returns the top-level package, not the submodule — always prefer importlib.import_module() over __import__() for programmatic imports; they both ultimately call the same import machinery but importlib.import_module() has cleaner semantics and handles dotted names correctly. The Claude Skills 360 bundle includes importlib.util skill sets covering load_module_from_file()/load_module_from_file_lazy()/reload_module() file loaders, module_exists()/module_path()/is_package()/ModuleInfo/inspect_module() introspection helpers, Plugin dataclass + load_plugins_from_dir() plugin system, and pyc_path()/source_from_pyc()/pyc_is_stale() cache utilities. Start with the free tier to try dynamic import patterns and importlib.util pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free