Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python plugin project: load owned code and publish only an accepted interface

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A plugin loader executes a selected module and checks its exported interface before making it available to application dispatch.

Download Python source kit

Operation contract

The fixture writes two owned modules into a temporary directory and loads each through importlib’s file specification. It places the module in sys.modules for initialization and removes that entry when loading or validation fails. A successful module must expose a callable receipt_label that passes one declared smoke case. Only that accepted callable enters the local registry.

Failure and ownership boundary

The smoke case is not proof for every input, and module side effects are not rolled back by removing a cache entry. This loader must receive trusted, application-owned code paths; it is not an isolation boundary for uploads or arbitrary executable text. The fixture releases its module entries when finished. Python import failures: module removal does not roll back every side effect, Python first-class functions: dispatch through an explicit operation registry and Python Protocol: structural intent without runtime validation explain the remaining boundaries.

Working program

python
import importlib.util
from pathlib import Path
import sys
import tempfile

def load_owned_label(path, name):
    specification = importlib.util.spec_from_file_location(name, path)
    if specification is None or specification.loader is None:
        raise ValueError("module specification unavailable")
    module = importlib.util.module_from_spec(specification)
    if name in sys.modules: raise ValueError("module name already retained")
    sys.modules[name] = module
    try:
        specification.loader.exec_module(module)
        operation = getattr(module, "receipt_label", None)
        if not callable(operation) or operation(41) != "R-0041":
            raise ValueError("plugin interface rejected")
        return operation
    except BaseException:
        sys.modules.pop(name, None)
        raise

with tempfile.TemporaryDirectory() as directory:
    owned = Path(directory)
    accepted = owned / "accepted.py"; rejected = owned / "rejected.py"
    accepted.write_text('def receipt_label(number):\n    return f"R-{number:04d}"\n', encoding="utf-8")
    rejected.write_text('receipt_label = 125\n', encoding="utf-8")
    registry = {}
    try:
        registry["minor"] = load_owned_label(accepted, "aitrove_owned_label")
        print(registry["minor"](41))
        try: registry["invalid"] = load_owned_label(rejected, "aitrove_rejected_label")
        except ValueError: print("rejected registry absent:", "invalid" not in registry)
        print("failed module absent:", "aitrove_rejected_label" not in sys.modules)
    finally:
        sys.modules.pop("aitrove_owned_label", None)

Output

Output
R-0041
rejected registry absent: True
failed module absent: True

Costs and limits

Initialization executes the module’s own work. The tiny owned sources here have bounded smoke checks; a file path or an import API does not impose execution time, memory or side-effect limits. Published callables retain their module-global references even after cache removal.

Common Mistakes

  • Import cache cleanup does not undo external side effects.
  • Do not label a trusted-code loader as an upload sandbox.

Connected lessons

Python import failures: module removal does not roll back every side effect, Python first-class functions: dispatch through an explicit operation registry, Python Protocol: structural intent without runtime validation.

Trace the related workflow

Python entry points: inspect a trusted distribution before loading its plugin.

python
plugin-project
Storage details