API: Plugins Package
The plugins package exposes the stable registry surface used by declarative config builders and plugin catalog UIs.
PluginCategory
Bases: StrEnum
Canonical category identifiers for all pluggable pipeline components.
Design rationale
Replacing raw strings with a StrEnum eliminates typo-induced KeyErrors at plugin registration and lookup time, provides IDE autocompletion, and makes mypy able to catch category mismatches statically.
StrEnum (Python 3.11+) means each member compares equal to its string value, so existing code that uses the string literal (e.g. "analyzer") continues to work without modification during migration.
PluginDefinition
dataclass
Immutable descriptor for a registered plugin.
The descriptor is intentionally serializable except for factory.
as_dict() exposes factory_path instead of the callable so diagnostics
and UIs can render plugin catalogs without leaking implementation objects.
Attributes:
| Name | Type | Description |
|---|---|---|
category |
str
|
Canonical plugin category. |
name |
str
|
Canonical plugin name used in configs. |
factory |
Callable[..., Any]
|
Callable used by |
description |
str
|
Human-readable summary for docs and UI catalogs. |
version |
str
|
Plugin implementation version. This is independent from pipeline config schema versioning. |
aliases |
tuple[str, ...]
|
Backwards-compatible names accepted by lookup and config builders. |
metadata |
Mapping[str, Any]
|
Immutable mapping for UI tags, ownership, expected inputs, hardware requirements, or adapter-specific catalog data. |
factory_path
property
factory_path: str
Return a stable dotted path for diagnostics and exported descriptors.
as_dict
as_dict() -> dict[str, Any]
Return a JSON-serializable descriptor without exposing the factory object.
PluginRegistry
Lightweight, centralised registry for pluggable pipeline components.
Design rationale
The registry is the single source of truth for available components. It decouples builders (which only know category + name) from concrete implementations (which only need to call register() once).
Thread safety
Registration usually happens at startup, but the registry still protects reads and writes with a re-entrant lock. Snapshots returned by public inspection methods are immutable.
register
register(
category: str | PluginCategory,
name: str,
factory: Callable[..., Any],
description: str = "",
*,
version: str = _DEFAULT_PLUGIN_VERSION,
aliases: Iterable[str] = (),
metadata: Mapping[str, Any] | None = None,
) -> PluginDefinition
Register a new plugin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
category
|
str | PluginCategory
|
Public plugin category, usually a |
required |
name
|
str
|
Stable canonical name used in declarative configs. |
required |
factory
|
Callable[..., Any]
|
Callable used to instantiate the component. |
required |
description
|
str
|
Optional human-readable description for diagnostics and catalogs. |
''
|
version
|
str
|
Plugin implementation version. |
_DEFAULT_PLUGIN_VERSION
|
aliases
|
Iterable[str]
|
Alternative lookup names for backwards compatibility. |
()
|
metadata
|
Mapping[str, Any] | None
|
Optional immutable metadata exposed through |
None
|
Returns:
| Type | Description |
|---|---|
PluginDefinition
|
Immutable descriptor stored by the registry. |
Raises:
| Type | Description |
|---|---|
InvalidPluginRegistrationError
|
If category/name/aliases/factory/version are malformed. |
DuplicatePluginRegistrationError
|
If a plugin with the same (category, name) pair is already registered. |
register_definition
register_definition(
definition: PluginDefinition,
) -> PluginDefinition
Register an already-built plugin definition.
This method applies the same validation and duplicate checks as
register(); it does not bypass registry invariants.
get
get(
category: str | PluginCategory, name: str
) -> PluginDefinition
Return the plugin definition for a category and name or alias.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the category/name pair cannot be resolved. Builders wrap this
into |
create
create(
category: str | PluginCategory,
name: str,
*args,
**kwargs,
) -> Any
Instantiate the plugin identified by category and name or alias.
Side Effects
Calls the registered factory with the provided positional and keyword arguments. Factory exceptions are intentionally not swallowed here so builders can attach configuration context.
list
list(
category: str | PluginCategory | None = None,
) -> list[PluginDefinition]
Return canonical plugin definitions, optionally filtered by category.
contains
contains(category: str | PluginCategory, name: str) -> bool
Return whether a plugin name or alias is registered in a category.
available_names
available_names(
category: str | PluginCategory,
*,
include_aliases: bool = False,
) -> tuple[str, ...]
Return registered names for a category.
Names are sorted to keep diagnostics, docs, and UI catalogs deterministic.
categories
categories() -> tuple[str, ...]
Return categories that currently contain at least one plugin.
snapshot
snapshot() -> Mapping[str, Mapping[str, PluginDefinition]]
Return an immutable category/name snapshot.
The snapshot contains canonical plugin definitions only; aliases remain lookup concerns and are visible through each definition.
describe
describe(
category: str | PluginCategory | None = None,
) -> list[dict[str, Any]]
Return JSON-serializable plugin descriptors for diagnostics and UIs.
create_builtin_registry
create_builtin_registry() -> PluginRegistry
Register the built-in OpenCV and Matplotlib components and return the registry.
This factory is the canonical entry-point for production use. Custom plugins can be added to the returned registry before passing it to a builder.
Example
registry = create_builtin_registry() registry.register(PluginCategory.ANALYZER, "my_analyzer", MyAnalyzer) builder = ConfigPipelineBuilder(registry)