Plugin Catalog
Generic plugin registry with typed descriptors and attribute-based filtering for Python.
Overview
vcti-plugin-catalog is the registry layer for plugin-style architectures —
anywhere an application keeps a set of interchangeable components (parsers,
exporters, validators, loaders) and must pick the right one at runtime. A
Descriptor[T] pairs a component instance with its metadata: a unique id, a
display name, and a free-form attributes dict. A Registry[D] holds those
descriptors, retrieves them by id in constant time, and filters them by
attribute rules via vcti-lookup. The
registry does no discovery — it never imports, constructs, or invokes a plugin,
so the wiring and trust decisions stay in your code. Both classes are generic
and built to be subclassed into a typed, domain-specific catalog.
Installation
pip install vcti-plugin-catalog>=1.0.2
In pyproject.toml dependencies
dependencies = [
"vcti-plugin-catalog>=1.0.2",
]
Quick Start
from vcti.lookup import Rule
from vcti.plugincatalog import Descriptor, Registry
# Define your plugin type
class Parser:
def __init__(self, extensions: list[str]):
self.extensions = extensions
# Create descriptors with metadata
csv_parser = Descriptor(
id="csv",
name="CSV Parser",
instance=Parser([".csv"]),
attributes={"file_type": "text", "streaming": True},
)
json_parser = Descriptor(
id="json",
name="JSON Parser",
instance=Parser([".json"]),
attributes={"file_type": "text", "streaming": False},
)
binary_parser = Descriptor(
id="hdf5",
name="HDF5 Parser",
instance=Parser([".h5", ".hdf5"]),
attributes={"file_type": "binary", "streaming": False},
)
# Build a registry
registry = Registry()
registry.register_many([csv_parser, json_parser, binary_parser])
# Lookup by ID
parser = registry.get("csv").instance
# Filter by attributes
text_parsers = registry.lookup.filter([Rule("file_type", "==", "text")])
# [csv_parser_desc, json_parser_desc]
# Multiple rules (AND)
streaming = registry.lookup.filter([
Rule("file_type", "==", "text"),
Rule("streaming", "==", True),
])
# [csv_parser_desc]
# OR filtering
subset = registry.lookup.filter_any([
Rule("file_type", "==", "binary"),
Rule("streaming", "==", True),
])
# [csv_parser_desc, hdf5_parser_desc]
# First match
first = registry.lookup.first([Rule("file_type", "==", "text")])
Core API
Descriptor[T]
Generic container holding plugin metadata and instance:
| Attribute | Type | Description |
|---|---|---|
id |
str |
Unique identifier |
name |
str |
Human-readable name |
instance |
T |
The plugin instance |
description |
str | None |
Optional description |
attributes |
dict[str, Any] |
Filterable metadata |
Registry[D]
Collection manager for descriptors:
| Method | Description |
|---|---|
register(descriptor) |
Add a descriptor |
register_many(descriptors) |
Add multiple descriptors |
unregister(id) |
Remove a descriptor |
unregister_many(ids) |
Remove multiple descriptors |
get(id) |
Retrieve by ID (raises EntryNotFoundError) |
find(id) |
Retrieve by ID or return None |
all() |
List all descriptors |
ids() |
List all IDs |
lookup |
Cached Lookup for attribute filtering |
create_lookup() |
New independent Lookup instance |
copy() |
Shallow copy of the registry |
clear() |
Remove all descriptors |
isolated(preload=) |
Context manager for test isolation |
The registry also supports in, len(), and for ... in iteration.
Filtering
The registry.lookup property returns a vcti.lookup.Lookup instance
that filters against descriptor .attributes:
from vcti.lookup import Rule
# AND — all rules must match
registry.lookup.filter([Rule("type", "==", "text"), Rule("active", "==", True)])
# OR — any rule matches
registry.lookup.filter_any([Rule("type", "==", "text"), Rule("type", "==", "csv")])
# NOT — exclude matches
registry.lookup.exclude([Rule("deprecated", "==", True)])
# First match
registry.lookup.first([Rule("type", "==", "text")])
See vcti-lookup for the full filtering API including operators, modifiers, and more.
Lifecycle
# Safe lookup (returns None instead of raising)
desc = registry.find("maybe-missing")
# Remove a plugin
registry.unregister("hdf5")
# Remove several at once
registry.unregister_many(["csv", "json"])
# Iterate over all registered descriptors
for desc in registry:
print(desc.id, desc.name)
Test Isolation
with Registry.isolated(preload=[csv_parser, json_parser]) as test_reg:
assert len(test_reg) == 2
test_reg.unregister("csv")
assert len(test_reg) == 1
# test_reg is discarded — the original registry is untouched
Dependencies
- vcti-lookup (>=1.0.1) — attribute-based filtering
Documentation
| If you want to… | Read |
|---|---|
| Get started using the package | Quick Start above |
| See practical, real-world usage | docs/patterns.md |
| Extend the library (new descriptor types, registry subclasses) | docs/extending.md |
| Understand the architecture and design decisions | docs/design.md |
| Navigate and understand the source | docs/source-guide.md |
| Troubleshoot or check a common question | docs/faq.md |
Metadata
Release files for vcti-plugin-catalog 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vcti_plugin_catalog-1.0.2.tar.gz | 15.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vcti_plugin_catalog-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.0 kB
Release files / vcti_plugin_catalog-1.0.2.tar.gz
| Download URL | vcti_plugin_catalog-1.0.2.tar.gz |
|---|---|
| Size | 15.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
232ebdefcc006088c51735a6d863ae40503ae8925082a386274955eba23256ee
|
|
BLAKE2b-256 checksum How to use checksums |
f8fbc60d64c6f912ce150fb02b3c8d95d6b917830b45c0940d92a0bf21e72185
|
| 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 Aug 28, 2026.
Transparency logRelease files / vcti_plugin_catalog-1.0.2-py3-none-any.whl
| Download URL | vcti_plugin_catalog-1.0.2-py3-none-any.whl |
|---|---|
| Size | 8.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06357dbe6c6457503c817b549ecfdea4b28c905aecf738a588402508a42a56da
|
|
BLAKE2b-256 checksum How to use checksums |
f0fa6bbb2451215f23a2eb8af0d1246ffb2fa36eb88bb0b014906f36a1d18ec9
|
| 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 Aug 28, 2026.
Transparency log