Defining Hooks¶
Hook specifications define the extension points in your application that plugins can implement.
Basic Syntax¶
Use the @simplug.spec decorator to define a hook:
from simplug import Simplug, SimplugResult
simplug = Simplug('myapp')
@simplug.spec
def my_hook(arg1, arg2):
"""My hook documentation."""
Decorator Options¶
The @simplug.spec decorator accepts the following parameters:
required¶
Whether this hook must be implemented by at least one plugin.
If no plugin implements a required hook, calling it will raise HookRequired exception.
result¶
Specifies how to collect results from plugin implementations. See Result Collection for all available strategies.
from simplug import SimplugResult
# Collect all non-None results
@simplug.spec(result=SimplugResult.ALL_AVAILS)
def process_data(data):
"""Process data and return results."""
warn_sync_impl_on_async¶
For async hooks, whether to warn when a plugin provides a synchronous implementation.
# Warn if plugin provides sync implementation
@simplug.spec(warn_sync_impl_on_async=True)
async def async_hook(data):
"""Async hook with sync implementation warning."""
Default is True. Set to False to suppress warnings.
Parameter Names and Defaults¶
Hook parameters are matched by name between spec and implementation.
Specifying Default Values¶
You can specify default values in the spec:
Implementation Requirements¶
Implementations must have the same parameter names, but default values are not required:
@plugin.impl
def configure(self, timeout, retries):
# Default values not needed in implementation
print(f"timeout={timeout}, retries={retries}")
Note
Default values in implementation functions are ignored. Always specify defaults in the hook specification.
The self Parameter¶
When defining hooks inside a class, you can use self as the first parameter:
When the hook is called, self will be None. This is just a naming convention for clarity.
Async Hooks¶
Define async hooks using async def:
See Async Hooks for more details on async hooks.
Signature Validation¶
simplug validates that hook implementations match the specification:
@simplug.spec
def my_hook(arg1, arg2):
"""Hook specification."""
class BadPlugin:
@simplug.impl
def my_hook(wrong_arg): # Mismatched signature!
pass
simplug.register(BadPlugin) # Raises HookSignatureDifferentFromSpec
Parameter names must match exactly (excluding self).
Hook Names¶
Hook names are derived from the function name:
Duplicate hook names are not allowed:
Complete Example¶
from simplug import Simplug, SimplugResult
simplug = Simplug('dataapp')
class DataHooks:
@simplug.spec(required=True)
def validate(self, data):
"""Validate data - required hook."""
@simplug.spec(result=SimplugResult.ALL_AVAILS)
def transform(self, data):
"""Transform data - collect all non-None results."""
@simplug.spec(result=SimplugResult.FIRST_AVAIL)
def get_cache_key(self, data):
"""Get cache key - first available result only."""
# Now plugins can implement these hooks
Next Steps¶
- Implementing Hooks - How to implement hook specifications
- Result Collection - All result collection strategies
- Async Hooks - Working with async hooks