Hooks
Hooks let you attach extra behavior (refreshing models, firing custom logic, raising alerts) whenever a component emits lifecycle events such as on_set, on_run, or on_error. The SDK treats hooks as child components: you describe them declaratively, and the Hooks container registers each hook class on the parent component.
What is registered
Hooks: aSpxContainersubclass that reads thehooks:section of a definition.RefreshHook: a built-in hook (refresh_model) that callsprepare()andrun()on the root component, useful for recalculating derived values after an attribute change.
Both are exposed via spx_sdk.hooks. The container itself is decorated with @definition_schema, so invalid shapes are rejected early.
Defining hooks in YAML
Each entry under hooks maps an event name to one or more hook classes. You can supply either a bare class name or a single-key object that includes per-hook configuration.
attributes:
temperature:
default: 20.0
hooks:
on_set:
- refresh_model # reuse built-in hook
- notifier_hook # another custom hook, no config
on_threshold:
alert_hook:
level: critical
email: [email protected]
{
"attributes": {
"temperature": {
"default": 20.0,
"hooks": {
"on_set": [
"refresh_model",
"notifier_hook"
],
"on_threshold": {
"alert_hook": {
"level": "critical",
"email": "[email protected]"
}
}
}
}
}
}
When the SDK loads this definition, it creates hook instances under the attribute's Hooks container:
refresh_model-> instance ofRefreshHooknotifier_hook-> instance of a user-registered classalert_hook-> instance configured with the provided payload
Hooks are stored on the parent component and triggered via trigger_hooks(event_name, *args, **kwargs); tests under tests/test_hooks/test_hooks.py confirm each entry runs when the parent triggers the event.
Authoring custom hooks
Create a subclass of SpxComponent, register it, and implement run():
Use keyword arguments to accept contextual information when the parent triggers your hook (for example, the attribute object, old/new values, or custom metadata).
Runtime integration
During _populate, the Hooks container normalises every event entry into a list, instantiates the specified classes using create_instance, and registers them on the parent via parent.register_hook(event_name, hook_instance). Duplicate classes gain suffixes (dummy_hook, dummy_hook_1) to stay unique, as shown in tests/test_hooks/test_hooks.py::test_duplicate_entries_named_uniquely.
At runtime, call component.trigger_hooks("on_update", attribute=self, value=new_value). Each hook's run() executes in order; returning True signals success, while raising SpxFault (or any exception) propagates according to your diagnostics setup.
Validating definitions
The JSON Schema attached to Hooks catches malformed definitions before instantiation:
event values must be a string, list of strings, or a single-key object
{HookClass: {...}},lists cannot contain booleans or other primitives,
dict entries must only declare one hook class (see
tests/test_hooks/test_hooks_validation.py).
This means user-supplied YAML that misconfigures hooks produces a structured validation error instead of a runtime crash.
Built-in refresh_model hook
refresh_model hookThe included RefreshHook calls prepare() and run() on the root component. Use it when an attribute change should immediately recompute dependent state:
When weight changes, the hook re-prepares and re-runs the system, mirroring the behaviour covered in tests/test_hooks/test_hooks_attributes.py.
Last updated

