Source code for mersal._activation.builtin_handler_activator

from __future__ import annotations

from collections import defaultdict
from typing import TYPE_CHECKING, TypeVar, cast

from mersal.exceptions import MersalExceptionError
from mersal.pipeline import MessageContext

if TYPE_CHECKING:
    from collections.abc import Sequence

    from mersal._activation.handler_activator import HandlerFactory
    from mersal.core.app import Mersal
    from mersal.handlers import MessageHandler
    from mersal.transport import TransactionContext

# Define locally to avoid import cycle with handler_activator.py
MessageT = TypeVar("MessageT")

__all__ = ("BuiltinHandlerActivator",)


[docs] class BuiltinHandlerActivator: """Default implementation of the handler activator pattern. This class manages the registration and activation of message handlers based on message types. It stores handler factories indexed by message type and instantiates the appropriate handlers when a message needs to be processed. """
[docs] def __init__(self) -> None: """Initialize a new instance of the BuiltinHandlerActivator.""" self._handler_factories: dict[type, list[HandlerFactory]] = defaultdict(list) self._app: Mersal | None = None
[docs] async def get_handlers( self, message: MessageT, transaction_context: TransactionContext, ) -> Sequence[MessageHandler[MessageT]]: """Get handlers for the specified message. Args: message: The message to get handlers for transaction_context: The current transaction context Returns: A sequence of message handlers that can process the message Raises: Exception: If called outside of a message context """ message_context = MessageContext.current() if not message_context: raise MersalExceptionError( "BuiltinHandlerActivator get_handlers called outside of a transaction.", ) handlers: list[MessageHandler[MessageT]] = [] for cls in type(message).__mro__: if cls is object: continue handlers.extend(x(message_context, self.app) for x in self._handler_factories.get(cls, [])) return handlers
[docs] def register( self, message_type: type[MessageT], factory: HandlerFactory[MessageT], ) -> BuiltinHandlerActivator: """Register a handler factory for a specific message type. Args: message_type: The type of message to register a handler for factory: A factory function that creates a message handler Returns: The handler activator instance for method chaining """ self._handler_factories[message_type].append(factory) return self
@property def registered_message_types(self) -> set[type]: """Get the set of message types that have registered handlers. Returns: A set containing all registered message types """ return set(self._handler_factories.keys()) @property def app(self) -> Mersal: """Get the associated application instance. Returns: The Mersal application instance """ return cast("Mersal", self._app) @app.setter def app(self, value: Mersal) -> None: """Set the associated application instance. Args: value: The Mersal application instance """ self._app = value