dc4client package

Submodules

dc4client.dc_client module

exception dc4client.dc_client.AuthenticationError(message: str, status: int | None = None, detail: str | None = None)[source]

Bases: Exception

Raised when authentication fails and the client should stop immediately.

class dc4client.dc_client.DCClient(match_id: UUID, username: str, password: str, log_level: int = 20, match_team_name: MatchNameModel = MatchNameModel.team1, socket_read_timeout: int | None = 15, enable_tcp_keepalive: bool = True, auto_save_log: bool = True, log_dir: str = 'logs')[source]

Bases: object

Initialize the DCClient. :param match_id: To identify the match. :type match_id: UUID :param username: Username for authentication. :type username: str :param password: Password for authentication. :type password: str :param log_level: Logging level. :type log_level: int :param match_team_name: The name of the team in the match. :type match_team_name: MatchNameModel :param socket_read_timeout: Timeout in seconds for socket read. Defaults to 15. Set None to disable. :type socket_read_timeout: int | None :param enable_tcp_keepalive: Whether to enable TCP Keep-Alive. Defaults to True. :type enable_tcp_keepalive: bool :param auto_save_log: Whether to enable log buffering and saving. Defaults to True. :type auto_save_log: bool :param log_dir: Directory to save logs. Defaults to “logs”. :type log_dir: str

get_end_number() int[source]

Get the current end number from the state data.

get_last_move() ShotInfoSchema | None[source]

Get the last move information from the state data.

get_next_team() str | None[source]

Get the next team to shot from the state data.

get_score() tuple[list, list] | None[source]

Get the current score from the state data.

get_shot_number() int | None[source]

Get the current shot number from the state data.

get_stone_coordinates() tuple[list[tuple[float, float]], list[tuple[float, float]]][source]

Get the stone coordinates for both teams from the state data. :returns: A tuple containing two lists of tuples.

The first list contains the coordinates of team0’s stones, and the second list contains the coordinates of team1’s stones.

Return type:

Tuple[List[Tuple[float, float]], List[Tuple[float, float]]]

get_winner_team() str | None[source]

Get the winner team from the state data.

async receive_state_data() AsyncGenerator[StateSchema, None][source]
Robust SSE receiver with:
  • explicit reconnect loop (exponential backoff + jitter)

  • Authorization header (Basic) for wider compatibility

  • TCP connector with keepalive options

  • clear logging for connect / disconnect / parse errors

save_log_file() None[source]

Saves the buffered logs to a JSONL file.

async send_positioned_stones_info(positioned_stones: PositionedStonesModel) None[source]

This method is to support mixed doubles positioned stones info. Send positioned stones information to the server. :param positioned_stones: Positioned stones information model. :type positioned_stones: PositionedStonesModel

async send_shot_info(translational_velocity: float, shot_angle: float, angular_velocity=1.5707963267948966)[source]

Send shot information to the server. :param translational_velocity: The translational velocity of the stone. :type translational_velocity: float :param shot_angle: The shot angle of the stone in radians. :type shot_angle: float :param angular_velocity: The angular velocity of the stone. :type angular_velocity: float

async send_shot_info_dc3(vx: float, vy: float, rotation: str)[source]

Send shot information to the server for DC3 style input. :param vx: The x-component of the velocity of the stone. :type vx: float :param vy: The y-component of the velocity of the stone. :type vy: float :param rotation: The rotation direction of the stone (“cw” for clockwise, “ccw” for counter-clockwise). :type rotation: str

async send_team_info(team_info: TeamModel) MatchNameModel[source]

Send team information to the server. :param team_info: Team information model. :type team_info: TeamModel

Returns:

The assigned team name in the match.

Return type:

MatchNameModel

set_server_address(host: str, port: int) None[source]

Set the server address for the client. :param host: The server host address. :type host: str :param port: The server port number. :type port: int

class dc4client.dc_client.JsonLineFormatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)[source]

Bases: Formatter

Format log records as single-line JSON. Output keys match:

{“timestamp”: “…”, “logger”: “…”, “level”: “…”, “message”: “…”}

format(record: LogRecord) str[source]

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

class dc4client.dc_client.MemoryBufferHandler[source]

Bases: Handler

Custom logging handler that stores log records in a memory list instead of writing them to a file immediately.

