Skip to content

codingame_tools.client.service.services

services

Async per-service endpoint implementations.

CgAchievementService

CgAchievementService(client)

Bases: CgService

Async Achievement service endpoint.

Source code in codingame_tools/client/service/services/achievement.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Achievement")
    self.helper = CgAchievementServiceHelper(self)

find_by_codingamer_id async

find_by_codingamer_id(codingamer_id=None)

Find the achievements a codingamer has unlocked.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose achievements to list. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/achievement.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
async def find_by_codingamer_id(
            self,
            codingamer_id: int | None = None,
        ) -> list[CgAchievement]:
    """Find the achievements a codingamer has unlocked.

    Args:
        codingamer_id: The codingamer whose achievements to list. If not provided, defaults
                       to the logged-in codingamer's ID.

    Returns:
        A list of CgAchievement objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_achievements = await self.service_request_to_list("findByCodingamerId", [codingamer_id])
    return CgAchievement.from_list(cast(list[JsonDict], raw_achievements))

CgAchievementServiceHelper

CgAchievementServiceHelper(service)

Bases: CgServiceHelper['CgAchievementService']

Helper methods for CgAchievementService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgClashOfCodeService

CgClashOfCodeService(client)

Bases: CgService

Async ClashOfCode service endpoint.

Source code in codingame_tools/client/service/services/clash_of_code.py
24
25
26
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "ClashOfCode")
    self.helper = CgClashOfCodeServiceHelper(self)

get_clash_rank_by_codingamer_id async

get_clash_rank_by_codingamer_id(codingamer_id=None)

Get a codingamer's global Clash of Code ranking.

Returns None if the codingamer has never played Clash of Code--the server responds with a genuine (not an error) JSON null in that case, rather than 404 or an empty dict. This uses service_request (untyped JsonData) rather than service_request_to_dict, since the latter would reject a null response as an error--there would be no way to distinguish "no rank" from an actual failure.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer's numeric ID. If not provided, defaults to the logged-in codingamer's ID.

Returns:

  • CgClashRank | None

    A CgClashRank object, or None if the codingamer has never played Clash of Code.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is neither a dict nor null.

Source code in codingame_tools/client/service/services/clash_of_code.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
async def get_clash_rank_by_codingamer_id(
            self,
            codingamer_id: int | None = None,
        ) -> CgClashRank | None:
    """Get a codingamer's global Clash of Code ranking.

       Returns None if the codingamer has never played Clash of Code--the server responds
       with a genuine (not an error) JSON `null` in that case, rather than 404 or an empty
       dict. This uses `service_request` (untyped `JsonData`) rather than
       `service_request_to_dict`, since the latter would reject a `null` response as an
       error--there would be no way to distinguish "no rank" from an actual failure.

    Args:
        codingamer_id: The codingamer's numeric ID. If not provided, defaults to the
                       logged-in codingamer's ID.

    Returns:
        A CgClashRank object, or None if the codingamer has never played Clash of Code.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is neither a dict nor null.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_rank = await self.service_request(
            "getClashRankByCodinGamerId", [codingamer_id])
    if raw_rank is None:
        return None
    if not isinstance(raw_rank, dict):
        raise CgClientHttpError(
                f"Invalid response type: expected a JSON dictionary or null, got {type(raw_rank).__name__}",
                content=raw_rank,
            )
    return CgClashRank.from_dict(raw_rank)

find_clash_by_handle async

find_clash_by_handle(handle)

Find a Clash of Code session by its handle.

handle must be a clash-instance handle (e.g. a CgClashSlot.clash_handle from FeaturedEvent/findClashSlots)--confirmed empirically, neither a codingamer's public handle nor the parent CgFeaturedEvent.handle are accepted here (both rejected with a 422).

Parameters:

  • handle (str) –

    The opaque clash-instance handle string.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/clash_of_code.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
async def find_clash_by_handle(
            self,
            handle: str,
        ) -> CgClash:
    """Find a Clash of Code session by its handle.

       `handle` must be a clash-instance handle (e.g. a `CgClashSlot.clash_handle` from
       FeaturedEvent/findClashSlots)--confirmed empirically, neither a codingamer's public
       handle nor the parent `CgFeaturedEvent.handle` are accepted here (both rejected with
       a 422).

    Args:
        handle: The opaque clash-instance handle string.

    Returns:
        A CgClash object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_clash = await self.service_request_to_dict("findClashByHandle", [handle])
    return CgClash.from_dict(raw_clash)

CgClashOfCodeServiceHelper

CgClashOfCodeServiceHelper(service)

Bases: CgServiceHelper['CgClashOfCodeService']

Helper methods for CgClashOfCodeService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgClashOfCodeDescriptionService

CgClashOfCodeDescriptionService(client)

Bases: CgService

Async ClashOfCodeDescription service endpoint.

Source code in codingame_tools/client/service/services/clash_of_code_description.py
23
24
25
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "ClashOfCodeDescription")
    self.helper = CgClashOfCodeDescriptionServiceHelper(self)

get_clash_description async

get_clash_description()

Get localized help/explainer content for Clash of Code.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/clash_of_code_description.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
async def get_clash_description(self) -> CgClashDescription:
    """Get localized help/explainer content for Clash of Code.

    Returns:
        A CgClashDescription object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_description = await self.service_request_to_dict("getClashDescription")
    return CgClashDescription.from_dict(raw_description)

CgClashOfCodeDescriptionServiceHelper

CgClashOfCodeDescriptionServiceHelper(service)

Bases: CgServiceHelper['CgClashOfCodeDescriptionService']

Helper methods for CgClashOfCodeDescriptionService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgCodingamerService

CgCodingamerService(client)

Bases: CgService

Async Codingamer service endpoint.

Source code in codingame_tools/client/service/services/codingamer.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "CodinGamer")
    self.helper = CgCodingamerServiceHelper(self)

find_codingame_points_stats_by_handle async

find_codingame_points_stats_by_handle(handle)

Find a codingamer's points/ranking stats by their opaque public handle.

Parameters:

  • handle (str) –

    The codingamer's opaque public handle string (not their numeric ID).

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/codingamer.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
async def find_codingame_points_stats_by_handle(
            self,
            handle: str,
        ) -> CgCodingamePointsStats:
    """Find a codingamer's points/ranking stats by their opaque public handle.

    Args:
        handle: The codingamer's opaque public handle string (not their numeric ID).

    Returns:
        A CgCodingamePointsStats object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_stats = await self.service_request_to_dict(
            "findCodingamePointsStatsByHandle", [handle])
    return CgCodingamePointsStats.from_dict(raw_stats)

find_codingamer_public_informations async

find_codingamer_public_informations(codingamer_id=None)

Find a codingamer's public profile information by their numeric ID.

This is a genuinely public endpoint--no login is required when codingamer_id is explicitly provided. A login is only required to resolve the default codingamer_id when one is not provided.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer's numeric ID. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/codingamer.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
async def find_codingamer_public_informations(
            self,
            codingamer_id: int | None = None,
        ) -> CgCodingamer:
    """Find a codingamer's public profile information by their numeric ID.

       This is a genuinely public endpoint--no login is required when `codingamer_id` is
       explicitly provided. A login is only required to resolve the default
       `codingamer_id` when one is not provided.

    Args:
        codingamer_id: The codingamer's numeric ID. If not provided, defaults to the
                       logged-in codingamer's ID.

    Returns:
        A CgCodingamer object.

    Raises:
        CgAuthenticationError:
            If `codingamer_id` is not provided and no codingamer ID can be resolved from
            the session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_codingamer = await self.service_request_to_dict(
            "findCodinGamerPublicInformations", [codingamer_id], require_login=False)
    return CgCodingamer.from_dict(raw_codingamer)

find_followers async

find_followers(codingamer_id=None, current_codingamer_id=None, arg3=None)

Find the followers of a codingamer.

Empirically, current_codingamer_id is not a free "viewpoint" parameter: the server rejects the call with a 422 unless it equals the logged-in codingamer's own ID, even when codingamer_id refers to a different codingamer. It appears to exist purely so the server can compute is_follower/is_following on each result relative to the logged-in codingamer, rather than relative to codingamer_id.

arg3's purpose is unknown. Passing a scalar (int, str, bool) causes a 422; only None and {} have been observed to succeed--possibly reserved for future pagination/filtering parameters.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose followers to list. Defaults to the logged-in codingamer's ID.

  • current_codingamer_id (int | None, default: None ) –

    Must equal the logged-in codingamer's ID (server-enforced; see above). Defaults to the logged-in codingamer's ID.

  • arg3 (dict[str, Any] | None, default: None ) –

    Third positional argument to the underlying findFollowers API call. Purpose unknown; defaults to None.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if either ID is not provided and cannot be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/codingamer.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
async def find_followers(
            self,
            codingamer_id: int | None = None,
            current_codingamer_id: int | None = None,
            arg3: dict[str, Any] | None = None,
        ) -> list[CgCodingamerFollower]:
    """Find the followers of a codingamer.

       Empirically, `current_codingamer_id` is not a free "viewpoint" parameter: the server
       rejects the call with a 422 unless it equals the logged-in codingamer's own ID, even
       when `codingamer_id` refers to a different codingamer. It appears to exist purely so
       the server can compute `is_follower`/`is_following` on each result relative to the
       logged-in codingamer, rather than relative to `codingamer_id`.

       `arg3`'s purpose is unknown. Passing a scalar (int, str, bool) causes a 422; only
       `None` and `{}` have been observed to succeed--possibly reserved for future
       pagination/filtering parameters.

    Args:
        codingamer_id: The codingamer whose followers to list. Defaults to the logged-in
                       codingamer's ID.
        current_codingamer_id: Must equal the logged-in codingamer's ID (server-enforced;
                       see above). Defaults to the logged-in codingamer's ID.
        arg3:          Third positional argument to the underlying findFollowers API call.
                       Purpose unknown; defaults to None.

    Returns:
        A list of CgCodingamerFollower objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if either ID
            is not provided and cannot be resolved from the session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    await self.require_authenticate()
    own_id = self.client.codingamer_id
    if codingamer_id is None:
        codingamer_id = own_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    if current_codingamer_id is None:
        current_codingamer_id = own_id
        if current_codingamer_id is None:
            raise CgAuthenticationError()
    raw_followers = await self.service_request_to_list(
            "findFollowers", [codingamer_id, current_codingamer_id, arg3])
    return CgCodingamerFollower.from_list(cast(list[JsonDict], raw_followers))

find_following async

find_following(codingamer_id=None, current_codingamer_id=None)

Find the codingamers that a codingamer is following.

Same codingamer_id/current_codingamer_id semantics as find_followers (see its docstring)--current_codingamer_id must equal the logged-in codingamer's own ID, and serves only to compute is_follower/is_following from the logged-in codingamer's perspective. Unlike find_followers, there is no third (unknown) argument.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose followees to list. Defaults to the logged-in codingamer's ID.

  • current_codingamer_id (int | None, default: None ) –

    Must equal the logged-in codingamer's ID (server-enforced). Defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if either ID is not provided and cannot be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/codingamer.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
async def find_following(
            self,
            codingamer_id: int | None = None,
            current_codingamer_id: int | None = None,
        ) -> list[CgCodingamerFollower]:
    """Find the codingamers that a codingamer is following.

       Same `codingamer_id`/`current_codingamer_id` semantics as `find_followers` (see its
       docstring)--`current_codingamer_id` must equal the logged-in codingamer's own ID, and
       serves only to compute `is_follower`/`is_following` from the logged-in codingamer's
       perspective. Unlike `find_followers`, there is no third (unknown) argument.

    Args:
        codingamer_id: The codingamer whose followees to list. Defaults to the logged-in
                       codingamer's ID.
        current_codingamer_id: Must equal the logged-in codingamer's ID (server-enforced).
                       Defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgCodingamerFollower objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if either ID
            is not provided and cannot be resolved from the session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    await self.require_authenticate()
    own_id = self.client.codingamer_id
    if codingamer_id is None:
        codingamer_id = own_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    if current_codingamer_id is None:
        current_codingamer_id = own_id
        if current_codingamer_id is None:
            raise CgAuthenticationError()
    raw_following = await self.service_request_to_list(
            "findFollowing", [codingamer_id, current_codingamer_id])
    return CgCodingamerFollower.from_list(cast(list[JsonDict], raw_following))

find_codingamer_follow_card async

find_codingamer_follow_card(codingamer_id=None, current_codingamer_id=None)

Find a codingamer's follow-card summary--their public profile plus follow-relationship flags relative to another codingamer.

