pluggy

1.6.0 · active · verified Sat Mar 28

pluggy is the crystallized core of plugin management and hook calling for pytest, powering 1400+ pytest plugins and pytest itself. It provides HookspecMarker and HookimplMarker decorators to define typed hook contracts, a PluginManager to register plugins and dispatch calls, and supports hook ordering (tryfirst/trylast), firstresult short-circuiting, historic hooks, and new-style generator-based hook wrappers. Current stable version is 1.6.0 (released May 15, 2025); releases follow Semantic Versioning with breaking changes reserved for major version bumps.

Warnings

Install

Imports

Quickstart

Define a hook spec and two implementations, register them with a PluginManager scoped to a project name, then call the hook and collect results.

import pluggy

# Both markers MUST share the same project name as PluginManager
hookspec = pluggy.HookspecMarker("myproject")
hookimpl = pluggy.HookimplMarker("myproject")


class MySpec:
    """Hook specification namespace."""

    @hookspec
    def process(self, value: int) -> int:
        """Transform a value. Each implementation's return is collected into a list."""


class PluginA:
    @hookimpl
    def process(self, value: int) -> int:
        return value * 2


class PluginB:
    @hookimpl(tryfirst=True)  # runs before PluginA despite LIFO default
    def process(self, value: int) -> int:
        return value + 10


pm = pluggy.PluginManager("myproject")
pm.add_hookspecs(MySpec)       # register the spec BEFORE plugins
pm.register(PluginA())
pm.register(PluginB())

# Hook calls MUST use keyword arguments only
results = pm.hook.process(value=5)
print(results)  # [15, 10]  — PluginB (tryfirst) then PluginA, LIFO order

# New-style wrapper (>=1.2.0): use wrapper=True, plain function with yield
class WrapperPlugin:
    @hookimpl(wrapper=True)
    def process(self, value: int) -> int:
        print("before")
        result = yield  # receives return value of inner calls
        print("after")
        return result

pm.register(WrapperPlugin())
results2 = pm.hook.process(value=3)
print(results2)

view raw JSON →