emit(record: LogRecord)[source]

Record log data :param record: The log record to be buffered. :type record: logging.LogRecord

dc4client.match_maker_client module

class dc4client.match_maker_client.MatchMakerClient(host: str, port: int, username: str, password: str)[source]

Bases: object

Initialize the MatchMakerClient. :param host: Server host address. :type host: str :param port: Server port number. :type port: int :param username: Username for authentication. :type username: str :param password: Password for authentication. :type password: str

async create_match(data: ClientDataModel) Any[source]

Create a match on the server.

Returns:

Parsed JSON returned by the server (typically a match_id).

Raises:

RuntimeError – When the request fails (includes status/body).

dc4client.receive_data module

class dc4client.receive_data.CoordinateDataSchema(*, x: float, y: float)[source]

Bases: BaseModel

model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

x: float
y: float
class dc4client.receive_data.MatchDataSchema(*, match_id: UUID, first_team_id: UUID, second_team_id: UUID, score_id: UUID, time_limit: int, extra_end_time_limit: int, standard_end_count: int, physical_simulator_id: UUID, tournament_id: UUID, match_name: str, created_at: datetime, started_at: datetime, score: ScoreSchema | None = None, tournament: TournamentSchema | None = None, simulator: PhysicalSimulatorSchema | None = None)[source]

Bases: BaseModel

created_at: datetime
extra_end_time_limit: int
first_team_id: UUID
match_id: UUID
match_name: str
model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

physical_simulator_id: UUID
score: ScoreSchema | None
score_id: UUID
second_team_id: UUID
simulator: PhysicalSimulatorSchema | None
standard_end_count: int
started_at: datetime
time_limit: int
tournament: TournamentSchema | None
tournament_id: UUID
class dc4client.receive_data.MixedDoublesSettingsSchema(*, end_setup_team: str, positioned_stones_pattern: int, power_play_end: PowerPlayEndSchema)[source]

Bases: BaseModel

end_setup_team: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

positioned_stones_pattern: int
power_play_end: PowerPlayEndSchema
class dc4client.receive_data.PhysicalSimulatorSchema(*, physical_simulator_id: UUID, simulator_name: str)[source]

Bases: BaseModel

model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

physical_simulator_id: UUID
simulator_name: str
class dc4client.receive_data.PlayerSchema(*, player_id: UUID, max_velocity: float, shot_dispersion_rate: float, player_name: str)[source]

Bases: BaseModel

max_velocity: float
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

player_id: UUID
player_name: str
shot_dispersion_rate: float
class dc4client.receive_data.PowerPlayEndSchema(*, team0: int | None = None, team1: int | None = None)[source]

Bases: BaseModel

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

team0: int | None
team1: int | None
class dc4client.receive_data.ScoreSchema(*, team0: list, team1: list)[source]

Bases: BaseModel

model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

team0: list
team1: list
class dc4client.receive_data.ShotInfoSchema(*, translational_velocity: float, angular_velocity: float, shot_angle: float)[source]

Bases: BaseModel

angular_velocity: float
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

shot_angle: float
translational_velocity: float
class dc4client.receive_data.StateSchema(*, winner_team: str | None, end_number: int, team_shot_number: int | None, total_shot_number: int | None, next_shot_team: str | None, first_team_remaining_time: float, second_team_remaining_time: float, first_team_extra_end_remaining_time: float, second_team_extra_end_remaining_time: float, mixed_doubles_settings: MixedDoublesSettingsSchema | None = None, last_move: ShotInfoSchema | None, stone_coordinate: StoneCoordinateSchema | None = None, score: ScoreSchema | None = None)[source]

Bases: BaseModel

end_number: int
first_team_extra_end_remaining_time: float
first_team_remaining_time: float
last_move: ShotInfoSchema | None
mixed_doubles_settings: MixedDoublesSettingsSchema | None
model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

next_shot_team: str | None
score: ScoreSchema | None
second_team_extra_end_remaining_time: float
second_team_remaining_time: float
stone_coordinate: StoneCoordinateSchema | None
team_shot_number: int | None
total_shot_number: int | None
winner_team: str | None
class dc4client.receive_data.StoneCoordinateSchema(*, data: Dict[str, List[CoordinateDataSchema]])[source]