Same codingamer_id/current_codingamer_id semantics as find_followers (see its docstring)--current_codingamer_id must equal the logged-in codingamer's own ID (server-enforced with a 422 otherwise); it serves only to compute is_follower/is_following from the logged-in codingamer's perspective. The response shape is identical to a single entry of find_followers/find_following.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose follow card to fetch. Defaults to the logged-in codingamer's ID.

  • current_codingamer_id (int | None, default: None ) –

    Must equal the logged-in codingamer's ID (server-enforced). Defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if either ID is not provided and cannot be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/codingamer.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
async def find_codingamer_follow_card(
            self,
            codingamer_id: int | None = None,
            current_codingamer_id: int | None = None,
        ) -> CgCodingamerFollower:
    """Find a codingamer's follow-card summary--their public profile plus
       follow-relationship flags relative to another codingamer.

       Same `codingamer_id`/`current_codingamer_id` semantics as `find_followers` (see its
       docstring)--`current_codingamer_id` must equal the logged-in codingamer's own ID
       (server-enforced with a 422 otherwise); it serves only to compute
       `is_follower`/`is_following` from the logged-in codingamer's perspective. The response
       shape is identical to a single entry of `find_followers`/`find_following`.

    Args:
        codingamer_id: The codingamer whose follow card to fetch. Defaults to the logged-in
                       codingamer's ID.
        current_codingamer_id: Must equal the logged-in codingamer's ID (server-enforced).
                       Defaults to the logged-in codingamer's ID.

    Returns:
        A CgCodingamerFollower object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if either ID
            is not provided and cannot be resolved from the session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    await self.require_authenticate()
    own_id = self.client.codingamer_id
    if codingamer_id is None:
        codingamer_id = own_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    if current_codingamer_id is None:
        current_codingamer_id = own_id
        if current_codingamer_id is None:
            raise CgAuthenticationError()
    raw_card = await self.service_request_to_dict(
            "findCodingamerFollowCard", [codingamer_id, current_codingamer_id])
    return CgCodingamerFollower.from_dict(raw_card)

find_follower_ids async

find_follower_ids(codingamer_id=None)

Find the numeric IDs of a codingamer's followers.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose follower IDs to list. Defaults to the logged-in codingamer's ID.

Returns:

  • list[int]

    A list of numeric codingamer IDs.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/codingamer.py
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
async def find_follower_ids(
            self,
            codingamer_id: int | None = None,
        ) -> list[int]:
    """Find the numeric IDs of a codingamer's followers.

    Args:
        codingamer_id: The codingamer whose follower IDs to list. Defaults to the logged-in
                       codingamer's ID.

    Returns:
        A list of numeric codingamer IDs.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_ids = await self.service_request_to_list("findFollowerIds", [codingamer_id])
    return cast(list[int], raw_ids)

find_following_ids async

find_following_ids(codingamer_id=None)

Find the numeric IDs of the codingamers that a codingamer is following.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose followee IDs to list. Defaults to the logged-in codingamer's ID.

Returns:

  • list[int]

    A list of numeric codingamer IDs.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/codingamer.py
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
async def find_following_ids(
            self,
            codingamer_id: int | None = None,
        ) -> list[int]:
    """Find the numeric IDs of the codingamers that a codingamer is following.

    Args:
        codingamer_id: The codingamer whose followee IDs to list. Defaults to the logged-in
                       codingamer's ID.

    Returns:
        A list of numeric codingamer IDs.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_ids = await self.service_request_to_list("findFollowingIds", [codingamer_id])
    return cast(list[int], raw_ids)

CgCodingamerServiceHelper

CgCodingamerServiceHelper(service)

Bases: CgServiceHelper['CgCodingamerService']

Helper methods for CgCodingamerService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgCodingamerPuzzleTopicService

CgCodingamerPuzzleTopicService(client)

Bases: CgService

Async CodingamerPuzzleTopic service endpoint.

Source code in codingame_tools/client/service/services/codingamer_puzzle_topic.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "CodingamerPuzzleTopic")
    self.helper = CgCodingamerPuzzleTopicServiceHelper(self)

find_topics_by_codingamer_id async

find_topics_by_codingamer_id(codingamer_id=None)

Find the puzzle topics a codingamer has made progress on (e.g. "Arrays", "BFS"), along with a per-topic puzzle count and last-progress timestamp.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose puzzle topic progress to list. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/codingamer_puzzle_topic.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
async def find_topics_by_codingamer_id(
            self,
            codingamer_id: int | None = None,
        ) -> list[CgCodingamerPuzzleTopic]:
    """Find the puzzle topics a codingamer has made progress on (e.g. "Arrays", "BFS"),
       along with a per-topic puzzle count and last-progress timestamp.

    Args:
        codingamer_id: The codingamer whose puzzle topic progress to list. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgCodingamerPuzzleTopic objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_topics = await self.service_request_to_list(
            "findTopicsByCodingamerId", [codingamer_id])
    return CgCodingamerPuzzleTopic.from_list(cast(list[JsonDict], raw_topics))

select_topics_by_codingamer_id_and_puzzle_id async

select_topics_by_codingamer_id_and_puzzle_id(puzzle_id, codingamer_id=None)

Find the topic tree for a single puzzle, personalized with the codingamer's per-topic "learned" status.

Parameters:

  • puzzle_id (int) –

    Numeric ID of the puzzle.

  • codingamer_id (int | None, default: None ) –

    The codingamer whose topic mastery to check. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/codingamer_puzzle_topic.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
async def select_topics_by_codingamer_id_and_puzzle_id(
            self,
            puzzle_id: int,
            codingamer_id: int | None = None,
        ) -> list[CgCodingamerTopicNode]:
    """Find the topic tree for a single puzzle, personalized with the codingamer's
       per-topic "learned" status.

    Args:
        puzzle_id:     Numeric ID of the puzzle.
        codingamer_id: The codingamer whose topic mastery to check. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgCodingamerTopicNode objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_topics = await self.service_request_to_list(
            "selectTopicsByCodingamerIdAndPuzzleId", [codingamer_id, puzzle_id])
    return CgCodingamerTopicNode.from_list(cast(list[JsonDict], raw_topics))

CgCodingamerPuzzleTopicServiceHelper

CgCodingamerPuzzleTopicServiceHelper(service)

Bases: CgServiceHelper['CgCodingamerPuzzleTopicService']

Helper methods for CgCodingamerPuzzleTopicService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgContributionService

CgContributionService(client)

Bases: CgService

Async Contribution service endpoint.

Source code in codingame_tools/client/service/services/contribution.py
215
216
217
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Contribution")
    self.helper = CgContributionServiceHelper(self)

find_contribution async

find_contribution(contribution_id, arg2=True)

Find a contribution by its opaque contribution ID.

Parameters:

  • contribution_id (str) –

    The opaque contribution ID string (see CgContributionId).

  • arg2 (bool, default: True ) –

    Second positional argument to the underlying findContribution API call. Purpose unknown; defaults to True.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/contribution.py
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
async def find_contribution(
            self,
            contribution_id: str,
            arg2: bool = True,
        ) -> CgContribution:
    """Find a contribution by its opaque contribution ID.

    Args:
        contribution_id: The opaque contribution ID string (see `CgContributionId`).
        arg2:            Second positional argument to the underlying findContribution API
                          call. Purpose unknown; defaults to True.

    Returns:
        A CgContribution object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_contribution = await self.service_request_to_dict(
            "findContribution", [contribution_id, arg2])
    return CgContribution.from_dict(raw_contribution)

find_new_contribution_count async

find_new_contribution_count(codingamer_id=None, since=None)

Count new contributions (e.g. community puzzles) published since a given point in time, for a given codingamer.

