| from __future__ import annotations |
|
|
| from collections.abc import Callable |
| from dataclasses import dataclass, field |
| from enum import Enum |
| from typing import Any |
|
|
|
|
| class StrEnum(str, Enum): |
| """Python 3.10-compatible subset of enum.StrEnum.""" |
|
|
| def __str__(self) -> str: |
| return str(self.value) |
|
|
|
|
| class EventType(StrEnum): |
| """Event names shared across future services.""" |
|
|
| DATASET_LOADED = "dataset_loaded" |
| INFERENCE_REQUEST = "inference_request" |
| INFERENCE_RESPONSE = "inference_response" |
| UI_ERROR = "ui_error" |
| FIELD_NOTE_SAVED = "field_note_saved" |
| TRAINING_STARTED = "training_started" |
| EXPORT_STARTED = "export_started" |
|
|
|
|
| @dataclass |
| class Event: |
| """A lightweight event payload.""" |
|
|
| type: EventType |
| payload: dict[str, Any] = field(default_factory=dict) |
|
|
|
|
| class EventBus: |
| """In-process event dispatcher for low-volume app events.""" |
|
|
| def __init__(self) -> None: |
| self._handlers: dict[EventType, list[Callable[[Event], None]]] = {} |
|
|
| def on(self, event_type: EventType) -> Callable: |
| def decorator(fn: Callable[[Event], None]) -> Callable[[Event], None]: |
| self._handlers.setdefault(event_type, []).append(fn) |
| return fn |
|
|
| return decorator |
|
|
| def emit(self, event: Event) -> None: |
| for handler in self._handlers.get(event.type, []): |
| handler(event) |
|
|
|
|
| bus = EventBus() |
|
|