After #360 we should do this
Summary
We need a way for external packages (e.g. fastcs_foo) to register Controller subclasses so that fastcs can discover and instantiate them dynamically (e.g. from YAML configuration), without requiring explicit imports of those packages.
This would enable a proper plugin ecosystem for controllers.
Proposed approach
Use Python packaging entry points as an extension mechanism.
- Define an entry point group:
fastcs.controllers
- Each plugin package registers its
Controller subclasses there
fastcs discovers them at runtime using importlib.metadata.entry_points
Example plugin (fastcs_foo)
Implementation
# fastcs_foo/foo_controller.py
from fastcs.controller import Controller
class FooController(Controller):
def run(self):
print(f"Foo running with {self.config}")
Registration
# pyproject.toml
[project.entry-points."fastcs.controllers"]
FooController = "fastcs_foo.foo_controller:FooController"
YAML configuration
Controllers are referenced by:
Example:
controllers:
- type: fastcs_foo.FooController
config:
speed: 10
Discovery + resolution (in fastcs)
from importlib.metadata import entry_points
from fastcs.controller import Controller
def discover_controllers():
registry = {}
for ep in entry_points(group="fastcs.controllers"):
cls = ep.load()
namespace = cls.__module__.split(".", 1)[0]
name = ep.name
registry[(namespace, name)] = cls
return registry
def resolve_controller(type_string: str):
namespace, class_name = type_string.split(".", 1)
registry = discover_controllers()
key = (namespace, class_name)
if key not in registry:
raise ValueError(f"Unknown controller '{type_string}'")
cls = registry[key]
if not issubclass(cls, Controller):
raise TypeError(f"{type_string} is not a Controller subclass")
return cls
Benefits
- No explicit imports required
- Clean separation between core and plugins
- Works with standard Python packaging
- Controllers can live in independently installable packages
- YAML remains simple and explicit (
fastcs_foo.FooController)
Notes / future considerations
- Could validate distribution name vs module root more strictly
- Could support aliases or versioning
- Could cache discovery results for performance
Outcome
This would provide a robust, extensible plugin system for Controller implementations, similar to how pytest and other tools manage plugins.
After #360 we should do this
Summary
We need a way for external packages (e.g.
fastcs_foo) to registerControllersubclasses so thatfastcscan discover and instantiate them dynamically (e.g. from YAML configuration), without requiring explicit imports of those packages.This would enable a proper plugin ecosystem for controllers.
Proposed approach
Use Python packaging entry points as an extension mechanism.
fastcs.controllersControllersubclasses therefastcsdiscovers them at runtime usingimportlib.metadata.entry_pointsExample plugin (
fastcs_foo)Implementation
Registration
YAML configuration
Controllers are referenced by:
Example:
Discovery + resolution (in
fastcs)Benefits
fastcs_foo.FooController)Notes / future considerations
Outcome
This would provide a robust, extensible plugin system for
Controllerimplementations, similar to how pytest and other tools manage plugins.