since is sent to the server as a bare epoch-millis integer, like every other epoch-millis argument in this API (including FeaturedEvent/findNewFeaturedEventCount, where CodinGame's own web client sends a quoted string but a bare int was confirmed to work equally well--see CgFeaturedEventService.find_new_featured_event_count).

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer to count new contributions for. If not provided, defaults to the logged-in codingamer's ID.

  • since (datetime | None, default: None ) –

    Count contributions published after this point in time. If not provided, defaults to now (which will always yield 0--callers interested in a nonzero count should track their own reference point, e.g. the last time they called this). Naive datetimes are interpreted as local time (matching Python's own datetime.timestamp() behavior).

Returns:

  • int

    The number of new contributions published since since.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not an int.

Source code in codingame_tools/client/service/services/contribution.py
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
async def find_new_contribution_count(
            self,
            codingamer_id: int | None = None,
            since: datetime | None = None,
        ) -> int:
    """Count new contributions (e.g. community puzzles) published since a given point in
       time, for a given codingamer.

       `since` is sent to the server as a bare epoch-millis integer, like every other
       epoch-millis argument in this API (including FeaturedEvent/findNewFeaturedEventCount,
       where CodinGame's own web client sends a quoted string but a bare int was confirmed
       to work equally well--see `CgFeaturedEventService.find_new_featured_event_count`).

    Args:
        codingamer_id: The codingamer to count new contributions for. If not provided,
                       defaults to the logged-in codingamer's ID.
        since:         Count contributions published after this point in time. If not
                       provided, defaults to now (which will always yield 0--callers
                       interested in a nonzero count should track their own reference
                       point, e.g. the last time they called this). Naive datetimes are
                       interpreted as local time (matching Python's own
                       `datetime.timestamp()` behavior).

    Returns:
        The number of new contributions published since `since`.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not an int.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    if since is None:
        since = datetime.now(timezone.utc)
    since_ms = int(since.timestamp() * 1000)
    result = await self.service_request("findNewContributionCount", [codingamer_id, since_ms])
    return cast(int, result)

find_contribution_moderators async

find_contribution_moderators(contribution_numeric_id, action)

List the moderators who have cast a given vote on a PENDING contribution's approve/reject moderation gate--the privileged (moderator/high-level-codingamer-only) mechanism that actually decides whether a contribution gets published or rejected, confirmed live to require 3 "validate" votes to approve or 3 "deny" votes to reject. Entirely distinct from the ungated community up/down vote (CgContribution. up_votes/down_votes, Vote/findVotableValuesById)--do not conflate the two.

The required threshold (3, either way) is not itself part of this response--only the current list of moderators on the requested side. Call this twice (once per action) to get both sides' current tallies (len(result)) and named voters.

Parameters:

  • contribution_numeric_id (int) –

    The contribution's numeric ID (CgContribution.id)--NOT the opaque public_handle/CgContributionId string used by every other method on this service (find_contribution/ update_contribution/etc.). Confirmed live: passing the numeric id (e.g. 149373) works; the opaque handle was not tried here and is not expected to.

  • action (CgModerationAction) –

    "validate" (approve) or "deny" (reject)--see CgModerationAction.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/contribution.py
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
async def find_contribution_moderators(
            self,
            contribution_numeric_id: int,
            action: CgModerationAction,
        ) -> list[CgContributionModerator]:
    """List the moderators who have cast a given vote on a PENDING contribution's
       approve/reject moderation gate--the privileged (moderator/high-level-codingamer-only)
       mechanism that actually decides whether a contribution gets published or rejected,
       confirmed live to require 3 `"validate"` votes to approve or 3 `"deny"` votes to
       reject. Entirely distinct from the ungated community up/down vote (`CgContribution.
       up_votes`/`down_votes`, `Vote/findVotableValuesById`)--do not conflate the two.

       The required threshold (3, either way) is not itself part of this response--only the
       current list of moderators on the requested side. Call this twice (once per `action`)
       to get both sides' current tallies (`len(result)`) and named voters.

    Args:
        contribution_numeric_id: The contribution's *numeric* ID (`CgContribution.id`)--NOT
                                  the opaque `public_handle`/`CgContributionId` string used
                                  by every other method on this service (`find_contribution`/
                                  `update_contribution`/etc.). Confirmed live: passing the
                                  numeric `id` (e.g. `149373`) works; the opaque handle was
                                  not tried here and is not expected to.
        action:                  `"validate"` (approve) or `"deny"` (reject)--see
                                  `CgModerationAction`.

    Returns:
        A list of CgContributionModerator objects--one per moderator who has cast that vote.
        Empty if nobody has voted that way yet.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    raw_moderators = await self.service_request_to_list(
            "findContributionModerators", [contribution_numeric_id, action])
    return CgContributionModerator.from_list(cast(list[JsonDict], raw_moderators))

get_all_pending_contributions async

get_all_pending_contributions(contribution_type_filter='ALL', codingamer_id=None, page=1)

Get pending (community-review-queue) contributions.

Raw argument order is [page, contribution_type_filter, codingamer_id]; this method reorders them to put the more commonly-varied contribution_type_filter first.

codingamer_id must equal the logged-in codingamer's own ID--the server rejects any other value with a 403 (UserRequired: Only a logged user is authorized to perform this operation), confirmed empirically. It does NOT filter results to contributions authored by that codingamer (a single call returned contributions from 30 different authors)--it's presumably used to compute per-item context (e.g. CgPendingContribution.user_moderation_status) relative to the viewer, similar to current_codingamer_id on CgCodingamerService.find_followers.

contribution_type_filter accepts coarse category values, confirmed empirically: "ALL" (every type), "CLASHOFCODE" (only Clash of Code), "PUZZLE" (every puzzle subtype--"PUZZLE_INOUT", "PUZZLE_OPTI", "PUZZLE_SOLO", "PUZZLE_MULTI--but not "CLASHOFCODE"). An unrecognized value (e.g. one of the specific type values itself, like "PUZZLE_INOUT") does not filter or error--it behaves like "ALL".

page is assumed to be a 1-indexed page number, but this is not fully confirmed: page=1 returned all 57 currently-pending contributions in one call; page=0 caused a 500 Internal Server Error; every page >= 2 tried returned an empty list. That's consistent with simple pagination where all current matches fit on page 1, but true multi-page behavior (page size, etc.) has never been observed.

Parameters:

  • contribution_type_filter (str, default: 'ALL' ) –

    Category filter; see above. Defaults to "ALL".

  • codingamer_id (int | None, default: None ) –

    Must equal the logged-in codingamer's own ID (server-enforced; see above). If not provided, defaults to the logged-in codingamer's ID.

  • page (int, default: 1 ) –

    Assumed 1-indexed page number; see above. Defaults to 1.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx (e.g. 403 if codingamer_id is not your own, or 500 if page is 0), or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/contribution.py
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
async def get_all_pending_contributions(
            self,
            contribution_type_filter: str = "ALL",
            codingamer_id: int | None = None,
            page: int = 1,
        ) -> list[CgPendingContribution]:
    """Get pending (community-review-queue) contributions.

       Raw argument order is `[page, contribution_type_filter, codingamer_id]`; this method
       reorders them to put the more commonly-varied `contribution_type_filter` first.

       `codingamer_id` must equal the logged-in codingamer's own ID--the server rejects any
       other value with a 403 (`UserRequired: Only a logged user is authorized to perform
       this operation`), confirmed empirically. It does NOT filter results to contributions
       authored by that codingamer (a single call returned contributions from 30 different
       authors)--it's presumably used to compute per-item context (e.g.
       `CgPendingContribution.user_moderation_status`) relative to the viewer, similar to
       `current_codingamer_id` on `CgCodingamerService.find_followers`.

       `contribution_type_filter` accepts coarse category values, confirmed empirically:
       "ALL" (every type), "CLASHOFCODE" (only Clash of Code), "PUZZLE" (every puzzle
       subtype--"PUZZLE_INOUT", "PUZZLE_OPTI", "PUZZLE_SOLO", "PUZZLE_MULTI--but not
       "CLASHOFCODE"). An unrecognized value (e.g. one of the specific `type` values itself,
       like "PUZZLE_INOUT") does not filter or error--it behaves like "ALL".

       `page` is assumed to be a 1-indexed page number, but this is not fully confirmed:
       `page=1` returned all 57 currently-pending contributions in one call; `page=0` caused
       a 500 Internal Server Error; every `page >= 2` tried returned an empty list. That's
       consistent with simple pagination where all current matches fit on page 1, but true
       multi-page behavior (page size, etc.) has never been observed.

    Args:
        contribution_type_filter: Category filter; see above. Defaults to "ALL".
        codingamer_id: Must equal the logged-in codingamer's own ID (server-enforced; see
                       above). If not provided, defaults to the logged-in codingamer's ID.
        page:          Assumed 1-indexed page number; see above. Defaults to 1.

    Returns:
        A list of CgPendingContribution objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx (e.g. 403 if `codingamer_id` is not your own, or
            500 if `page` is 0), or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_contributions = await self.service_request_to_list(
            "getAllPendingContributions", [page, contribution_type_filter, codingamer_id])
    return CgPendingContribution.from_list(cast(list[JsonDict], raw_contributions))

get_personal_contributions async

get_personal_contributions(codingamer_id=None, page=1)

List every contribution (any status--draft, PENDING, APPROVED, REFUSED, etc.) authored by a codingamer, e.g. for a "my contributions" listing page. Unlike get_all_pending_contributions's codingamer_id, this one genuinely filters to just that codingamer's own contributions.

codingamer_id must equal the logged-in codingamer's own ID--confirmed live that both an arbitrary ID (1) and a real, different codingamer's ID are rejected with a 422 (no distinguishing error detail between the two cases); page is a real 1-indexed page number--confirmed live via the server's own error detail (page=0 -> 422 INVALID_PAGE: Page must be at least 1, unlike get_all_pending_contributions's page, which merely 500s on 0 with no detail)--page values beyond the last page return [] rather than erroring.

Parameters:

  • codingamer_id (int | None, default: None ) –

    Must equal the logged-in codingamer's own ID (server-enforced; see above). If not provided, defaults to the logged-in codingamer's ID.

  • page (int, default: 1 ) –

    1-indexed page number; see above. Defaults to 1.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx (e.g. 422 if codingamer_id isn't your own, or if page is less than 1), or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/contribution.py
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
async def get_personal_contributions(
            self,
            codingamer_id: int | None = None,
            page: int = 1,
        ) -> list[CgPersonalContribution]:
    """List every contribution (any status--draft, PENDING, APPROVED, REFUSED, etc.)
       authored by a codingamer, e.g. for a "my contributions" listing page. Unlike
       `get_all_pending_contributions`'s `codingamer_id`, this one genuinely filters to just
       that codingamer's own contributions.

       `codingamer_id` must equal the logged-in codingamer's own ID--confirmed live that both
       an arbitrary ID (`1`) and a real, different codingamer's ID are rejected with a 422
       (no distinguishing error detail between the two cases); `page` is a real 1-indexed
       page number--confirmed live via the server's own error detail (`page=0` -> 422
       `INVALID_PAGE: Page must be at least 1`, unlike `get_all_pending_contributions`'s
       `page`, which merely 500s on `0` with no detail)--`page` values beyond the last page
       return `[]` rather than erroring.

    Args:
        codingamer_id: Must equal the logged-in codingamer's own ID (server-enforced; see
                       above). If not provided, defaults to the logged-in codingamer's ID.
        page:          1-indexed page number; see above. Defaults to 1.

    Returns:
        A list of CgPersonalContribution objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx (e.g. 422 if `codingamer_id` isn't your own, or if
            `page` is less than 1), or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_contributions = await self.service_request_to_list(
            "getPersonalContributions", [codingamer_id, page])
    return CgPersonalContribution.from_list(cast(list[JsonDict], raw_contributions))

update_contribution async

update_contribution(contribution_id, puzzle_type, contribution_data, draft, ready_for_moderation, prev_version, codingamer_id=None)

Submit a new version of a contribution's content.

A thin wrapper over the raw API--no retries and no normalization of contribution_data are performed here. The server re-validates the full contribution (running all local and server-side validator test cases) on every call, though it is reportedly smart enough to skip re-running test cases whose content hasn't changed. For a contribution with many/heavy test cases, this re-validation can take long enough that Cloudflare's edge disconnects the request (surfacing as an CgClientHttpError with status_code == 524) even though the origin request eventually completes successfully server-side. See CgContributionServiceHelper.update_contribution (self.helper.update_contribution) for a version that layers retry/polling on top of this method.

Parameters:

  • contribution_id (CgContributionId) –

    The opaque contribution ID (see CgContributionId).

  • puzzle_type (CgPuzzleType) –

    The type of the contribution, e.g. "PUZZLE_INOUT".

  • contribution_data (CgContributionData) –

    The new contribution content, typically obtained by mutating the CgContributionData returned by find_contribution.

  • draft (bool) –

    Whether this version is a private, unpublished draft.

  • ready_for_moderation (bool) –

    Whether the contribution is being formally submitted for moderation (requiring 3 moderator upvotes and fewer than 3 downvotes before the moderation window expires).

  • prev_version (int) –

    The version number of the contribution as last retrieved via find_contribution (CgContribution.last_version.version). Serves as an idempotency/concurrency check--the server rejects the update if this doesn't match its current version.

  • codingamer_id (int | None, default: None ) –

    The authoring codingamer's numeric ID. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx (e.g. if prev_version is stale, or 524 if Cloudflare's edge disconnects while the origin is still validating--see above), or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/contribution.py
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
async def update_contribution(
            self,
            contribution_id: CgContributionId,
            puzzle_type: CgPuzzleType,
            contribution_data: CgContributionData,
            draft: bool,
            ready_for_moderation: bool,
            prev_version: int,
            codingamer_id: int | None = None,
        ) -> CgContribution:
    """Submit a new version of a contribution's content.

       A thin wrapper over the raw API--no retries and no normalization of
       `contribution_data` are performed here. The server re-validates the full contribution
       (running all local and server-side validator test cases) on every call, though it is
       reportedly smart enough to skip re-running test cases whose content hasn't changed.
       For a contribution with many/heavy test cases, this re-validation can take long enough
       that Cloudflare's edge disconnects the request (surfacing as an
       `CgClientHttpError` with `status_code == 524`) even though the origin request
       eventually completes successfully server-side. See
       `CgContributionServiceHelper.update_contribution` (`self.helper.update_contribution`)
       for a version that layers retry/polling on top of this method.

    Args:
        contribution_id:      The opaque contribution ID (see `CgContributionId`).
        puzzle_type:          The type of the contribution, e.g. "PUZZLE_INOUT".
        contribution_data:    The new contribution content, typically obtained by mutating
                              the `CgContributionData` returned by `find_contribution`.
        draft:                Whether this version is a private, unpublished draft.
        ready_for_moderation: Whether the contribution is being formally submitted for
                              moderation (requiring 3 moderator upvotes and fewer than 3
                              downvotes before the moderation window expires).
        prev_version:         The version number of the contribution as last retrieved via
                              `find_contribution` (`CgContribution.last_version.version`).
                              Serves as an idempotency/concurrency check--the server rejects
                              the update if this doesn't match its current version.
        codingamer_id:        The authoring codingamer's numeric ID. If not provided,
                              defaults to the logged-in codingamer's ID.

    Returns:
        The updated CgContribution.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx (e.g. if `prev_version` is stale, or 524 if
            Cloudflare's edge disconnects while the origin is still validating--see above), or
            if the decoded content is not a dict.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_result = await self.service_request_to_dict(
            "updateContribution",
            [
                    codingamer_id,
                    contribution_id,
                    puzzle_type,
                    contribution_data.to_dict(),
                    draft,
                    ready_for_moderation,
                    prev_version,
                ])
    return CgContribution.from_dict(raw_result)

create_contribution async

create_contribution(puzzle_type, contribution_data, draft, ready_for_moderation, codingamer_id=None)

Create a brand new contribution.

A thin wrapper over the raw API--no retries are performed here (see CgContributionServiceHelper.create_contribution, self.helper.create_contribution, which deliberately doesn't add 524 retry either; see that method's docstring for why). No layer here normalizes contribution_data. Argument order/shape mirrors update_contribution, minus contribution_id/ prev_version (there's no existing contribution yet, and thus nothing to reference).

The response is just the new contribution's opaque public handle (a bare JSON string), unlike update_contribution's full CgContribution--call find_contribution(handle) afterward for the rest (e.g. id, last_version).

Parameters:

  • puzzle_type (CgPuzzleType) –

    The type of the contribution, e.g. "PUZZLE_INOUT".

  • contribution_data (CgContributionData) –

    The new contribution's initial content.

  • draft (bool) –

    Whether this version is a private, unpublished draft.

  • ready_for_moderation (bool) –

    Whether the contribution is being formally submitted for moderation (requiring 3 moderator upvotes and fewer than 3 downvotes before the moderation window expires).

  • codingamer_id (int | None, default: None ) –

    The authoring codingamer's numeric ID. If not provided, defaults to the logged-in codingamer's ID.

Returns:

  • CgContributionId

    The new contribution's opaque public handle (CgContributionId).

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a str.

Source code in codingame_tools/client/service/services/contribution.py
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
async def create_contribution(
            self,
            puzzle_type: CgPuzzleType,
            contribution_data: CgContributionData,
            draft: bool,
            ready_for_moderation: bool,
            codingamer_id: int | None = None,
        ) -> CgContributionId:
    """Create a brand new contribution.

       A thin wrapper over the raw API--no retries are performed here (see
       `CgContributionServiceHelper.create_contribution`, `self.helper.create_contribution`,
       which deliberately doesn't add 524 retry either; see that method's docstring for why).
       No layer here normalizes `contribution_data`.
       Argument order/shape mirrors `update_contribution`, minus `contribution_id`/
       `prev_version` (there's no existing contribution yet, and thus nothing to reference).

       The response is just the new contribution's opaque public handle (a bare JSON string),
       unlike `update_contribution`'s full `CgContribution`--call `find_contribution(handle)`
       afterward for the rest (e.g. `id`, `last_version`).

    Args:
        puzzle_type:          The type of the contribution, e.g. "PUZZLE_INOUT".
        contribution_data:    The new contribution's initial content.
        draft:                Whether this version is a private, unpublished draft.
        ready_for_moderation: Whether the contribution is being formally submitted for
                              moderation (requiring 3 moderator upvotes and fewer than 3
                              downvotes before the moderation window expires).
        codingamer_id:        The authoring codingamer's numeric ID. If not provided,
                              defaults to the logged-in codingamer's ID.

    Returns:
        The new contribution's opaque public handle (`CgContributionId`).

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a str.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_result = await self.service_request(
            "createContribution",
            [codingamer_id, puzzle_type, contribution_data.to_dict(), draft, ready_for_moderation])
    return cast(str, raw_result)

delete_contribution async

delete_contribution(contribution_id, codingamer_id=None)

Delete a contribution.

Argument shape ([codingamerId, contributionId]), by analogy with update_contribution/create_contribution (both codingamerId-first)--confirmed live (2026-07-29) against a disposable draft contribution created via create_contribution for the purpose.

Parameters:

  • contribution_id (CgContributionId) –

    The opaque contribution ID (see CgContributionId) to delete.

  • codingamer_id (int | None, default: None ) –

    The authoring codingamer's numeric ID. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/contribution.py
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
async def delete_contribution(
            self,
            contribution_id: CgContributionId,
            codingamer_id: int | None = None,
        ) -> CgDeleteContributionResult:
    """Delete a contribution.

       Argument shape (`[codingamerId, contributionId]`), by analogy with
       `update_contribution`/`create_contribution` (both `codingamerId`-first)--confirmed
       live (2026-07-29) against a disposable draft contribution created via
       `create_contribution` for the purpose.

    Args:
        contribution_id: The opaque contribution ID (see `CgContributionId`) to delete.
        codingamer_id:   The authoring codingamer's numeric ID. If not provided, defaults to
                         the logged-in codingamer's ID.

    Returns:
        A `CgDeleteContributionResult` (an action ID and a success flag).

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_result = await self.service_request_to_dict(
            "deleteContribution", [codingamer_id, contribution_id])
    return CgDeleteContributionResult.from_dict(raw_result)

CgContributionServiceHelper

CgContributionServiceHelper(service)

Bases: CgServiceHelper['CgContributionService']

Helper methods for CgContributionService.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

update_contribution async

update_contribution(contribution_id, puzzle_type, contribution_data, draft, ready_for_moderation, prev_version, codingamer_id=None, *, max_wait_seconds=0.0, on_poll=None)

Submit a new version of a contribution's content, adding 524 retry/polling on top of the plain CgContributionService.update_contribution.

Deliberately does no normalization of contribution_data. Newline canonicalization lives in codingame_tools.common.text_files, applied by the puzzle/contribution managers as they convert between server values and local files--not here, where it would silently rewrite a caller's data at the transport layer and, worse, half of a round trip whose other half lives somewhere else entirely.

The server re-validates a contribution's full test suite on every update, which for heavy contributions can take long enough that Cloudflare's edge disconnects the request even though the origin call eventually completes successfully server-side. If that happens (an CgClientHttpError with status_code == 524), this method assumes the update likely succeeded and polls find_contribution every 30 seconds until last_version.version increments past prev_version, instead of propagating the 524.

contribution_id, puzzle_type, contribution_data, draft, ready_for_moderation, prev_version and codingamer_id are passed straight through--see CgContributionService.update_contribution.

Parameters:

  • max_wait_seconds (float, default: 0.0 ) –

    How long to keep polling after a 524 before giving up, in seconds. 0 (the default) means wait indefinitely. Ignored entirely if no 524 occurs.

  • on_poll (Callable[[CgContribution], Awaitable[None]] | None, default: None ) –

    If given, awaited with each CgContribution observed while polling after a 524 (i.e. find_contribution results still at prev_version, before the final, committed one)--unlike CgReportServiceHelper. find_report_by_submission_when_ready's on_poll, this one always carries real (if stale) data. Never called at all if no 524 occurs. Doubles as a cancellation hook: raise from it (or from an await inside it) to abort the wait immediately, instead of only being able to give up via max_wait_seconds. Any exception it raises propagates out of this method uncaught.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx and not 524, or if the decoded content is not a dict.

  • TimeoutError

    If a 524 occurred and max_wait_seconds elapsed before the contribution's version incremented. The update may still complete server-side.

Source code in codingame_tools/client/service/services/contribution.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
async def update_contribution(
            self,
            contribution_id: CgContributionId,
            puzzle_type: CgPuzzleType,
            contribution_data: CgContributionData,
            draft: bool,
            ready_for_moderation: bool,
            prev_version: int,
            codingamer_id: int | None = None,
            *,
            max_wait_seconds: float = 0.0,
            on_poll: Callable[[CgContribution], Awaitable[None]] | None = None,
        ) -> CgContribution:
    """Submit a new version of a contribution's content, adding 524 retry/polling on top of
       the plain `CgContributionService.update_contribution`.

       Deliberately does no normalization of `contribution_data`. Newline canonicalization lives
       in `codingame_tools.common.text_files`, applied by the puzzle/contribution managers as
       they convert between server values and local files--not here, where it would silently
       rewrite a caller's data at the transport layer and, worse, half of a round trip whose
       other half lives somewhere else entirely.

       The server re-validates a contribution's full test suite on every update, which for
       heavy contributions can take long enough that Cloudflare's edge disconnects the
       request even though the origin call eventually completes successfully server-side. If
       that happens (an `CgClientHttpError` with `status_code == 524`), this method
       assumes the update likely succeeded and polls `find_contribution` every 30 seconds
       until `last_version.version` increments past `prev_version`, instead of propagating
       the 524.

    `contribution_id`, `puzzle_type`, `contribution_data`, `draft`, `ready_for_moderation`,
       `prev_version` and `codingamer_id` are passed straight through--see
       `CgContributionService.update_contribution`.

    Args:
        max_wait_seconds:
            How long to keep polling after a 524 before giving up, in seconds. 0 (the
            default) means wait indefinitely. Ignored entirely if no 524 occurs.
        on_poll: If given, awaited with each `CgContribution` observed while polling after a
                 524 (i.e. `find_contribution` results still at `prev_version`, before the
                 final, committed one)--unlike `CgReportServiceHelper.
                 find_report_by_submission_when_ready`'s `on_poll`, this one always carries
                 real (if stale) data. Never called at all if no 524 occurs. Doubles as a
                 cancellation hook: raise from it (or from an `await` inside it) to abort the
                 wait immediately, instead of only being able to give up via
                 `max_wait_seconds`. Any exception it raises propagates out of this method
                 uncaught.

    Returns:
        The updated CgContribution.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx and not 524, or if the decoded content is not a
            dict.
        TimeoutError:
            If a 524 occurred and `max_wait_seconds` elapsed before the contribution's
            version incremented. The update may still complete server-side.
    """
    try:
        return await self.service.update_contribution(
                contribution_id, puzzle_type, contribution_data, draft, ready_for_moderation,
                prev_version, codingamer_id)
    except CgClientHttpError as e:
        if e.status_code != 524:
            raise
    logger.warning(
        "update_contribution: got HTTP 524 for contribution %r; server likely committed "
        "the update anyway. Polling find_contribution for the version to increment "
        "(max_wait_seconds=%s)...",
        contribution_id, "infinite" if max_wait_seconds <= 0 else max_wait_seconds,
    )
    deadline = None if max_wait_seconds <= 0 else time.monotonic() + max_wait_seconds
    return await self._poll_until_committed(
            contribution_id, prev_version, deadline, contribution_data, on_poll)

create_contribution async

create_contribution(puzzle_type, contribution_data, draft, ready_for_moderation, codingamer_id=None)

Create a brand new contribution. Deliberately adds no 524 retry (see below) and, like update_contribution, no normalization of contribution_data.

Unlike update_contribution, there is no prev_version-style idempotency check the server can use to reject a duplicate resubmission, and no existing contribution_id to poll find_contribution against if a request times out at Cloudflare's edge (the same status_code == 524 scenario update_contribution recovers from by polling)--so blindly retrying here could create a second, duplicate contribution instead of recovering from one. This method therefore does NOT catch/retry on 524; it just logs an error making that risk explicit and re-raises, leaving the decision (retry and risk a duplicate, or go check cg api contribution get-all-pending-contributions/the CodinGame site first) to the caller.

puzzle_type, contribution_data, draft, ready_for_moderation and codingamer_id are passed straight through--see CgContributionService.create_contribution.

Returns:

  • CgContributionId

    The new contribution's opaque public handle (CgContributionId).

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a str. In particular, a 524 is NOT retried--see above--and is raised like any other error.

Source code in codingame_tools/client/service/services/contribution.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
async def create_contribution(
            self,
            puzzle_type: CgPuzzleType,
            contribution_data: CgContributionData,
            draft: bool,
            ready_for_moderation: bool,
            codingamer_id: int | None = None,
        ) -> CgContributionId:
    """Create a brand new contribution. Deliberately adds no 524 retry (see below) and, like
       `update_contribution`, no normalization of `contribution_data`.

       Unlike `update_contribution`, there is no `prev_version`-style idempotency check the
       server can use to reject a duplicate resubmission, and no existing `contribution_id`
       to poll `find_contribution` against if a request times out at Cloudflare's edge (the
       same `status_code == 524` scenario `update_contribution` recovers from by polling)--so
       blindly retrying here could create a second, duplicate contribution instead of
       recovering from one. This method therefore does NOT catch/retry on 524; it just logs
       an error making that risk explicit and re-raises, leaving the decision (retry and risk
       a duplicate, or go check `cg api contribution get-all-pending-contributions`/the
       CodinGame site first) to the caller.

    `puzzle_type`, `contribution_data`, `draft`, `ready_for_moderation` and `codingamer_id` are
       passed straight through--see `CgContributionService.create_contribution`.

    Returns:
        The new contribution's opaque public handle (`CgContributionId`).

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a str. In
            particular, a 524 is NOT retried--see above--and is raised like any other error.
    """
    try:
        return await self.service.create_contribution(
                puzzle_type, contribution_data, draft, ready_for_moderation, codingamer_id)
    except CgClientHttpError as e:
        if e.status_code == 524:
            logger.error(
                "create_contribution: got HTTP 524; the contribution may or may not have "
                "actually been created server-side. NOT retrying automatically (unlike "
                "update_contribution, there's no prev_version-style check to prevent a retry "
                "from creating a *second*, duplicate contribution)--check "
                "get_all_pending_contributions/the CodinGame site before deciding whether to "
                "resubmit.",
            )
        raise

CgFeaturedEventService

CgFeaturedEventService(client)

Bases: CgService

Async FeaturedEvent service endpoint.

Source code in codingame_tools/client/service/services/featured_event.py
27
28
29
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "FeaturedEvent")
    self.helper = CgFeaturedEventServiceHelper(self)
find_upcoming_and_ongoing_featured_events(codingamer_id=None)

Find upcoming and ongoing site-wide featured events (e.g. scheduled Clash of Code or puzzle events), and whether the given codingamer is registered for each.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer to check registration status for. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/featured_event.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
async def find_upcoming_and_ongoing_featured_events(
            self,
            codingamer_id: int | None = None,
        ) -> list[CgFeaturedEvent]:
    """Find upcoming and ongoing site-wide featured events (e.g. scheduled Clash of Code or
       puzzle events), and whether the given codingamer is registered for each.

    Args:
        codingamer_id: The codingamer to check registration status for. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgFeaturedEvent objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_events = await self.service_request_to_list(
            "findUpcomingAndOngoingFeaturedEvents", [codingamer_id])
    return CgFeaturedEvent.from_list(cast(list[JsonDict], raw_events))

