-
Notifications
You must be signed in to change notification settings - Fork 0
Hooks
Asterios Raptis edited this page Mar 27, 2026
·
1 revision
PluginForge uses pluggy for its hook system. Pluggy is the same system used by pytest, tox, and datasette.
- Hook Spec - Defines the interface (what hooks exist and their signatures)
- Hook Impl - A plugin's implementation of a hook
- Hook Caller - The application calling a hook on all registered plugins
Create a module with @hookspec-decorated functions:
# myapp/hookspecs.py
import pluggy
hookspec = pluggy.HookspecMarker("myapp")
class MyAppHookSpec:
@hookspec
def on_startup(self) -> None:
"""Called when the application starts."""
@hookspec
def on_document_save(self, document: dict) -> dict | None:
"""Called when a document is saved. Can modify the document."""
@hookspec(firstresult=True)
def get_renderer(self, format: str) -> object | None:
"""Return a renderer for the given format. First non-None result wins."""Register the specs with PluginManager:
from myapp.hookspecs import MyAppHookSpec
pm = PluginManager("config/app.yaml")
pm.register_hookspecs(MyAppHookSpec)Plugins implement hooks using @hookimpl:
import pluggy
from pluginforge import BasePlugin
hookimpl = pluggy.HookimplMarker("myapp")
class ExportPlugin(BasePlugin):
name = "export"
@hookimpl
def on_startup(self) -> None:
print("ExportPlugin ready")
@hookimpl
def on_document_save(self, document: dict) -> dict | None:
document["exported"] = True
return documentThe marker name ("myapp") must match between HookspecMarker and HookimplMarker.
# Call all implementations
results = pm.call_hook("on_startup")
# Call with arguments
results = pm.call_hook("on_document_save", document={"title": "Hello"})call_hook() returns a list of results from all implementations. If the hook is not found, it logs a warning and returns an empty list.
Since pluggy >= 1.1.0, hook wrappers require explicit wrapper=True:
@hookimpl(wrapper=True)
def on_document_save(self, document: dict) -> dict | None:
# Code before all other implementations
print("Before save")
# Yield to run other implementations
result = yield
# Code after all other implementations
print("After save")
return result| Concern | Managed by |
|---|---|
| Hook specs and implementations | pluggy |
| Hook calling and result collection | pluggy |
| Plugin discovery (entry points) | PluginForge |
| Plugin lifecycle (init/activate/deactivate) | PluginForge |
| YAML configuration | PluginForge |
| Dependency resolution | PluginForge |
| Enable/disable | PluginForge |
They are complementary layers, not competing.