Skip to main content

pluginkit

PyPI Python CI Docs License: MIT

A small, strictly-typed, generics-first plugin framework for Python 3.13+. Declare extension points, let plugins implement them, discover plugins via entry points - and, unlike untyped hook systems, get the right return type for every call, derived from the spec and checked by your type checker.

That strict typing applies to caller arguments and mode-correct results. Plugin implementation annotations are not statically linked to independently declared specs; registration validates their argument names at runtime.

pm.caller(spec) hands back a caller whose result type matches the dispatch mode - list[R] for collecting, R | None for firstresult, R for pipeline - with no hand-annotations and no drift. Zero runtime dependencies, a py.typed marker, and a few readable files.

uv add pluginkit   # or: pip install pluginkit
from pluginkit import Extension, ExtensionPoint, PluginManager

extension_point = ExtensionPoint("greeter")
extension = Extension("greeter")


class Specs:
    @staticmethod
    @extension_point
    def greeting(name: str) -> str:
        """Return a greeting for the given name."""


class Casual:
    @extension
    def greeting(self, name: str) -> str:
        return f"hey {name}!"


pm = PluginManager("greeter")
pm.add_extension_points(Specs)
pm.register(Casual(), name="casual")

greetings = pm.caller(Specs.greeting)(name="Ada")  # typed list[str] - derived, not asserted
print(greetings)  # ['hey Ada!']

What it supports

  • collecting, firstresult, and pipeline (fold/middleware) hooks;
  • call ordering with tryfirst / trylast, plus optional and target;
  • generator wrappers that decorate results and observe exceptions safely;
  • historic hooks replayed to plugins registered later;
  • async dispatch via AsyncPluginManager (awaits coroutine impls);
  • plugin lifecycle: register, unregister (by name or object), set_blocked, lookup, call_extra;
  • registration-time validation and call-time argument checking (failures are loud);
  • external plugin discovery via the stdlib importlib.metadata (no setuptools);
  • attribution-preserving collection and structured entry-point diagnostics;
  • thread-safe registry mutation.

Layout

src/pluginkit/             the library (pure - no demo code)
examples/                  everything that uses the library (not shipped):
  cookbook/                  worked examples: bite-size scripts + full apps
  tour/                      pluginkit-tour: a guided CLI walkthrough
  external-plugin/           a separate distribution discovered via entry points
docs/                      mkdocs + Material documentation
tests/                     library, tour, and cookbook tests

Everything that demonstrates the library lives under examples/. The cookbook holds standalone examples (from one-mechanism snippets to complete FastAPI/Click/pytest apps); the tour is a guided walkthrough on one host; the external-plugin shows cross-package discovery via entry points.

Use it

make install              # uv sync (library + tour + external plugin)
make test                 # pytest (framework, tour, examples)
make lint                 # ruff + mypy + pyright
make docs-serve           # serve the docs at http://127.0.0.1:8000
make docs-build           # build the docs (strict)

Two ways to learn it

The tour (examples/tour/) walks through one mechanism at a time on a single host:

make run                  # run every step
make run DEMO=wrapper      # run one
uv run pluginkit-tour list

The cookbook applies the library to realistic domains and frameworks - see examples/cookbook/:

uv run python examples/cookbook/report_builder.py
uv run python examples/cookbook/fastapi_app.py
uv run python examples/cookbook/cli_app.py --help
uv run python examples/cookbook/app_lifecycle.py

Documentation

Full docs (concepts, one page per mechanism, production/hardening notes, and a generated API reference) live under docs/. Serve them with make docs-serve.

Is it production ready?

It is solid - exception-safe wrappers, fail-fast validation, lifecycle management, resilient discovery, thread-safe mutation, strict typing, and a test suite. But for anything you ship, prefer pluggy itself: it is maintained and battle tested by pytest, tox, and datasette. See docs/production/vs-pluggy.md for the honest inventory of what differs.

Metadata

Release files for pluginkit 0.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pluginkit 0.5.1
File Size Uploaded Provenance
pluginkit-0.5.1.tar.gz 18.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pluginkit 0.5.1
File Interpreter ABI Platform
pluginkit-0.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 38.7 kB

Release files / pluginkit-0.5.1.tar.gz

Download URL pluginkit-0.5.1.tar.gz
Size 18.0 kB
Tags Source
SHA-256 checksum
How to use checksums
4f08e839687c9542128ae619d8a3a68b707b40b78241b540a0be897e53cbc217
BLAKE2b-256 checksum
How to use checksums
be2b2759505c00d61edeaf585d22601291b6bc8b0403e191e5e93f1e5aa2e696
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

Release files / pluginkit-0.5.1-py3-none-any.whl

Download URL pluginkit-0.5.1-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c05e388db16502877a73796a1f861346cf7483670aa140140183950c94803763
BLAKE2b-256 checksum
How to use checksums
df9f243729b3e5fe17c8f388d7ff3308ff21e33cdfff23dd42ea5224a696d4c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

Security for pluginkit 0.5.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pluginkit-0.5.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page