Source code for maverick.events

"""
Game event model for the synchronous event dispatch system.

This module defines an immutable GameEvent payload that represents
a snapshot of what happened in the game at a specific point in time.
"""

import time
import uuid
import warnings
from typing import Optional, Any

from pydantic import BaseModel, ConfigDict, Field, model_validator

from .enums import GameEventType, Street, GameStage
from .playeraction import PlayerAction

__all__ = ["GameEvent"]


[docs] class GameEvent(BaseModel): """ Immutable game event payload. Represents a snapshot of a game event that occurred, including the type of event, current game state, and relevant action details. Payload by event type: - PLAYER_CARDS_REVEALED: - holding: list[str] - The player's hole cards as a list of card codes. - best_hand: list[str] - The best hand the player can make as a list of card codes. - best_hand_type: str - The type of the best hand (e.g., "FLUSH") according to HandType. - best_score: float - The score of the best hand the player can make. .. versionadded:: 0.2.0 Fields ------ type : GameEventType The type of event that occurred. hand_number : int The current hand number. street : Optional[Street] The current betting street. stage : Optional[GameStage] The current game stage. .. versionadded:: 0.2.0 uid : str Unique identifier for the event. Replaces deprecated ``id``. player_uid : Optional[str] UID of the player involved in the event, if applicable. Replaces deprecated ``player_id``. action : Optional[PlayerAction] The action taken by the player, if applicable. payload : dict[str, Any] Additional event-specific data. """ uid: str = Field(default_factory=lambda: uuid.uuid4().hex, alias="id") ts: float = Field(default_factory=time.time) type: GameEventType hand_number: int street: Optional[Street] = None stage: Optional[GameStage] = None player_uid: Optional[str] = Field(default=None, alias="player_id") action: Optional[PlayerAction] = None payload: dict[str, Any] = Field(default_factory=dict) @model_validator(mode="before") @classmethod def _warn_on_deprecated_params(cls, data): if isinstance(data, dict): if "id" in data and "uid" not in data: warnings.warn( "GameEvent 'id' parameter is deprecated, use 'uid' instead.", DeprecationWarning, stacklevel=2, ) if "player_id" in data and "player_uid" not in data: warnings.warn( "GameEvent 'player_id' parameter is deprecated, use 'player_uid' instead.", DeprecationWarning, stacklevel=2, ) return data model_config = ConfigDict( frozen=True, # Makes the model immutable extra="forbid", # Prevents accidental fields arbitrary_types_allowed=True, populate_by_name=True, # Allow both uid= and id= in constructor ) @property def id(self) -> str: """Deprecated: use ``uid`` instead.""" warnings.warn( "GameEvent.id is deprecated, use GameEvent.uid instead.", DeprecationWarning, stacklevel=2, ) return self.uid @property def player_id(self) -> Optional[str]: """Deprecated: use ``player_uid`` instead.""" warnings.warn( "GameEvent.player_id is deprecated, use GameEvent.player_uid instead.", DeprecationWarning, stacklevel=2, ) return self.player_uid