High-level handlers MR2: Contextual handlers
This MR is split out from the original High-level handlers MR !25 (closed), towards uis/devops/epics#321
These MRs are chained, with each MR targeting the previous MR's branch. They either need to be merged in order, or all at once from the final one (after changing it to target main).
This MR adds support for the implicit context used by the higher level handlers
(@cloud_event_handler and @message_handler) to provide access to information
about the event being handled, without passing the event down through every
function a handler uses. This implicit context is used to automatically populate
ExecutionInfo values with information about the event/message, for example
things like the ID and type of the CloudEvent, the ID of the Pub/Sub message,
its topic, etc.
Two things are added in this MR:
-
contextual_default_factory()function -
@contextual_handler()decorator
contextual_default_factory()
contextual_default_factory() is used to automatically populate fields in
Pydantic models and Python dataclasses. Both of these support providing default
values to fields with a default_factory option to their respective field
configuration.
contextual_default_factory() generates default factory functions that read a
value from a ContextVar, and map it through a function (e.g. to pull out a sub
property or otherwise transform the value).
We use this on any field of an ExceptionInfo subclass that needs to be
automatically populated. The tests here have an example of this:
ucam_faas/tests/test_contextual_handlers.py has ExampleExecutionInfo which
automatically populates its weather_today field.
@contextual_handler()
Contextual event handler functions receive a primary value as an argument, with
additional context value provided implicitly using a ContextVar.
This separation allows a handler function to act primarily on an important
subset of incoming event data, but still access the wider event metadata when
needed, and automatically include metadata in ExecutionInfo result values
(using the contextual_default_factory() pattern).
Incoming events are separated into the primary value and context value by a parser function that receives the incoming event value from the parent handler.
The @contextual_handler(...) decorator is the interface to this functionality.
Issues
This MR contributes towards the later @cloud_event_handler and
@message_handler MRs, but doesn't implement any specific issue in full.