is_codingamer_auto_registered async

is_codingamer_auto_registered(codingamer_id=None)

Check whether a codingamer is auto-registered for featured events (e.g. an account setting that opts them into upcoming Clash of Code/puzzle events automatically).

This is a personal setting: passing a codingamer_id other than your own logged-in ID is rejected by the server with a 403 (invalidUser: You are not authorized to perform this operation).

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer to check. Must be the logged-in codingamer's own ID (server-enforced; see above). If not provided, defaults to the logged-in codingamer's ID.

Returns:

  • bool

    True if the codingamer is auto-registered, False otherwise.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx (e.g. 403 if codingamer_id is not your own), or if the decoded content is not a bool.

Source code in codingame_tools/client/service/services/featured_event.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
async def is_codingamer_auto_registered(
            self,
            codingamer_id: int | None = None,
        ) -> bool:
    """Check whether a codingamer is auto-registered for featured events (e.g. an account
       setting that opts them into upcoming Clash of Code/puzzle events automatically).

       This is a personal setting: passing a `codingamer_id` other than your own logged-in
       ID is rejected by the server with a 403 (`invalidUser: You are not authorized to
       perform this operation`).

    Args:
        codingamer_id: The codingamer to check. Must be the logged-in codingamer's own ID
                       (server-enforced; see above). If not provided, defaults to the
                       logged-in codingamer's ID.

    Returns:
        True if the codingamer is auto-registered, False otherwise.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx (e.g. 403 if `codingamer_id` is not your own), or
            if the decoded content is not a bool.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    result = await self.service_request("isCodingamerAutoRegistered", [codingamer_id])
    return cast(bool, result)
find_new_featured_event_count(since=None)

Count featured events published since a given point in time.

since is sent to the server as a bare epoch-millis integer, like every other epoch-millis argument in this API. CodinGame's own web client has been observed sending it as a quoted (string-encoded) number instead--both encodings were tested empirically and the server accepts either, so the simpler bare-int form is used here. Also confirmed empirically: passing a timestamp before a known featured event's publish_time counts it towards the result; passing one at or after does not.

This value has not been observed being returned by any other endpoint (e.g. as a stored "last checked" marker)--callers are expected to track their own reference point (e.g. "now", or whenever they last called this).

Parameters:

  • since (datetime | None, default: None ) –

    Count featured events published after this point in time. If not provided, defaults to now (which will always yield 0--callers interested in a nonzero count should track their own reference point, e.g. the last time they called this). Naive datetimes are interpreted as local time (matching Python's own datetime.timestamp() behavior).

Returns:

  • int

    The number of featured events published since since.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not an int.

Source code in codingame_tools/client/service/services/featured_event.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
async def find_new_featured_event_count(
            self,
            since: datetime | None = None,
        ) -> int:
    """Count featured events published since a given point in time.

       `since` is sent to the server as a bare epoch-millis integer, like every other
       epoch-millis argument in this API. CodinGame's own web client has been observed
       sending it as a quoted (string-encoded) number instead--both encodings were tested
       empirically and the server accepts either, so the simpler bare-int form is used here.
       Also confirmed empirically: passing a timestamp before a known featured event's
       `publish_time` counts it towards the result; passing one at or after does not.

       This value has not been observed being returned by any other endpoint (e.g. as a
       stored "last checked" marker)--callers are expected to track their own reference
       point (e.g. "now", or whenever they last called this).

    Args:
        since: Count featured events published after this point in time. If not provided,
               defaults to now (which will always yield 0--callers interested in a nonzero
               count should track their own reference point, e.g. the last time they called
               this). Naive datetimes are interpreted as local time (matching Python's own
               `datetime.timestamp()` behavior).

    Returns:
        The number of featured events published since `since`.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not an int.
    """
    if since is None:
        since = datetime.now(timezone.utc)
    since_ms = int(since.timestamp() * 1000)
    result = await self.service_request("findNewFeaturedEventCount", [since_ms])
    return cast(int, result)

find_clash_slots async

find_clash_slots(featured_event_id)

Find the individual scheduled Clash of Code slots belonging to a featured event.

featured_event_id is CgFeaturedEvent.id (not CgFeaturedEvent.handle)--e.g. for a CgFeaturedEvent with handle == "4725bc5cbd6926ec69e31fd542cd0b354738", id is 4725, the (coincidental-looking) numeric prefix of the handle.

Parameters:

  • featured_event_id (int) –

    The id of a "CLASH_OF_CODE"-type CgFeaturedEvent.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/featured_event.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
async def find_clash_slots(
            self,
            featured_event_id: int,
        ) -> list[CgClashSlot]:
    """Find the individual scheduled Clash of Code slots belonging to a featured event.

       `featured_event_id` is `CgFeaturedEvent.id` (not `CgFeaturedEvent.handle`)--e.g. for
       a `CgFeaturedEvent` with `handle == "4725bc5cbd6926ec69e31fd542cd0b354738"`, `id`
       is `4725`, the (coincidental-looking) numeric prefix of the handle.

    Args:
        featured_event_id: The `id` of a "CLASH_OF_CODE"-type `CgFeaturedEvent`.

    Returns:
        A list of CgClashSlot objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    raw_slots = await self.service_request_to_list("findClashSlots", [featured_event_id])
    return CgClashSlot.from_list(cast(list[JsonDict], raw_slots))

