Skip to content

Decorators

decorators

Decorators for message classes.

Provides @message_dataclass (and its aliases @event_dataclass,
@command_dataclass, @query_dataclass) to reduce boilerplate when
defining message types. The decorated class is a frozen dataclass whose
fields are automatically exposed via get_payload_fields() and are used
by from_payload_fields() for reconstruction.

Example
class OrderPayload:
    def __init__(self, order_id: str, customer_id: str, total: float) -> None:
        self.order_id = order_id
        self.customer_id = customer_id
        self.total = total


class Event[T]:
    # Inline stub for the example.
    pass


@event_dataclass
class OrderCreated(Event[OrderPayload]):
    order_id: str
    customer_id: str
    total: float


event = OrderCreated(order_id="ORD-001", customer_id="CUST-42", total=99.95)

event_dataclass = message_dataclass module-attribute

Alias for @message_dataclass intended for domain events.

command_dataclass = message_dataclass module-attribute

Alias for @message_dataclass intended for commands.

query_dataclass = message_dataclass module-attribute

Alias for @message_dataclass intended for queries.

message_dataclass(cls: type[_M] | None = None) -> type[_M] | Callable[[type[_M]], type[_M]]

message_dataclass(cls: type[_M]) -> type[_M]
message_dataclass(
    cls: None = None,
) -> Callable[[type[_M]], type[_M]]

Decorate a class as a message dataclass.

The decorator applies @dataclass(frozen=False) and then replaces
__setattr__ and __delattr__ with custom implementations that raise
FrozenInstanceError after __init__ completes. It also patches
get_payload_fields and from_payload_fields onto the class so that
payload data is automatically derived from its fields.

When the decorated class inherits from an abstract base (e.g.
Event, Command, Query), the decorator
automatically patches _payload, value, and
from_payload_fields — and removes them from __abstractmethods__
— so the concrete subclass is instantiable without manual stubs.

Parameters:

Name Type Description Default
cls type[_M] | None

The class to decorate (when used without arguments).

None

Returns:

Type Description
type[_M] | Callable[[type[_M]], type[_M]]

The decorated class (or a wrapper when called with keyword arguments).

Source code in src/forging_blocks/domain/messages/decorators.py
def message_dataclass(
    cls: type[_M] | None = None,
) -> type[_M] | Callable[[type[_M]], type[_M]]:
    """Decorate a class as a message dataclass.

    The decorator applies ``@dataclass(frozen=False)`` and then replaces
    ``__setattr__`` and ``__delattr__`` with custom implementations that raise
    ``FrozenInstanceError`` after ``__init__`` completes. It also patches
    ``get_payload_fields`` and ``from_payload_fields`` onto the class so that
    payload data is automatically derived from its fields.

    When the decorated class inherits from an abstract base (e.g.
    `Event`, `Command`, `Query`), the decorator
    automatically patches ``_payload``, ``value``, and
    ``from_payload_fields`` — and removes them from ``__abstractmethods__``
    — so the concrete subclass is instantiable without manual stubs.

    Args:
        cls: The class to decorate (when used without arguments).

    Returns:
        The decorated class (or a wrapper when called with keyword arguments).
    """
    return _wrap_message_dataclass if cls is None else _wrap_message_dataclass(cls)