Source code for betty.event_dispatcher

"""
Provide the Dispatch API.
"""

from __future__ import annotations

from asyncio import gather
from collections import defaultdict
from typing import (
    Sequence,
    Callable,
    Awaitable,
    TypeVar,
    TypeAlias,
    TYPE_CHECKING,
    final,
)

if TYPE_CHECKING:
    from collections.abc import MutableMapping, MutableSequence, Mapping


[docs] class Event: """ An event that can be dispatched and handled. For each unique 'conceptual' event (a thing that happens while using Betty), a subclass **MUST** be created for that specific event type. Instances of these subclasses are dispatched and handled. """ pass
_EventT = TypeVar("_EventT", bound=Event) EventHandler: TypeAlias = Callable[[_EventT], Awaitable[None]] class _EventHandlerRegistry: """ Manage event handlers. """ def __init__(self): self._handlers: MutableMapping[ type[Event], MutableSequence[Sequence[EventHandler[Event]]] ] = defaultdict(list) def add_handler(self, event_type: type[_EventT], *handlers: EventHandler[_EventT]): """ Add a batch of one or more event handlers. All handlers of a batch are invoked concurrently. """ self._handlers[event_type].append( handlers # type: ignore[arg-type] ) def add_registry(self, event_handler_registry: EventHandlerRegistry) -> None: """ Add another registry to this one. """ for ( event_type, event_type_handler_batches, ) in event_handler_registry.handlers.items(): for event_type_handler_batch in event_type_handler_batches: self.add_handler(event_type, *event_type_handler_batch)
[docs] @final class EventHandlerRegistry(_EventHandlerRegistry): """ Manage event handlers. """ @property def handlers( self, ) -> Mapping[type[Event], Sequence[Sequence[EventHandler[Event]]]]: """ The registered event handlers. """ return self._handlers
[docs] @final class EventDispatcher(_EventHandlerRegistry): """ Dispatch events to event handlers. """
[docs] async def dispatch(self, event: Event) -> None: """ Dispatch an event. """ for handler_batch in self._handlers[type(event)]: await gather(*(handler(event) for handler in handler_batch))