find_by_handle async

find_by_handle(handle)

Find a featured event by its opaque handle.

Unlike findUpcomingAndOngoingFeaturedEvents, this endpoint has no codingamer context, so the returned CgFeaturedEvent.registered is always None here.

Parameters:

  • handle (str) –

    The featured event's opaque handle (CgFeaturedEvent.handle).

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/featured_event.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
async def find_by_handle(
            self,
            handle: str,
        ) -> CgFeaturedEvent:
    """Find a featured event by its opaque handle.

       Unlike findUpcomingAndOngoingFeaturedEvents, this endpoint has no codingamer context,
       so the returned `CgFeaturedEvent.registered` is always None here.

    Args:
        handle: The featured event's opaque handle (`CgFeaturedEvent.handle`).

    Returns:
        A CgFeaturedEvent object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_event = await self.service_request_to_dict("findByHandle", [handle])
    return CgFeaturedEvent.from_dict(raw_event)

CgFeaturedEventServiceHelper

CgFeaturedEventServiceHelper(service)

Bases: CgServiceHelper['CgFeaturedEventService']

Helper methods for CgFeaturedEventService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgIntercomService

CgIntercomService(client)

Bases: CgService

Async Intercom service endpoint.

Source code in codingame_tools/client/service/services/intercom.py
23
24
25
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Intercom")
    self.helper = CgIntercomServiceHelper(self)

generate_token async

generate_token()

Generate an Intercom identity-verification JWT for the logged-in codingamer, used to authenticate the user's identity to Intercom's live-chat widget.

The decoded JWT payload (HS256, audience "Intercom") contains standard identity claims: user_id, email, pseudo, language_override, plus iat/exp (observed validity: 1 hour).

Returns None if Intercom is not available for the logged-in codingamer--observed for one real, logged-in account, reason unknown (possibly an account/plan-specific feature gate). This is a genuine, successfully-decoded null response, not an error.

Returns:

  • str | None

    The signed JWT string, or None if not available for this codingamer.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is neither a str nor null.

Source code in codingame_tools/client/service/services/intercom.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
async def generate_token(self) -> str | None:
    """Generate an Intercom identity-verification JWT for the logged-in codingamer, used to
       authenticate the user's identity to Intercom's live-chat widget.

       The decoded JWT payload (HS256, audience "Intercom") contains standard identity
       claims: `user_id`, `email`, `pseudo`, `language_override`, plus `iat`/`exp` (observed
       validity: 1 hour).

       Returns None if Intercom is not available for the logged-in codingamer--observed for
       one real, logged-in account, reason unknown (possibly an account/plan-specific
       feature gate). This is a genuine, successfully-decoded `null` response, not an error.

    Returns:
        The signed JWT string, or None if not available for this codingamer.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is neither a str nor null.
    """
    result = await self.service_request("generateToken")
    if result is None:
        return None
    if not isinstance(result, str):
        raise CgClientHttpError(
                f"Invalid response type: expected a JSON string or null, got {type(result).__name__}",
                content=result,
            )
    return result

CgIntercomServiceHelper

CgIntercomServiceHelper(service)

Bases: CgServiceHelper['CgIntercomService']

Helper methods for CgIntercomService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgLastActivitiesService

CgLastActivitiesService(client)

Bases: CgService

Async LastActivities service endpoint.

Source code in codingame_tools/client/service/services/last_activities.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "LastActivities")
    self.helper = CgLastActivitiesServiceHelper(self)

get_last_activities async

get_last_activities(codingamer_id=None, limit=4)

Get a codingamer's most recent activity feed entries.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose recent activity to list. If not provided, defaults to the logged-in codingamer's ID.

  • limit (int, default: 4 ) –

    Maximum number of activity entries to return. Defaults to 4 (the only value observed in practice, believed to be the max entry count).

Returns:

  • list[CgLastActivity]

    A list of CgLastActivity objects, most recent first.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/last_activities.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
async def get_last_activities(
            self,
            codingamer_id: int | None = None,
            limit: int = 4,
        ) -> list[CgLastActivity]:
    """Get a codingamer's most recent activity feed entries.

    Args:
        codingamer_id: The codingamer whose recent activity to list. If not provided,
                       defaults to the logged-in codingamer's ID.
        limit:         Maximum number of activity entries to return. Defaults to 4 (the only
                       value observed in practice, believed to be the max entry count).

    Returns:
        A list of CgLastActivity objects, most recent first.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_activities = await self.service_request_to_list(
            "getLastActivities", [codingamer_id, limit])
    return CgLastActivity.from_list(cast(list[JsonDict], raw_activities))

CgLastActivitiesServiceHelper

CgLastActivitiesServiceHelper(service)

Bases: CgServiceHelper['CgLastActivitiesService']

Helper methods for CgLastActivitiesService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgNotificationService

CgNotificationService(client)

Bases: CgService

Async Notification service endpoint.

Source code in codingame_tools/client/service/services/notification.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Notification")
    self.helper = CgNotificationServiceHelper(self)

find_unread_notifications async

find_unread_notifications(codingamer_id=None)

Find unread notifications for a codingamer.

This endpoint always requires a valid login, regardless of whose notifications are being queried.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer to find unread notifications for. If not provided, defaults to the logged-in codingamer's ID.

Returns:

  • list[CgNotification]

    A list of CgNotification objects, most recent first.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/notification.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
async def find_unread_notifications(
            self,
            codingamer_id: int | None = None,
        ) -> list[CgNotification]:
    """Find unread notifications for a codingamer.

       This endpoint always requires a valid login, regardless of whose notifications are
       being queried.

    Args:
        codingamer_id: The codingamer to find unread notifications for. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgNotification objects, most recent first.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    await self.require_authenticate()
    if codingamer_id is None:
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_notifications = await self.service_request_to_list(
            "findUnreadNotifications", [codingamer_id])
    return CgNotification.from_list(cast(list[JsonDict], raw_notifications))

CgNotificationServiceHelper

CgNotificationServiceHelper(service)

Bases: CgServiceHelper['CgNotificationService']

Helper methods for CgNotificationService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgProgrammingLanguageService

CgProgrammingLanguageService(client)

Bases: CgService

Async ProgrammingLanguage service endpoint.

Source code in codingame_tools/client/service/services/programming_language.py
23
24
25
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "ProgrammingLanguage")
    self.helper = CgProgrammingLanguageServiceHelper(self)

find_all_ids async

find_all_ids()

Find the IDs of all programming languages supported for contribution reference solutions.

Returns:

  • list[CgSolutionLanguage]

    A list of CgSolutionLanguage strings, e.g. "Python3", "Java", "C++".

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/programming_language.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
async def find_all_ids(self) -> list[CgSolutionLanguage]:
    """Find the IDs of all programming languages supported for contribution reference solutions.

    Returns:
        A list of `CgSolutionLanguage` strings, e.g. "Python3", "Java", "C++".

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    raw_ids = await self.service_request_to_list("findAllIds", [])
    return cast(list[CgSolutionLanguage], raw_ids)

CgProgrammingLanguageServiceHelper

CgProgrammingLanguageServiceHelper(service)

Bases: CgServiceHelper['CgProgrammingLanguageService']

Helper methods for CgProgrammingLanguageService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgPuzzleService

CgPuzzleService(client)

Bases: CgService

Async Puzzle service endpoint.

Source code in codingame_tools/client/service/services/puzzle.py
33
34
35
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Puzzle")
    self.helper = CgPuzzleServiceHelper(self)

count_solved_puzzles_by_programming_language async

count_solved_puzzles_by_programming_language(codingamer_id=None)

Count a codingamer's solved puzzles, broken down by programming language.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose solved-puzzle counts to list. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/puzzle.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
async def count_solved_puzzles_by_programming_language(
            self,
            codingamer_id: int | None = None,
        ) -> list[CgSolvedPuzzlesByLanguage]:
    """Count a codingamer's solved puzzles, broken down by programming language.

    Args:
        codingamer_id: The codingamer whose solved-puzzle counts to list. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgSolvedPuzzlesByLanguage objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_counts = await self.service_request_to_list(
            "countSolvedPuzzlesByProgrammingLanguage", [codingamer_id])
    return CgSolvedPuzzlesByLanguage.from_list(cast(list[JsonDict], raw_counts))

find_puzzle_of_the_week async

find_puzzle_of_the_week()

Find the current puzzle of the week.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/puzzle.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
async def find_puzzle_of_the_week(self) -> CgPuzzleOfTheWeek:
    """Find the current puzzle of the week.

    Returns:
        A CgPuzzleOfTheWeek object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_puzzle = await self.service_request_to_dict("findPuzzleOfTheWeek")
    return CgPuzzleOfTheWeek.from_dict(raw_puzzle)

