The Plugin
What is a Plugin?
A Plugin is where your actual functionality lives. It's the concrete implementation that users interact with. Plugins:
Are attached to a specific Handler via the
@Plugin.for_handler()decoratorReceive services automatically through injection
Define metadata (name, version, description)
Can be extended through inheritance for polymorphic behavior
Attaching Plugins to Handlers
Every plugin must be attached to a handler using the @Plugin.for_handler() decorator:
from gl_plugin.plugin.plugin import Plugin
@Plugin.for_handler(CalculatorHandler)
class MathPlugin(Plugin):
name = "MathPlugin"
version = "1.0.0"
description = "A math plugin"This binding tells the framework:
Which handler manages this plugin
What services to inject (from that handler's
create_injections())How to initialize the plugin (via that handler's
initialize_plugin())
A plugin can only be attached to one handler. If you need the same functionality across different handlers, create a shared base class and extend it for each handler.
Plugin Metadata
Every plugin requires three metadata attributes:
name
Unique identifier used with manager.get_plugin("name")
version
Version tracking for your plugin
description
Documents what the plugin does
Abstract vs Concrete Plugins
Plugins support inheritance, allowing you to define abstract base plugins with shared behavior and concrete implementations with specific functionality.
Abstract Base Plugin
Define a base plugin with shared services and abstract methods:
Concrete Implementations
Extend the base plugin with specific implementations:
Benefits of This Pattern
This pattern allows you to:
Define a consistent interface via the base plugin
Share service injections across all implementations
Add new operations without modifying existing code
Process all plugins of a type uniformly
Overriding Injected Services
Sometimes you need to replace an injected service with your own instance. GL Plugin's injection mechanism makes this straightforward using Python's __new__ vs __init__ lifecycle.
Understanding the Lifecycle

__new__— Instance is created, services are injected__init__— Your initialization code runs, services already exist
Because injection happens at __new__, any assignment in __init__ overwrites the injected service.
Basic Override
Override Order Matters
If your parent class uses the service in its __init__, override before calling super().__init__():
If the parent doesn't use the service in __init__, order doesn't matter:
When to Override Services
Testing with Mocks
Replace real services with mocks for unit testing:
Special Cases Requiring Custom Instances
When a specific plugin needs different configuration:
Concrete Implementations Needing Different Behavior
When extending a plugin but needing a specialized service:
Summary
@Plugin.for_handler()
Binds a plugin to its handler
Metadata
name, version, description required
Abstract plugins
Define shared interface and services
Concrete plugins
Implement specific functionality
Inheritance
Child plugins inherit services and behavior
Overriding
Assign in __init__ to replace injected services
Override order
Override before super().__init__() if parent uses the service
Last updated