from abc import ABC, abstractmethod
from typing import ClassVar
from attrs import define, field
from . import MessageBusConfigurationError
from .command import Command
from .event import Event
from .returnmessage import ReturnMessage
type HandlerReturnType = list[Command | ReturnMessage]
[docs]
@define
class Handler(ABC):
"""
Abstract base class for handling one or more :py:class:`~bus_ride.event.Event`.
Event handlers should do as little as possible, such as send a quick notification,
log an action, or issue Command(s). If an Event implies anything significant needs
to be done in response, the Handler should return
:py:class:`~bus_ride.command.Command` object(s). We can't enforce this guideline
for you, but recommend you follow it.
Your handler may return a list containing :py:class:`~bus_ride.command.Command`
and/or :py:class:`~bus_ride.returnmessage.ReturnMessage` objects.
If one or more :py:class:`~bus_ride.returnmessage.ReturnMessage` are returned,
your application should do something with them.
.. note::
Event handlers are located by searching through all subclasses of
``Handler``, to find Handler(s) that accept the Event. They are cached once
located. If any of your Handlers are not being used when they should be,
make sure they are imported when your application starts up. Usually,
importing them in an ``__init__.py`` file or keeping them in the same file
with their ``Event`` will fix it.
"""
event: Event = field()
handles_events: ClassVar[list[type[Event]]]
"""
A list of the :py:class:`~bus_ride.event.Event` class(es) this ``Handler`` should
respond to.
"""
def __attrs_post_init__(self): # pragma: no cover
if not self.handles_events:
msg = f"Handler {self.__class__.__name__} must define handles_events."
raise MessageBusConfigurationError(msg)
[docs]
@abstractmethod
def handle_event(self) -> HandlerReturnType: # pragma: no cover
"""
Your implementation of a response to ``self.event``.
"""
raise NotImplementedError
[docs]
@classmethod
def handles_event(cls, event: Event) -> bool: # pragma: no cover
"""
Determines whether this handler should respond to ``event``.
"""
return type(event) in cls.handles_events
type HandlerType = type[Handler]