find_all_minimal_progress async

find_all_minimal_progress(codingamer_id=None)

Find a codingamer's minimal progress summary for every puzzle they have some relationship to (not just solved/attempted ones--see CgPuzzleMinimalProgress).

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose puzzle progress to list. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/puzzle.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
async def find_all_minimal_progress(
            self,
            codingamer_id: int | None = None,
        ) -> list[CgPuzzleMinimalProgress]:
    """Find a codingamer's minimal progress summary for every puzzle they have some
       relationship to (not just solved/attempted ones--see `CgPuzzleMinimalProgress`).

    Args:
        codingamer_id: The codingamer whose puzzle progress to list. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        A list of CgPuzzleMinimalProgress objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_progress = await self.service_request_to_list("findAllMinimalProgress", [codingamer_id])
    return CgPuzzleMinimalProgress.from_list(cast(list[JsonDict], raw_progress))

find_progress_by_ids async

find_progress_by_ids(puzzle_ids, codingamer_id=None, arg3=2)

Find a codingamer's progress summary for a specific set of puzzles, by puzzle ID.

arg3's purpose is unclear: only 1 and 2 have been observed to return real data (both return the identical full result set, in the same order); every other value tried (0, 3, 4, 5, 6, 10, 100) silently returned an empty list rather than erroring. Defaults to 2, matching observed real usage.

Parameters:

  • puzzle_ids (list[int]) –

    Numeric puzzle IDs to look up (e.g. CgLastActivityPuzzle.id, CgPuzzleMinimalProgress.id).

  • codingamer_id (int | None, default: None ) –

    The codingamer whose progress to look up. If not provided, defaults to the logged-in codingamer's ID.

  • arg3 (int, default: 2 ) –

    Third positional argument to the underlying findProgressByIds API call. Purpose unclear; see above. Defaults to 2.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/puzzle.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
async def find_progress_by_ids(
            self,
            puzzle_ids: list[int],
            codingamer_id: int | None = None,
            arg3: int = 2,
        ) -> list[CgLastActivityPuzzle]:
    """Find a codingamer's progress summary for a specific set of puzzles, by puzzle ID.

       `arg3`'s purpose is unclear: only `1` and `2` have been observed to return real data
       (both return the identical full result set, in the same order); every other value
       tried (0, 3, 4, 5, 6, 10, 100) silently returned an empty list rather than erroring.
       Defaults to 2, matching observed real usage.

    Args:
        puzzle_ids:    Numeric puzzle IDs to look up (e.g. `CgLastActivityPuzzle.id`,
                       `CgPuzzleMinimalProgress.id`).
        codingamer_id: The codingamer whose progress to look up. If not provided, defaults
                       to the logged-in codingamer's ID.
        arg3:          Third positional argument to the underlying findProgressByIds API
                       call. Purpose unclear; see above. Defaults to 2.

    Returns:
        A list of CgLastActivityPuzzle objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_progress = await self.service_request_to_list(
            "findProgressByIds", cast(list[JsonData], [puzzle_ids, codingamer_id, arg3]))
    return CgLastActivityPuzzle.from_list(cast(list[JsonDict], raw_progress))

find_best_following_progress async

find_best_following_progress(puzzle_id, codingamer_id=None)

Find the best progress on a given puzzle among the codingamers a codingamer follows.

Returns an empty list if none of the followed codingamer(s) have attempted the puzzle. Only a single followed codingamer has been observed in testing, so it's unconfirmed whether more than one entry can be returned, or how "best" is determined among them--see CgFollowingPuzzleProgress.

Parameters:

  • puzzle_id (int) –

    Numeric ID of the puzzle to check.

  • codingamer_id (int | None, default: None ) –

    The codingamer whose followees to check. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/puzzle.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
async def find_best_following_progress(
            self,
            puzzle_id: int,
            codingamer_id: int | None = None,
        ) -> list[CgFollowingPuzzleProgress]:
    """Find the best progress on a given puzzle among the codingamers a codingamer follows.

       Returns an empty list if none of the followed codingamer(s) have attempted the
       puzzle. Only a single followed codingamer has been observed in testing, so it's
       unconfirmed whether more than one entry can be returned, or how "best" is determined
       among them--see `CgFollowingPuzzleProgress`.

    Args:
        puzzle_id:     Numeric ID of the puzzle to check.
        codingamer_id: The codingamer whose followees to check. If not provided, defaults
                       to the logged-in codingamer's ID.

    Returns:
        A list of CgFollowingPuzzleProgress objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_progress = await self.service_request_to_list(
            "findBestFollowingProgress", [codingamer_id, puzzle_id])
    return CgFollowingPuzzleProgress.from_list(cast(list[JsonDict], raw_progress))

find_progress_by_pretty_id async

find_progress_by_pretty_id(pretty_id, codingamer_id=None)

Find a codingamer's progress summary for a single puzzle, by its pretty ID (the displayed puzzle title, lowercased with spaces replaced by hyphens--e.g. "literary-alfabet-soupe" for "Literary Alfabet Soupe").

The richest of the three findProgress* methods: uniquely among them, this one also populates linked_achievements/moderators/statement/title_map.

Parameters:

  • pretty_id (str) –

    The puzzle's pretty ID (see CgLastActivityPuzzle.pretty_id).

  • codingamer_id (int | None, default: None ) –

    The codingamer whose progress to look up. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/puzzle.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
async def find_progress_by_pretty_id(
            self,
            pretty_id: str,
            codingamer_id: int | None = None,
        ) -> CgLastActivityPuzzle:
    """Find a codingamer's progress summary for a single puzzle, by its pretty ID (the
       displayed puzzle title, lowercased with spaces replaced by hyphens--e.g.
       "literary-alfabet-soupe" for "Literary Alfabet Soupe").

       The richest of the three findProgress* methods: uniquely among them, this one also
       populates `linked_achievements`/`moderators`/`statement`/`title_map`.

    Args:
        pretty_id:     The puzzle's pretty ID (see `CgLastActivityPuzzle.pretty_id`).
        codingamer_id: The codingamer whose progress to look up. If not provided, defaults
                       to the logged-in codingamer's ID.

    Returns:
        A CgLastActivityPuzzle object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_puzzle = await self.service_request_to_dict(
            "findProgressByPrettyId", [pretty_id, codingamer_id])
    return CgLastActivityPuzzle.from_dict(raw_puzzle)

generate_session_from_puzzle_pretty_id async

generate_session_from_puzzle_pretty_id(puzzle_pretty_id, codingamer_id=None, arg3=False)

Get (or create) the codingamer's test session handle for a puzzle, by the puzzle's pretty ID (e.g. "literary-alfabet-soupe"--see CgTestSessionPuzzle.pretty_id).

This is the API that resolves "which puzzle" into "which test session" before calling TestSession/startTestSession--i.e. the entry point for solving a puzzle by pretty ID rather than already having a test_session_handle in hand (e.g. from CgLastActivityPuzzle). Confirmed live (2026-07-30) to return the same handle across repeated calls for the same codingamer/puzzle--i.e. a per-user singleton test session, safely reusable/cacheable rather than needing to be re-derived on every use.

arg3's purpose is unknown; only observed as False.

Parameters:

  • puzzle_pretty_id (str) –

    The puzzle's pretty ID/slug.

  • codingamer_id (int | None, default: None ) –

    The codingamer to get/create the session for. If not provided, defaults to the logged-in codingamer's ID.

  • arg3 (bool, default: False ) –

    Third positional argument to the underlying API call. Purpose unknown; defaults to False.

Returns:

  • str

    The test session handle (see CgTestSessionService.start_test_session).

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/puzzle.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
async def generate_session_from_puzzle_pretty_id(
            self,
            puzzle_pretty_id: str,
            codingamer_id: int | None = None,
            arg3: bool = False,
        ) -> str:
    """Get (or create) the codingamer's test session handle for a puzzle, by the puzzle's
       pretty ID (e.g. "literary-alfabet-soupe"--see `CgTestSessionPuzzle.pretty_id`).

       This is the API that resolves "which puzzle" into "which test session" before calling
       `TestSession/startTestSession`--i.e. the entry point for solving a puzzle by pretty ID
       rather than already having a `test_session_handle` in hand (e.g. from
       `CgLastActivityPuzzle`). Confirmed live (2026-07-30) to return the *same* handle across
       repeated calls for the same codingamer/puzzle--i.e. a per-user singleton test session,
       safely reusable/cacheable rather than needing to be re-derived on every use.

       `arg3`'s purpose is unknown; only observed as `False`.

    Args:
        puzzle_pretty_id: The puzzle's pretty ID/slug.
        codingamer_id:    The codingamer to get/create the session for. If not provided,
                           defaults to the logged-in codingamer's ID.
        arg3:              Third positional argument to the underlying API call. Purpose
                           unknown; defaults to False.

    Returns:
        The test session handle (see `CgTestSessionService.start_test_session`).

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_result = await self.service_request_to_dict(
            "generateSessionFromPuzzlePrettyId", [codingamer_id, puzzle_pretty_id, arg3])
    return CgGeneratedPuzzleSession.from_dict(raw_result).handle

CgPuzzleServiceHelper

CgPuzzleServiceHelper(service)

Bases: CgServiceHelper['CgPuzzleService']

Helper methods for CgPuzzleService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgQuestService

CgQuestService(client)

Bases: CgService

Async Quest service endpoint.

Source code in codingame_tools/client/service/services/quest.py
24
25
26
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Quest")
    self.helper = CgQuestServiceHelper(self)

find_quest_map async

find_quest_map(codingamer_id=None)

Find a codingamer's quest map (the graph of quest nodes and links shown on the "Path" / quest-tree page), including their own progress on each quest.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer whose quest map to fetch. If not provided, defaults to the logged-in codingamer's ID.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/quest.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
async def find_quest_map(
            self,
            codingamer_id: int | None = None,
        ) -> CgQuestMap:
    """Find a codingamer's quest map (the graph of quest nodes and links shown on the
       "Path" / quest-tree page), including their own progress on each quest.

    Args:
        codingamer_id: The codingamer whose quest map to fetch. If not provided, defaults
                       to the logged-in codingamer's ID.

    Returns:
        A CgQuestMap object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_map = await self.service_request_to_dict("findQuestMap", [codingamer_id])
    return CgQuestMap.from_dict(raw_map)

count_lootable_quests async

count_lootable_quests(codingamer_id=None)

Count a codingamer's completed-but-unclaimed quests (i.e. quests where CgCodingamerQuest.completion_time is set but loot_time is still None).

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer to count lootable quests for. If not provided, defaults to the logged-in codingamer's ID.

Returns:

  • int

    The number of lootable (completed, reward not yet claimed) quests.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not an int.

Source code in codingame_tools/client/service/services/quest.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
async def count_lootable_quests(
            self,
            codingamer_id: int | None = None,
        ) -> int:
    """Count a codingamer's completed-but-unclaimed quests (i.e. quests where
       `CgCodingamerQuest.completion_time` is set but `loot_time` is still None).

    Args:
        codingamer_id: The codingamer to count lootable quests for. If not provided,
                       defaults to the logged-in codingamer's ID.

    Returns:
        The number of lootable (completed, reward not yet claimed) quests.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not an int.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    result = await self.service_request("countLootableQuests", [codingamer_id])
    return cast(int, result)

CgQuestServiceHelper

CgQuestServiceHelper(service)

Bases: CgServiceHelper['CgQuestService']

Helper methods for CgQuestService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgReportService

CgReportService(client)

Bases: CgService

Async Report service endpoint.

Source code in codingame_tools/client/service/services/report.py
80
81
82
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Report")
    self.helper = CgReportServiceHelper(self)

find_report_by_submission async

find_report_by_submission(submission_id)

Find the results report for a single puzzle submission.

Parameters:

  • submission_id (int) –

    Numeric ID of the submission (e.g. CgTestSessionQuestion.last_submission_id).

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/report.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
async def find_report_by_submission(self, submission_id: int) -> CgSubmissionReport:
    """Find the results report for a single puzzle submission.

    Args:
        submission_id: Numeric ID of the submission (e.g.
                       `CgTestSessionQuestion.last_submission_id`).

    Returns:
        A CgSubmissionReport object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_report = await self.service_request_to_dict("findReportBySubmission", [submission_id])
    return CgSubmissionReport.from_dict(raw_report)

CgReportServiceHelper

CgReportServiceHelper(service)

Bases: CgServiceHelper['CgReportService']

Helper methods for CgReportService.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

find_report_by_submission_when_ready async

find_report_by_submission_when_ready(submission_id, *, max_wait_seconds=60.0, on_poll=None)

