Source code for codingame.clash_of_code.clash_of_code

from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Dict, List, Optional

from ..abc import BaseObject
from ..exceptions import ClashOfCodeError, LoginRequired
from ..http.httperror import HTTPError
from ..types.clash_of_code import ClashOfCode as ClashOfCodeDict
from ..types.clash_of_code import LanguageIds, Mode, Modes
from ..utils import minified_players_to_players, to_datetime
from .player import Player
from .question import Question, TestCaseResult
from .solution import Solution

if TYPE_CHECKING:
    from ..state import ConnectionState

__all__ = ("ClashOfCode",)


[docs]class ClashOfCode(BaseObject): """Represents a Clash of Code. Attributes ----------- public_handle: :class:`str` Public handle of the Clash of Code (hexadecimal str). join_url: :class:`str` URL to join the Clash of Code. public: :class:`bool` Whether the Clash of Code is public. min_players: :class:`int` Minimum number of players. max_players: :class:`int` Maximum number of players. modes: Optional :class:`list` of :class:`str` List of possible modes. programming_languages: Optional :class:`list` of :class:`str` List of possible programming languages. started: :class:`bool` Whether the Clash of Code is started. finished: :class:`bool` Whether the Clash of Code is finished. mode: Optional :class:`str` The mode of the Clash of Code. creation_time: Optional :class:`~datetime.datetime` Creation time of the Clash of Code. Doesn't always exist. start_time: :class:`~datetime.datetime` Start time of the Clash of Code. If the Clash of Code hasn't started yet, this is the expected start time of the Clash of Code. end_time: Optional :class:`~datetime.datetime` End time of the Clash of Code. time_before_start: :class:`~datetime.timedelta` Time before the start of the Clash of Code. time_before_end: Optional :class:`~datetime.timedelta` Time before the end of the Clash of Code. players: :class:`list` of :class:`Player` List of the players in the Clash of Code. """ public_handle: str join_url: str public: bool min_players: int max_players: int modes: Optional[Modes] programming_languages: Optional[LanguageIds] started: bool finished: bool mode: Optional[Mode] creation_time: Optional[datetime] start_time: datetime end_time: Optional[datetime] time_before_start: timedelta time_before_end: Optional[timedelta] players: List["Player"] __slots__ = ( "public_handle", "join_url", "public", "min_players", "max_players", "modes", "programming_languages", "started", "finished", "mode", "creation_time", "start_time", "end_time", "time_before_start", "time_before_end", "players", "_test_session_handle", "_question", ) def __init__(self, state: "ConnectionState", data: ClashOfCodeDict): self._test_session_handle: str = None self._question: Question = None super().__init__(state) self._set_data(data) def _set_data(self, data: ClashOfCodeDict): self._setattr("public_handle", data["publicHandle"]) self._setattr( "join_url", f"https://www.codingame.com/clashofcode/clash/{self.public_handle}", ) self._setattr("public", data.get("type", "PUBLIC") == "PUBLIC") self._setattr("min_players", data["nbPlayersMin"]) self._setattr("max_players", data["nbPlayersMax"]) self._setattr("modes", data.get("modes")) self._setattr("programming_languages", data.get("programmingLanguages")) self._setattr("started", data["started"]) self._setattr("finished", data["finished"]) self._setattr("mode", data.get("mode")) self._setattr("creation_time", to_datetime(data.get("creationTime"))) self._setattr("start_time", to_datetime(data.get("startTimestamp"))) self._setattr("end_time", to_datetime(data.get("endTime"))) self._setattr( "time_before_start", timedelta(milliseconds=data["msBeforeStart"]) ) self._setattr( "time_before_end", ( timedelta(milliseconds=data["msBeforeEnd"]) if "msBeforeEnd" in data else None ), ) self._setattr( "players", [ Player( self._state, self, self.started, self.finished, player, ) for player in data.get("players", []) ] or minified_players_to_players(data.get("minifiedPlayers", [])), ) def __repr__(self) -> str: return ( "<ClashOfCode public_handle={0.public_handle!r} " "public={0.public!r} modes={0.modes!r} " "programming_languages={0.programming_languages!r} " "started={0.started!r} finished={0.finished!r} " "players={0.players!r}>".format(self) )
[docs] def fetch(self): """|maybe_coro| Get and update the information about this Clash Of Code. This modifies this object's own attributes in place. """ if self._state.is_async: async def _fetch(): data = await self._state.http.get_clash_of_code_from_handle( self.public_handle ) self._set_data(data) else: def _fetch(): data = self._state.http.get_clash_of_code_from_handle( self.public_handle ) self._set_data(data) return _fetch()
[docs] def join(self, refetch: bool = False): """|maybe_coro| Join this Clash Of Code. You need to be logged in to join a Clash of Code or else a :exc:`~codingame.LoginRequired` will be raised. Parameters ----------- refetch: :class:`bool` Whether to update this object after joining. Default: `False` Raises ------ :exc:`LoginRequired` The Client needs to log in. See :meth:`Client.login`. """ if not self._state.logged_in: raise LoginRequired() if self._state.is_async: async def _join(): try: await self._state.http.join_clash_of_code_by_handle( self._state.codingamer.id, self.public_handle ) except HTTPError as error: if error.data["id"] in ClashOfCodeError._ids: raise ClashOfCodeError.from_id( error.data["id"], error.data.get("message") ) raise # pragma: no cover if refetch: await self.fetch() else: def _join(): try: self._state.http.join_clash_of_code_by_handle( self._state.codingamer.id, self.public_handle ) except HTTPError as error: if error.data["id"] in ClashOfCodeError._ids: raise ClashOfCodeError.from_id( error.data["id"], error.data.get("message") ) raise # pragma: no cover if refetch: self.fetch() return _join()
[docs] def start(self, refetch: bool = False): """|maybe_coro| Start this Clash Of Code. You need to be logged in as the owner to start a Clash of Code or else a :exc:`~codingame.LoginRequired` will be raised. .. note:: This sets the countdown to the start to 5s. You will need to fetch the Clash Of Code again in 5-10s. Parameters ----------- refetch: :class:`bool` Whether to update this object after starting. Default: `False` Raises ------ :exc:`LoginRequired` The Client needs to log in. See :meth:`Client.login`. """ if not self._state.logged_in: raise LoginRequired() if self._state.is_async: async def _start(): try: await self._state.http.start_clash_of_code_by_handle( self._state.codingamer.id, self.public_handle ) except HTTPError as error: if error.data["id"] in ClashOfCodeError._ids: raise ClashOfCodeError.from_id( error.data["id"], error.data.get("message") ) raise # pragma: no cover if refetch: await self.fetch() else: def _start(): try: self._state.http.start_clash_of_code_by_handle( self._state.codingamer.id, self.public_handle ) except HTTPError as error: if error.data["id"] in ClashOfCodeError._ids: raise ClashOfCodeError.from_id( error.data["id"], error.data.get("message") ) raise # pragma: no cover if refetch: self.fetch() return _start()
[docs] def leave(self, refetch: bool = False): """|maybe_coro| Leave this Clash Of Code. You need to be logged in or else a :exc:`~codingame.LoginRequired` will be raised. Parameters ----------- refetch: :class:`bool` Whether to update this object after leaving. Default: `False` Raises ------ :exc:`LoginRequired` The Client needs to log in. See :meth:`Client.login`. """ if not self._state.logged_in: raise LoginRequired() if self._state.is_async: async def _leave(): try: await self._state.http.leave_clash_of_code_by_handle( self._state.codingamer.id, self.public_handle ) except HTTPError as error: if error.data["id"] in ClashOfCodeError._ids: raise ClashOfCodeError.from_id( error.data["id"], error.data.get("message") ) raise # pragma: no cover if refetch: await self.fetch() else: def _leave(): try: self._state.http.leave_clash_of_code_by_handle( self._state.codingamer.id, self.public_handle ) except HTTPError as error: if error.data["id"] in ClashOfCodeError._ids: raise ClashOfCodeError.from_id( error.data["id"], error.data.get("message") ) raise # pragma: no cover if refetch: self.fetch() return _leave()
[docs] def get_question(self, refetch: bool = False) -> "Question": """|maybe_coro| Get the question for this Clash of Code. You need to be logged in or else a :exc:`~codingame.LoginRequired` will be raised. Parameters ----------- refetch: :class:`bool` Whether to update this object after getting the question. Default: `False` Raises ------ :exc:`LoginRequired` The Client needs to log in. See :meth:`Client.login`. """ if not self._state.logged_in: raise LoginRequired() if self._state.is_async: async def _get_question(): if not self._question: clash_test_session = ( await self._state.http.start_clash_test_session( self._state.codingamer.id, self.public_handle ) ) self._test_session_handle = clash_test_session["handle"] test_session = ( await self._state.http.start_test_session_by_handle( self._test_session_handle ) ) self._question = Question( self._state, self, test_session["currentQuestion"]["question"], ) if refetch: await self.fetch() return self._question else: def _get_question(): if not self._question: clash_test_session = ( self._state.http.start_clash_test_session( self._state.codingamer.id, self.public_handle ) ) self._test_session_handle = clash_test_session["handle"] test_session = ( self._state.http.start_test_session_by_handle( self._test_session_handle ) ) self._question = Question( self._state, self, test_session["currentQuestion"]["question"], ) if refetch: self.fetch() return self._question return _get_question()
[docs] def play_test_cases( self, language_id: str, code: str, indexes: List[int] = None, refetch: bool = False, ) -> Dict[int, TestCaseResult]: """|maybe_coro| Play test cases for this Clash of Code with the given code. You need to be logged in or else a :exc:`~codingame.LoginRequired` will be raised. Parameters ----------- language_id: :class:`str` The language ID of the used programming language. code: :class:`str` The code to test against the test cases. indexes: :class:`list` of :class:`int` The indexes of the test cases to test the code. Default: all test cases refetch: :class:`bool` Whether to update this object after getting the question. Default: `False` Raises ------ :exc:`LoginRequired` The Client needs to log in. See :meth:`Client.login`. """ if not self._state.logged_in: raise LoginRequired() if self._state.is_async: async def _play_test_cases(): if not self._question: await self.get_question() results = {} for test_case in self._question.test_cases: if indexes and test_case.index not in indexes: continue result = await self._state.http.play_test_session_by_handle( self._test_session_handle, language_id, code, test_case.index, ) results[test_case.index] = TestCaseResult( self._state, self, test_case, result ) if refetch: await self.fetch() return results else: def _play_test_cases(): if not self._question: self.get_question() results = {} for test_case in self._question.test_cases: if indexes and test_case.index not in indexes: continue result = self._state.http.play_test_session_by_handle( self._test_session_handle, language_id, code, test_case.index, ) results[test_case.index] = TestCaseResult( self._state, self, test_case, result ) if refetch: self.fetch() return results return _play_test_cases()
[docs] def submit( self, language_id: str, code: str, share: bool = False, refetch: bool = False, ) -> Solution: """|maybe_coro| Submit your solution for this Clash of Code. You need to be logged in or else a :exc:`~codingame.LoginRequired` will be raised. Parameters ----------- language_id: :class:`str` The language ID of the used programming language. code: :class:`str` The code to test against the test cases. share: :class:`bool` Whether to share the solution. Default: `False` refetch: :class:`bool` Whether to update this object after getting the question. Default: `False` Raises ------ :exc:`LoginRequired` The Client needs to log in. See :meth:`Client.login`. """ if not self._state.logged_in: raise LoginRequired() if self._state.is_async: async def _submit(): if not self._question: await self.get_question() solution_id = ( await self._state.http.submit_test_session_by_handle( self._test_session_handle, language_id, code ) ) solution_data = await self._state.http.get_solution_by_id( self._state.codingamer.id, solution_id ) solution = Solution(self._state, self, solution_data) if share: await solution.share() if refetch: await self.fetch() return solution else: def _submit(): if not self._question: self.get_question() solution_id = self._state.http.submit_test_session_by_handle( self._test_session_handle, language_id, code ) solution_data = self._state.http.get_solution_by_id( self._state.codingamer.id, solution_id ) solution = Solution(self._state, self, solution_data) if share: solution.share() if refetch: self.fetch() return solution return _submit()