python 56 lines · 9 steps

A decorator-based plugin registry in Python

A registry class uses a parameterized decorator to map names to classes so you can look them up and instantiate them by string.

Explained by highlit
1from typing import Callable, Dict, Type
2 
3 
4class PluginRegistry:
5 def __init__(self) -> None:
6 self._plugins: Dict[str, Type] = {}
7 
8 def register(self, name: str | None = None) -> Callable[[Type], Type]:
9 def decorator(cls: Type) -> Type:
10 key = name or getattr(cls, "plugin_name", cls.__name__.lower())
11 if key in self._plugins:
12 raise ValueError(f"Plugin {key!r} is already registered by {self._plugins[key].__name__}")
13 cls.plugin_name = key
14 self._plugins[key] = cls
15 return cls
16 
17 return decorator
18 
19 def get(self, name: str) -> Type:
20 try:
21 return self._plugins[name]
22 except KeyError:
23 raise LookupError(f"No plugin registered under {name!r}. Available: {sorted(self._plugins)}") from None
24 
25 def create(self, name: str, *args, **kwargs):
26 return self.get(name)(*args, **kwargs)
27 
28 def names(self) -> list[str]:
29 return sorted(self._plugins)
30 
31 def __contains__(self, name: str) -> bool:
32 return name in self._plugins
33 
34 
35exporters = PluginRegistry()
36 
37 
38@exporters.register("json")
39class JsonExporter:
40 def export(self, rows):
41 import json
42 
43 return json.dumps(rows)
44 
45 
46@exporters.register("csv")
47class CsvExporter:
48 def export(self, rows):
49 import csv
50 import io
51 
52 buf = io.StringIO()
53 writer = csv.DictWriter(buf, fieldnames=rows[0].keys())
54 writer.writeheader()
55 writer.writerows(rows)
56 return buf.getvalue()
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A decorator that takes arguments is really a factory returning the real decorator, giving you a three-layer closure.
  2. 2Storing classes (not instances) in a registry lets you defer construction until you know the arguments.
  3. 3Guarding against duplicate keys at registration time turns silent overrides into loud, early errors.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A decorator-based plugin registry in Python — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code