Poll find_report_by_submission until grading has finished, adding retry/polling on top of the plain CgReportService.find_report_by_submission.

Calling findReportBySubmission immediately after TestSession/submit can race server-side grading--see CgSubmissionReport's class docstring for a confirmed-live example (every field but best_score/validator_shareable entirely absent). This polls every _POLL_INTERVAL_SECONDS until CgSubmissionReport.is_ready() is true.

Parameters:

  • submission_id (int) –

    Numeric ID of the submission (e.g. CgTestSessionQuestion.last_submission_id).

  • max_wait_seconds (float, default: 60.0 ) –

    How long to keep polling before giving up, in seconds. 0 means wait indefinitely.

  • on_poll (Callable[[CgSubmissionReport], Awaitable[None]] | None, default: None ) –

    If given, awaited with each not-yet-ready CgSubmissionReport observed (i.e. every poll except the final, ready one). Currently these carry no real progress info (see the class docstring)--the main use is as a cancellation hook: raise from on_poll (or let an await inside it raise, e.g. asyncio.CancelledError) to abort the wait immediately, instead of only being able to give up via max_wait_seconds. Any exception it raises propagates out of this method uncaught.

Returns:

Raises:

  • (CgAuthenticationError, CgClientHttpError)

    see find_report_by_submission.

  • TimeoutError

    if grading hasn't finished before max_wait_seconds elapses.

Source code in codingame_tools/client/service/services/report.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
async def find_report_by_submission_when_ready(
            self, submission_id: int, *, max_wait_seconds: float = 60.0,
            on_poll: Callable[[CgSubmissionReport], Awaitable[None]] | None = None,
        ) -> CgSubmissionReport:
    """Poll `find_report_by_submission` until grading has finished, adding retry/polling on
       top of the plain `CgReportService.find_report_by_submission`.

       Calling `findReportBySubmission` immediately after `TestSession/submit` can race
       server-side grading--see `CgSubmissionReport`'s class docstring for a confirmed-live
       example (every field but `best_score`/`validator_shareable` entirely absent). This
       polls every `_POLL_INTERVAL_SECONDS` until `CgSubmissionReport.is_ready()` is true.

    Args:
        submission_id: Numeric ID of the submission (e.g.
                       `CgTestSessionQuestion.last_submission_id`).
        max_wait_seconds: How long to keep polling before giving up, in seconds. 0 means wait
                           indefinitely.
        on_poll: If given, awaited with each not-yet-ready `CgSubmissionReport` observed
                 (i.e. every poll except the final, ready one). Currently these carry no real
                 progress info (see the class docstring)--the main use is as a cancellation
                 hook: raise from `on_poll` (or let an `await` inside it raise, e.g.
                 `asyncio.CancelledError`) to abort the wait immediately, instead of only
                 being able to give up via `max_wait_seconds`. Any exception it raises
                 propagates out of this method uncaught.

    Returns:
        The first `CgSubmissionReport` observed with `is_ready()` true.

    Raises:
        CgAuthenticationError, CgClientHttpError: see `find_report_by_submission`.
        TimeoutError: if grading hasn't finished before `max_wait_seconds` elapses.
    """
    deadline = None if max_wait_seconds <= 0 else time.monotonic() + max_wait_seconds
    while True:
        report = await self.service.find_report_by_submission(submission_id)
        if report.is_ready():
            return report
        if on_poll is not None:
            await on_poll(report)
        if deadline is not None and time.monotonic() >= deadline:
            raise TimeoutError(
                f"Timed out waiting for the report for submission {submission_id} to "
                "finish grading; it may still complete server-side.")
        logger.info("find_report_by_submission_when_ready: submission %s not graded yet, "
                    "polling again in %.0fs...", submission_id, self._POLL_INTERVAL_SECONDS)
        await asyncio.sleep(self._POLL_INTERVAL_SECONDS)

CgSearchService

CgSearchService(client)

Bases: CgService

Async Search service endpoint.

Source code in codingame_tools/client/service/services/search.py
25
26
27
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Search")
    self.helper = CgSearchServiceHelper(self)

search async

search(query, locale='en', type_filter=None)

Search for codingamers, puzzles, and other objects by name.

Parameters:

  • query (str) –

    The search query text, e.g. a codingamer's pseudo or part of a puzzle title.

  • locale (str, default: 'en' ) –

    Locale code for localized result names, e.g. "en", "fr". Defaults to "en".

  • type_filter (CgSearchResultType | None, default: None ) –

    If provided, restricts results to a single CgSearchResultType (e.g. "USER", "PUZZLE"). Passing a list/tuple of types instead of a single string is rejected by the server with a 422 INVALID_PARAMETERS error. If not provided, results of all types are returned.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/search.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
async def search(
            self,
            query: str,
            locale: str = "en",
            type_filter: CgSearchResultType | None = None,
        ) -> list[CgSearchResult]:
    """Search for codingamers, puzzles, and other objects by name.

    Args:
        query:       The search query text, e.g. a codingamer's pseudo or part of a puzzle title.
        locale:      Locale code for localized result names, e.g. "en", "fr". Defaults to "en".
        type_filter: If provided, restricts results to a single `CgSearchResultType` (e.g.
                     "USER", "PUZZLE"). Passing a list/tuple of types instead of a single
                     string is rejected by the server with a 422 INVALID_PARAMETERS error.
                     If not provided, results of all types are returned.

    Returns:
        A list of CgSearchResult objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    raw_results = await self.service_request_to_list(
            "search", [query, locale, type_filter])
    return CgSearchResult.from_list(cast(list[JsonDict], raw_results))

CgSearchServiceHelper

CgSearchServiceHelper(service)

Bases: CgServiceHelper['CgSearchService']

Helper methods for CgSearchService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgSurveyService

CgSurveyService(client)

Bases: CgService

Async Survey service endpoint.

Source code in codingame_tools/client/service/services/survey.py
24
25
26
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Survey")
    self.helper = CgSurveyServiceHelper(self)

find_survey async

find_survey(codingamer_id=None, limit=2)

Find a survey to potentially show a codingamer.

UNVERIFIED: every account tested (including a couple of different real accounts) returned a bare null, so the real response shape (CgSurvey) is an empty placeholder pending a real example. limit's purpose is unconfirmed too--assumed (per the observed default value of 2) to cap the number of surveys returned, but this couldn't be verified empirically since no non-null response was ever observed.

Uses service_request (untyped JsonData) rather than service_request_to_dict, since the latter would reject the (apparently common) null response as an error.

Parameters:

  • codingamer_id (int | None, default: None ) –

    The codingamer to find a survey for. If not provided, defaults to the logged-in codingamer's ID.

  • limit (int, default: 2 ) –

    Assumed maximum number of results; unconfirmed. Defaults to 2 (the only value observed in practice).

Returns:

  • CgSurvey | None

    A CgSurvey object, or None if no survey is currently applicable.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is neither a dict nor null.

Source code in codingame_tools/client/service/services/survey.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
async def find_survey(
            self,
            codingamer_id: int | None = None,
            limit: int = 2,
        ) -> CgSurvey | None:
    """Find a survey to potentially show a codingamer.

       UNVERIFIED: every account tested (including a couple of different real accounts)
       returned a bare `null`, so the real response shape (`CgSurvey`) is an empty
       placeholder pending a real example. `limit`'s purpose is unconfirmed too--assumed
       (per the observed default value of 2) to cap the number of surveys returned, but this
       couldn't be verified empirically since no non-null response was ever observed.

       Uses `service_request` (untyped `JsonData`) rather than `service_request_to_dict`,
       since the latter would reject the (apparently common) `null` response as an error.

    Args:
        codingamer_id: The codingamer to find a survey for. If not provided, defaults to
                       the logged-in codingamer's ID.
        limit:         Assumed maximum number of results; unconfirmed. Defaults to 2 (the
                       only value observed in practice).

    Returns:
        A CgSurvey object, or None if no survey is currently applicable.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is neither a dict nor null.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_survey = await self.service_request("findSurvey", [codingamer_id, limit])
    if raw_survey is None:
        return None
    if not isinstance(raw_survey, dict):
        raise CgClientHttpError(
                f"Invalid response type: expected a JSON dictionary or null, got {type(raw_survey).__name__}",
                content=raw_survey,
            )
    return CgSurvey.from_dict(raw_survey)

CgSurveyServiceHelper

CgSurveyServiceHelper(service)

Bases: CgServiceHelper['CgSurveyService']

Helper methods for CgSurveyService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgTestSessionService

CgTestSessionService(client)

Bases: CgService

Async TestSession service endpoint.

Source code in codingame_tools/client/service/services/test_session.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "TestSession")
    self.helper = CgTestSessionServiceHelper(self)

start_test_session async

start_test_session(test_session_handle)

Start (or resume) an interactive IDE test session for a puzzle.

This is the API called by the web client when a codingamer clicks "Solve in IDE" on a puzzle. test_session_handle is a puzzle-specific handle (e.g. CgLastActivityPuzzle.test_session_handle, as returned by Puzzle/findProgressByIds/findProgressByPrettyId or embedded in a "PUZZLE"-type CgLastActivity)--not a codingamer or contribution handle.

Parameters:

  • test_session_handle (str) –

    The puzzle's test session handle.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/test_session.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
