codingame_tools.client.service.services.contribution¶
contribution
¶
Async Contribution service endpoint.
CgContributionServiceHelper
¶
CgContributionServiceHelper(service)
Bases: CgServiceHelper['CgContributionService']
Helper methods for CgContributionService.
Source code in codingame_tools/client/service/cg_service.py
124 125 | |
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
CgContributionobserved while polling after a 524 (i.e.find_contributionresults still atprev_version, before the final, committed one)--unlikeCgReportServiceHelper. find_report_by_submission_when_ready'son_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 anawaitinside it) to abort the wait immediately, instead of only being able to give up viamax_wait_seconds. Any exception it raises propagates out of this method uncaught.
Returns:
-
CgContribution–The updated CgContribution.
Raises:
-
CgAuthenticationError–If the session is not authenticated and cannot implicitly login, or if
codingamer_idis 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_secondselapsed 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 | |
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_idis 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 | |
CgContributionService
¶
CgContributionService(client)
Bases: CgService
Async Contribution service endpoint.
Source code in codingame_tools/client/service/services/contribution.py
215 216 217 | |
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:
-
CgContribution–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.
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 | |
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_idis 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 | |
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 opaquepublic_handle/CgContributionIdstring used by every other method on this service (find_contribution/update_contribution/etc.). Confirmed live: passing the numericid(e.g.149373) works; the opaque handle was not tried here and is not expected to. -
action(CgModerationAction) –"validate"(approve) or"deny"(reject)--seeCgModerationAction.
Returns:
-
list[CgContributionModerator]–A list of CgContributionModerator objects--one per moderator who has cast that vote.
-
list[CgContributionModerator]–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.
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 | |
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:
-
list[CgPendingContribution]–A list of CgPendingContribution objects.
Raises:
-
CgAuthenticationError–If the session is not authenticated and cannot implicitly login, or if
codingamer_idis 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_idis not your own, or 500 ifpageis 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 | |
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:
-
list[CgPersonalContribution]–A list of CgPersonalContribution objects.
Raises:
-
CgAuthenticationError–If the session is not authenticated and cannot implicitly login, or if
codingamer_idis 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_idisn't your own, or ifpageis 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 | |
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
CgContributionDatareturned byfind_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:
-
CgContribution–The updated CgContribution.
Raises:
-
CgAuthenticationError–If the session is not authenticated and cannot implicitly login, or if
codingamer_idis 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_versionis 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 | |
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_idis 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 | |
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:
-
CgDeleteContributionResult–A
CgDeleteContributionResult(an action ID and a success flag).
Raises:
-
CgAuthenticationError–If the session is not authenticated and cannot implicitly login, or if
codingamer_idis 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 | |