Lab 13: Plugin Framework

Time: 60 minutes | Level: Architect | Docker: docker run -it --rm python:3.11-slim bash

Overview

Build a production-grade plugin system using pluggy (the framework powering pytest), entry points via importlib.metadata, and __init_subclass__ for zero-dependency plugin discovery.

Prerequisites

pip install pluggy

Step 1: pluggy Basics — HookSpec and HookImpl

import pluggy

hookspec = pluggy.HookspecMarker('myapp')
hookimpl = pluggy.HookimplMarker('myapp')

class MySpec:
    @hookspec
    def process_request(self, request: dict) -> dict:
        """Process a request. Called for every registered plugin."""
    
    @hookspec(firstresult=True)
    def authenticate(self, token: str) -> dict | None:
        """Authenticate a token. Returns first non-None result."""
    
    @hookspec
    def on_startup(self) -> None:
        """Called when the application starts."""

print("Hook spec defined with 3 hooks.")
print("  process_request: all plugins called, results collected")
print("  authenticate: firstresult — stops at first non-None")
print("  on_startup: all plugins called")

Step 2: Implementing Plugins

Step 3: Plugin Manager Setup and Hook Calls

Step 4: Processing Requests Through Plugin Chain

📸 Verified Output:

Step 5: Plugin Discovery via __init_subclass__

Step 6: Plugin Versioning and Dependency Management

Step 7: Plugin Sandboxing for Test Isolation

Step 8: Capstone — Complete Plugin Framework

📸 Verified Output:

Summary

Concept
API
Use Case

Hook spec

@hookspec

Define plugin contracts

Hook impl

@hookimpl

Implement plugin behavior

First-result

@hookspec(firstresult=True)

Authentication, lookup

Ordering

tryfirst=True/trylast=True

Control plugin order

__init_subclass__

plugin_id=, version=

Zero-dep auto-registration

Versioning

SemVer comparison

Dependency validation

Sandboxing

types.ModuleType + restricted builtins

Safe plugin execution

Plugin platform

Combined pluggy + registry

Production plugin system

Last updated