async def start_test_session(self, test_session_handle: str) -> CgTestSession:
    """Start (or resume) an interactive IDE test session for a puzzle.

       This is the API called by the web client when a codingamer clicks "Solve in IDE" on
       a puzzle. `test_session_handle` is a puzzle-specific handle (e.g.
       `CgLastActivityPuzzle.test_session_handle`, as returned by
       Puzzle/findProgressByIds/findProgressByPrettyId or embedded in a "PUZZLE"-type
       `CgLastActivity`)--not a codingamer or contribution handle.

    Args:
        test_session_handle: The puzzle's test session handle.

    Returns:
        A CgTestSession object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_session = await self.service_request_to_dict("startTestSession", [test_session_handle])
    return CgTestSession.from_dict(raw_session)

play async

play(test_session_handle, request)

Run a codingamer's code against a single test case within a test session.

This is the API invoked by the IDE's "Test"/"Run" button (as opposed to a full "Submit"). Confirmed empirically: result.comparison is always present; when the code fails to compile/parse or raises an uncaught exception, result.error is also populated (with a stack trace) and result.output is empty. See CgPlayResult for the full breakdown of what's present in each case.

Parameters:

  • test_session_handle (str) –

    The puzzle's test session handle (see start_test_session).

  • request (CgPlayRequest) –

    The code/language/test-case-selection payload to run.

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a dict.

Source code in codingame_tools/client/service/services/test_session.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
async def play(
            self,
            test_session_handle: str,
            request: CgPlayRequest,
        ) -> CgPlayResult:
    """Run a codingamer's code against a single test case within a test session.

       This is the API invoked by the IDE's "Test"/"Run" button (as opposed to a full
       "Submit"). Confirmed empirically: `result.comparison` is always present; when the
       code fails to compile/parse or raises an uncaught exception, `result.error` is also
       populated (with a stack trace) and `result.output` is empty. See `CgPlayResult` for
       the full breakdown of what's present in each case.

    Args:
        test_session_handle: The puzzle's test session handle (see
                              `start_test_session`).
        request:              The code/language/test-case-selection payload to run.

    Returns:
        A CgPlayResult object.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a dict.
    """
    raw_result = await self.service_request_to_dict("play", [test_session_handle, request.to_dict()])
    return CgPlayResult.from_dict(raw_result)

generate_lsp_token async

generate_lsp_token(test_session_id)

Generate a Language Server Protocol (LSP) auth token for a test session.

Used by the IDE to authenticate to a separate language-server backend for syntax highlighting, autocomplete, etc.--not useful for a code-driven client, and not explored further than confirming its shape. test_session_id is the numeric CgTestSession.test_session_id (distinct from the string test_session_handle used by start_test_session/play).

The returned JWT (RS256-signed, confirmed by decoding one) has payload claims aud: "LanguageServer", application: "CodinGame IDE", a human-readable context (e.g. 'Puzzle literary-alfabet-soupe (id: 10075)'), and sub/userId identifying the codingamer. Observed validity: 1 hour.

Parameters:

  • test_session_id (int) –

    The test session's numeric ID (CgTestSession.test_session_id).

Returns:

  • str

    The signed JWT string.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a str.

Source code in codingame_tools/client/service/services/test_session.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
async def generate_lsp_token(self, test_session_id: int) -> str:
    """Generate a Language Server Protocol (LSP) auth token for a test session.

       Used by the IDE to authenticate to a separate language-server backend for
       syntax highlighting, autocomplete, etc.--not useful for a code-driven client, and not
       explored further than confirming its shape. `test_session_id` is the numeric
       `CgTestSession.test_session_id` (distinct from the string `test_session_handle` used
       by `start_test_session`/`play`).

       The returned JWT (RS256-signed, confirmed by decoding one) has payload claims
       `aud: "LanguageServer"`, `application: "CodinGame IDE"`, a human-readable `context`
       (e.g. 'Puzzle literary-alfabet-soupe (id: 10075)'), and `sub`/`userId` identifying the
       codingamer. Observed validity: 1 hour.

    Args:
        test_session_id: The test session's numeric ID (`CgTestSession.test_session_id`).

    Returns:
        The signed JWT string.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a str.
    """
    result = await self.service_request("generateLspToken", [test_session_id])
    return cast(str, result)

get_previous_code_by_language_id async

get_previous_code_by_language_id(test_session_handle, programming_language_id)

Fetch the codingamer's most recently saved code for one language in a test session.

CodinGame keeps your latest source per language for a puzzle, not just one. A test session hands back whichever language you last used; this reaches the others, and is how the IDE's language dropdown restores your previous work when you switch.

Two semantics confirmed live (2026-08-02) against "Temperatures", both easy to assume wrongly:

  • This is a pure read. It does not make programming_language_id the session's current language--after fetching Python3 from a session whose current language was C++, the session still reported C++. The current language only moves when you actually run a test against it or submit it (see play/submit).
  • A language you have never attempted returns None, not a generated starter stub (verified with Haskell). There is nothing saved to return, and this API does not render a stub from the puzzle's stub_generator.

Parameters:

  • test_session_handle (str) –

    The puzzle's test session handle.

  • programming_language_id (CgSolutionLanguage) –

    CodinGame's language ID, e.g. "Python3", "C++" (see CgSolutionLanguage).

Returns:

  • str | None

    The saved source for that language, or None if the codingamer has never attempted

  • str | None

    this puzzle in it.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, or if the status code is not 2xx.

Source code in codingame_tools/client/service/services/test_session.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
async def get_previous_code_by_language_id(
            self,
            test_session_handle: str,
            programming_language_id: CgSolutionLanguage,
        ) -> str | None:
    """Fetch the codingamer's most recently saved code for one language in a test session.

       CodinGame keeps your latest source *per language* for a puzzle, not just one. A test
       session hands back whichever language you last used; this reaches the others, and is how
       the IDE's language dropdown restores your previous work when you switch.

       Two semantics confirmed live (2026-08-02) against "Temperatures", both easy to assume
       wrongly:

       - **This is a pure read.** It does *not* make `programming_language_id` the session's
         current language--after fetching Python3 from a session whose current language was
         C++, the session still reported C++. The current language only moves when you actually
         run a test against it or submit it (see `play`/`submit`).
       - **A language you have never attempted returns `None`**, not a generated starter stub
         (verified with Haskell). There is nothing saved to return, and this API does not
         render a stub from the puzzle's `stub_generator`.

    Args:
        test_session_handle:     The puzzle's test session handle.
        programming_language_id: CodinGame's language ID, e.g. "Python3", "C++" (see
                                  `CgSolutionLanguage`).

    Returns:
        The saved source for that language, or `None` if the codingamer has never attempted
        this puzzle in it.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            or if the status code is not 2xx.
    """
    result = await self.service_request(
            "getPreviousCodeByLanguageId", [test_session_handle, programming_language_id])
    return None if result is None else cast(str, result)

submit async

submit(test_session_handle, request, arg3=None)

Submit a final solution to a puzzle for credit.

This is the API invoked by the IDE's "Submit" button--unlike play, it validates against all of the puzzle's private validator test cases rather than a single local one. Confirmed empirically: returns quickly with a new submission ID, and (at least for a small/fast puzzle) full results were already available via Report/findReportBySubmission by the time the response came back--grading appears to happen before the response is returned, not asynchronously, in that case.

CAUTION: for a puzzle with many/heavy validator test cases, the server needs to instantiate containers and run the code once per validator, which can take a long time. It may eventually become necessary to handle Cloudflare-level timeouts/disconnects here and poll for a result instead of assuming a synchronous response--a similar open concern exists for contribution submission, not yet implemented in this client.

arg3's purpose is unknown; only observed as None.

Parameters:

  • test_session_handle (str) –

    The puzzle's test session handle.

  • request (CgSubmitRequest) –

    The code/language payload to submit.

  • arg3 (JsonData | None, default: None ) –

    Third positional argument to the underlying submit API call. Purpose unknown; defaults to None.

Returns:

  • int

    The new submission's numeric ID (see Report/findReportBySubmission).

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not an int.

Source code in codingame_tools/client/service/services/test_session.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
async def submit(
            self,
            test_session_handle: str,
            request: CgSubmitRequest,
            arg3: JsonData | None = None,
        ) -> int:
    """Submit a final solution to a puzzle for credit.

       This is the API invoked by the IDE's "Submit" button--unlike `play`, it validates
       against all of the puzzle's private validator test cases rather than a single local
       one. Confirmed empirically: returns quickly with a new submission ID, and (at least
       for a small/fast puzzle) full results were already available via
       Report/findReportBySubmission by the time the response came back--grading appears to
       happen before the response is returned, not asynchronously, in that case.

       CAUTION: for a puzzle with many/heavy validator test cases, the server needs to
       instantiate containers and run the code once per validator, which can take a long
       time. It may eventually become necessary to handle Cloudflare-level
       timeouts/disconnects here and poll for a result instead of assuming a synchronous
       response--a similar open concern exists for contribution submission, not yet
       implemented in this client.

       `arg3`'s purpose is unknown; only observed as None.

    Args:
        test_session_handle: The puzzle's test session handle.
        request:              The code/language payload to submit.
        arg3:                 Third positional argument to the underlying submit API call.
                              Purpose unknown; defaults to None.

    Returns:
        The new submission's numeric ID (see Report/findReportBySubmission).

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not an int.
    """
    result = await self.service_request(
            "submit", [test_session_handle, request.to_dict(), arg3])
    return cast(int, result)

CgTestSessionServiceHelper

CgTestSessionServiceHelper(service)

Bases: CgServiceHelper['CgTestSessionService']

Helper methods for CgTestSessionService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgTestSessionQuestionSubmissionService

CgTestSessionQuestionSubmissionService(client)

Bases: CgService

Async TestSessionQuestionSubmission service endpoint.

Source code in codingame_tools/client/service/services/test_session_question_submission.py
25
26
27
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "TestSessionQuestionSubmission")
    self.helper = CgTestSessionQuestionSubmissionServiceHelper(self)

find_all_submissions async

find_all_submissions(test_session_handle)

Find all past submissions for a puzzle, most recent first.

Parameters:

  • test_session_handle (str) –

    The puzzle's test session handle (see CgTestSessionService.start_test_session).

Returns:

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/test_session_question_submission.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
async def find_all_submissions(
            self,
            test_session_handle: str,
        ) -> list[CgTestSessionQuestionSubmission]:
    """Find all past submissions for a puzzle, most recent first.

    Args:
        test_session_handle: The puzzle's test session handle (see
                              `CgTestSessionService.start_test_session`).

    Returns:
        A list of CgTestSessionQuestionSubmission objects.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    raw_submissions = await self.service_request_to_list("findAllSubmissions", [test_session_handle])
    return CgTestSessionQuestionSubmission.from_list(cast(list[JsonDict], raw_submissions))

CgTestSessionQuestionSubmissionServiceHelper

CgTestSessionQuestionSubmissionServiceHelper(service)

Bases: CgServiceHelper['CgTestSessionQuestionSubmissionService']

Helper methods for CgTestSessionQuestionSubmissionService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgUserService

CgUserService(client)

Bases: CgService

Async User service endpoint.

Source code in codingame_tools/client/service/services/user.py
24
25
26
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "User")
    self.helper = CgUserServiceHelper(self)

update_user_properties async

update_user_properties(properties, codingamer_id=None)

Update a subset of a codingamer's account properties.

Only fields explicitly set on properties (i.e. not left as None) are sent to the server and updated--all other properties are left unchanged. The server returns an empty string on success, which is discarded.

Only one property (contributions_list_last_visit) is known and modeled on CgUserProperties so far; this will need to grow incrementally as more properties are discovered.

Parameters:

  • properties (CgUserProperties) –

    The properties to update; unset (None) fields are left unchanged.

  • codingamer_id (int | None, default: None ) –

    The codingamer to update. If not provided, defaults to the logged-in codingamer's ID.

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, or if the status code is not 2xx.

Source code in codingame_tools/client/service/services/user.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
async def update_user_properties(
            self,
            properties: CgUserProperties,
            codingamer_id: int | None = None,
        ) -> None:
    """Update a subset of a codingamer's account properties.

       Only fields explicitly set on `properties` (i.e. not left as None) are sent to the
       server and updated--all other properties are left unchanged. The server returns an
       empty string on success, which is discarded.

       Only one property (`contributions_list_last_visit`) is known and modeled on
       `CgUserProperties` so far; this will need to grow incrementally as more properties
       are discovered.

    Args:
        properties:    The properties to update; unset (None) fields are left unchanged.
        codingamer_id: The codingamer to update. If not provided, defaults to the logged-in
                       codingamer's ID.

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, or if the status code is not 2xx.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    await self.service_request("updateUserProperties", [codingamer_id, properties.to_dict()])

CgUserServiceHelper

CgUserServiceHelper(service)

Bases: CgServiceHelper['CgUserService']

Helper methods for CgUserService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service

CgVoteService

CgVoteService(client)

Bases: CgService

Async Vote service endpoint.

Source code in codingame_tools/client/service/services/vote.py
26
27
28
def __init__(self, client: CgClient) -> None:
    super().__init__(client, "Vote")
    self.helper = CgVoteServiceHelper(self)

find_votable_values_by_id async

find_votable_values_by_id(votable_id, codingamer_id=None)

Find a votable's current up/down-vote tally (and the querying codingamer's own vote, if any). Despite the response being a bare JSON array, only a single-votable_id call has been confirmed so far (returning a single-element list)--passing a JSON array of IDs for votable_id was tried and rejected by the server with a 422, so there is no known batch form.

Parameters:

  • votable_id (int) –

    The votable entity's ID (e.g. CgContribution.votable_id).

  • codingamer_id (int | None, default: None ) –

    The codingamer whose own vote to report (CgVotableValue. user_vote_value). If not provided, defaults to the logged-in codingamer's ID. Confirmed required by the server--omitting it entirely (rather than defaulting it here) is rejected with a 422.

Returns:

  • list[CgVotableValue]

    A list of CgVotableValue objects (one element, for votable_id, in every case

  • list[CgVotableValue]

    confirmed so far).

Raises:

  • CgAuthenticationError

    If the session is not authenticated and cannot implicitly login, or if codingamer_id is not provided and no codingamer ID can be resolved from the session's credentials.

  • CgClientHttpError

    If a transport error occurs, if the response content could not be decoded at all, if the status code is not 2xx, or if the decoded content is not a list.

Source code in codingame_tools/client/service/services/vote.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
async def find_votable_values_by_id(
            self,
            votable_id: int,
            codingamer_id: int | None = None,
        ) -> list[CgVotableValue]:
    """Find a votable's current up/down-vote tally (and the querying codingamer's own vote,
       if any). Despite the response being a bare JSON array, only a single-`votable_id`
       call has been confirmed so far (returning a single-element list)--passing a JSON
       array of IDs for `votable_id` was tried and rejected by the server with a 422, so
       there is no known batch form.

    Args:
        votable_id:    The votable entity's ID (e.g. `CgContribution.votable_id`).
        codingamer_id: The codingamer whose own vote to report (`CgVotableValue.
                       user_vote_value`). If not provided, defaults to the logged-in
                       codingamer's ID. Confirmed required by the server--omitting it
                       entirely (rather than defaulting it here) is rejected with a 422.

    Returns:
        A list of CgVotableValue objects (one element, for `votable_id`, in every case
        confirmed so far).

    Raises:
        CgAuthenticationError:
            If the session is not authenticated and cannot implicitly login, or if
            `codingamer_id` is not provided and no codingamer ID can be resolved from the
            session's credentials.
        CgClientHttpError:
            If a transport error occurs, if the response content could not be decoded at all,
            if the status code is not 2xx, or if the decoded content is not a list.
    """
    if codingamer_id is None:
        await self.require_authenticate()
        codingamer_id = self.client.codingamer_id
        if codingamer_id is None:
            raise CgAuthenticationError()
    raw_values = await self.service_request_to_list(
            "findVotableValuesById", [votable_id, codingamer_id])
    return CgVotableValue.from_list(cast(list[JsonDict], raw_values))

CgVoteServiceHelper

CgVoteServiceHelper(service)

Bases: CgServiceHelper['CgVoteService']

Helper methods for CgVoteService. Currently empty.

Source code in codingame_tools/client/service/cg_service.py
124
125
def __init__(self, service: TService) -> None:
    self.service = service