Bases: BaseModel

data: Dict[str, List[CoordinateDataSchema]]
model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class dc4client.receive_data.TournamentSchema(*, tournament_id: UUID, tournament_name: str)[source]

Bases: BaseModel

model_config = {'from_attributes': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tournament_id: UUID
tournament_name: str
class dc4client.receive_data.TrajectorySchema(*, trajectory_id: UUID, trajectory_data: Json)[source]

Bases: BaseModel

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

trajectory_data: Json
trajectory_id: UUID

dc4client.send_data module

class dc4client.send_data.ClientDataModel(*, game_mode: GameMode = GameMode.standard, tournament: TournamentModel, simulator: PhysicalSimulatorModel, applied_rule: str, time_limit: float, extra_end_time_limit: float, standard_end_count: int, match_name: str, positioned_stones_pattern: int | None = None)[source]

Bases: BaseModel

applied_rule: str
extra_end_time_limit: float
game_mode: GameMode
match_name: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

positioned_stones_pattern: int | None
simulator: PhysicalSimulatorModel
standard_end_count: int
time_limit: float
tournament: TournamentModel
class dc4client.send_data.GameMode(*values)[source]

Bases: str, Enum

mixed_doubles = 'mixed_doubles'
standard = 'standard'
class dc4client.send_data.MatchModel(*, time_limit: int, extra_end_time_limit: int, standard_end_count: int, match_name: str)[source]

Bases: BaseModel

To get match_id from server

extra_end_time_limit: int
match_name: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

standard_end_count: int
time_limit: int
class dc4client.send_data.MatchNameModel(*values)[source]

Bases: str, Enum

team0 = 'team0'
team1 = 'team1'
class dc4client.send_data.MixedDoublesTeamModel(*, use_default_config: bool, team_name: str, match_team_name: MatchNameModel = MatchNameModel.team1, player1: PlayerModel, player2: PlayerModel)[source]

Bases: BaseModel

Team configuration for Mix Doubles.

Note

Current 4-person team config uses player1..player4. Mix Doubles typically uses 2 players, so this model is provided for clients that want to represent that explicitly.

match_team_name: MatchNameModel
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

player1: PlayerModel
player2: PlayerModel
team_name: str
use_default_config: bool
class dc4client.send_data.PhysicalSimulatorModel(*, simulator_name: str)[source]

Bases: BaseModel

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

simulator_name: str
class dc4client.send_data.PlayerModel(*, max_velocity: float, shot_std_dev: float, angle_std_dev: float, player_name: str)[source]

Bases: BaseModel

angle_std_dev: float
max_velocity: float
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

player_name: str
shot_std_dev: float
class dc4client.send_data.PositionedStonesModel(*values)[source]

Bases: str, Enum

center_guard = 'center_guard'
center_house = 'center_house'
pp_left = 'pp_left'
pp_right = 'pp_right'
class dc4client.send_data.ScoreModel(*, first_team_score: List[int], second_team_score: List[int])[source]

Bases: BaseModel

first_team_score: List[int]
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

second_team_score: List[int]
class dc4client.send_data.ShotInfoModel(*, translational_velocity: float, angular_velocity: float | None, shot_angle: float)[source]

Bases: BaseModel

angular_velocity: float | None
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

shot_angle: float
translational_velocity: float
class dc4client.send_data.StateModel(*, end_number: int, team_shot_number: int, total_shot_number: int)[source]

Bases: BaseModel

end_number: int
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

team_shot_number: int
total_shot_number: int
class dc4client.send_data.StoneCoordinates(*, stone_data: Json)[source]

Bases: BaseModel

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

stone_data: Json
class dc4client.send_data.TeamModel(*, use_default_config: bool, team_name: str, match_team_name: MatchNameModel = MatchNameModel.team1, player1: PlayerModel, player2: PlayerModel, player3: PlayerModel | None = None, player4: PlayerModel | None = None)[source]

Bases: BaseModel

match_team_name: MatchNameModel
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

player1: PlayerModel
player2: PlayerModel
player3: PlayerModel | None
player4: PlayerModel | None
team_name: str
use_default_config: bool
class dc4client.send_data.TournamentModel(*, tournament_name: str)[source]

Bases: BaseModel

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tournament_name: str

Module contents