icpc-api 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. icpc/__init__.py +32 -0
  2. icpc/api/__init__.py +18 -0
  3. icpc/api/common.py +97 -0
  4. icpc/api/contest.py +253 -0
  5. icpc/api/person.py +139 -0
  6. icpc/api/public.py +65 -0
  7. icpc/api/staff.py +83 -0
  8. icpc/api/team.py +335 -0
  9. icpc/auth/__init__.py +28 -0
  10. icpc/auth/cognito.py +142 -0
  11. icpc/auth/flows.py +314 -0
  12. icpc/auth/provider.py +29 -0
  13. icpc/auth/srp.py +185 -0
  14. icpc/auth/store.py +223 -0
  15. icpc/auth/tokens.py +86 -0
  16. icpc/cli/__init__.py +20 -0
  17. icpc/cli/columns.py +555 -0
  18. icpc/cli/main.py +1156 -0
  19. icpc/cli/render.py +160 -0
  20. icpc/config.py +57 -0
  21. icpc/errors.py +159 -0
  22. icpc/facade/__init__.py +6 -0
  23. icpc/facade/client.py +606 -0
  24. icpc/facade/domain.py +198 -0
  25. icpc/models/__init__.py +60 -0
  26. icpc/models/_generated.py +566 -0
  27. icpc/models/base.py +41 -0
  28. icpc/models/blobs.py +81 -0
  29. icpc/models/common.py +61 -0
  30. icpc/models/entities.py +522 -0
  31. icpc/models/enums.py +192 -0
  32. icpc/models/mixins.py +44 -0
  33. icpc/py.typed +0 -0
  34. icpc/search/__init__.py +99 -0
  35. icpc/search/_generated.py +1814 -0
  36. icpc/search/dsl.py +124 -0
  37. icpc/search/endpoint.py +173 -0
  38. icpc/search/fields.py +59 -0
  39. icpc/transport/__init__.py +29 -0
  40. icpc/transport/_shared.py +121 -0
  41. icpc/transport/async_client.py +120 -0
  42. icpc/transport/operation.py +139 -0
  43. icpc/transport/sync_client.py +121 -0
  44. icpc_api-0.1.0.dist-info/METADATA +143 -0
  45. icpc_api-0.1.0.dist-info/RECORD +50 -0
  46. icpc_api-0.1.0.dist-info/WHEEL +5 -0
  47. icpc_api-0.1.0.dist-info/entry_points.txt +2 -0
  48. icpc_api-0.1.0.dist-info/licenses/LICENSE +21 -0
  49. icpc_api-0.1.0.dist-info/licenses/THIRD-PARTY-LICENSES.md +220 -0
  50. icpc_api-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,566 @@
1
+ """Generated from icpc.global SPA bundle.
2
+
3
+ Field *names* come from each search endpoint itself. The API publishes no schema
4
+ for their *types*, so a field this module does not type explicitly is ``str``,
5
+ which is right for most columns but is a default rather than a verified fact.
6
+
7
+ Every field is optional: ``proj:`` does not shape the response, so anything not
8
+ projected arrives as ``null``.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from datetime import date, datetime
14
+
15
+ from pydantic import Field as _Field
16
+
17
+ from icpc.models.base import Row
18
+ from icpc.models.enums import (
19
+ Consent,
20
+ EligibilityStatus,
21
+ InstitutionUnitType,
22
+ MemberRole,
23
+ Sex,
24
+ ShirtSize,
25
+ TeamStatus,
26
+ Title,
27
+ )
28
+ from icpc.models.mixins import HasExtraFields, HasTeamMembers
29
+
30
+ __all__ = [
31
+ "CertificateRow",
32
+ "ContestParticipantRow",
33
+ "InstitutionRow",
34
+ "PromoteRow",
35
+ "StaffFundingRow",
36
+ "StaffMemberRow",
37
+ "StaffRow",
38
+ "StaffTshirtRow",
39
+ "StandingsRow",
40
+ "TeamMemberRow",
41
+ "TeamRow",
42
+ "TeamSummaryRow",
43
+ "Top20Row",
44
+ "TransportationMissingRow",
45
+ "TshirtRow",
46
+ ]
47
+
48
+
49
+ class CertificateRow(HasTeamMembers, Row):
50
+ """Team certificates issued for a contest.
51
+
52
+ Returned by:
53
+ * ``/contest/certificate/team/contest/{contest_id}/search``
54
+ * ``/contest/certificate/staff/contest/{contest_id}/search``
55
+ * ``/contest/certificate/site/team/site/{site_id}/search``
56
+ """
57
+
58
+ id: int | None = _Field(default=None, description="ID")
59
+ email: str | None = _Field(default=None, description="Email")
60
+ user_id: int | None = None
61
+ name: str | None = _Field(default=None, description="Name")
62
+ certificate_name: str | None = None
63
+ site_name: str | None = _Field(default=None, description="Site Name")
64
+ site_id: int | None = None
65
+ contest_name: str | None = _Field(default=None, description="Contest Name")
66
+ contest_id: int | None = None
67
+ role: str | None = _Field(default=None, description="Role")
68
+ institution_name: str | None = _Field(default=None, description="Institution Name")
69
+ inst_id: int | None = None
70
+ institution_short_name: str | None = _Field(default=None, description="Institution Short Name")
71
+ team_name: str | None = _Field(default=None, description="Team Name")
72
+ team_id: int | None = None
73
+ team_members: str | None = None
74
+ lite_team_member_set: str | None = None
75
+
76
+
77
+ class ContestParticipantRow(Row):
78
+ """Every person at a contest, with travel and visa detail. The widest DTO here.
79
+
80
+ Returned by:
81
+ * ``/contest/search/contest/{contest_id}/contestparticipant``
82
+ * ``/contest/search/site/{site_id}/contestparticipant``
83
+ """
84
+
85
+ person_id: int | None = None
86
+ username: str | None = _Field(default=None, description="Username")
87
+ local_name: str | None = _Field(default=None, description="Local Name")
88
+ badge_name: str | None = _Field(default=None, description="Badge Name")
89
+ secondary_email: str | None = _Field(default=None, description="Secondary Email")
90
+ first_name: str | None = _Field(default=None, description="First Name")
91
+ last_name: str | None = _Field(default=None, description="Last Name")
92
+ title: Title | str | None = _Field(
93
+ default=None, union_mode="left_to_right", description="Title"
94
+ )
95
+ sex: Sex | str | None = _Field(default=None, union_mode="left_to_right", description="Sex")
96
+ dob: date | str | None = _Field(
97
+ default=None, union_mode="left_to_right", description="Date of Birth"
98
+ )
99
+ phone: str | None = _Field(default=None, description="Phone")
100
+ emergency_contact: str | None = _Field(default=None, description="Emergency Contact")
101
+ emergency_phone: str | None = _Field(default=None, description="Emergency Phone")
102
+ job_title: str | None = _Field(default=None, description="Job Title")
103
+ company: str | None = _Field(default=None, description="Company")
104
+ special_needs: str | None = _Field(default=None, description="Special Needs")
105
+ shirt_size: ShirtSize | str | None = _Field(
106
+ default=None, union_mode="left_to_right", description="Shirt Size"
107
+ )
108
+ registration_complete: bool | None = _Field(default=None, description="Registration Complete")
109
+ home_country: str | None = _Field(default=None, description="Home Country")
110
+ expected_grad: date | str | None = _Field(
111
+ default=None, union_mode="left_to_right", description="Expected Graduation"
112
+ )
113
+ began_degree: date | str | None = _Field(
114
+ default=None, union_mode="left_to_right", description="Began Degree"
115
+ )
116
+ include_email: Consent | str | None = _Field(
117
+ default=None, union_mode="left_to_right", description="Interest - Include Email"
118
+ )
119
+ employment_opportunities: Consent | str | None = _Field(
120
+ default=None, union_mode="left_to_right", description="Interest - Employment Opportunities"
121
+ )
122
+ inform_other_contests: Consent | str | None = _Field(
123
+ default=None, union_mode="left_to_right", description="Interest - Inform Other Contests"
124
+ )
125
+ address_line1: str | None = _Field(default=None, description="Shipping Address Line 1")
126
+ address_line2: str | None = _Field(default=None, description="Shipping Address Line 2")
127
+ address_line3: str | None = _Field(default=None, description="Shipping Address Line 3")
128
+ city: str | None = _Field(default=None, description="City")
129
+ state: str | None = _Field(default=None, description="State")
130
+ postal_code: str | None = _Field(default=None, description="Postal Code")
131
+ twitter: str | None = _Field(default=None, description="Twitter")
132
+ facebook: str | None = _Field(default=None, description="Facebook")
133
+ top_coder: str | None = _Field(default=None, description="TopCoder")
134
+ codeforces: str | None = _Field(default=None, description="CodeForces")
135
+ linkedin: str | None = _Field(default=None, description="LinkedIn")
136
+ surname: str | None = _Field(default=None, description="Surname")
137
+ given_names: str | None = _Field(default=None, description="Given Names")
138
+ apply_from_city: str | None = _Field(default=None, description="Apply From City")
139
+ passport_country: str | None = _Field(default=None, description="Passport Country")
140
+ visa_plan: str | None = _Field(default=None, description="Visa Plan")
141
+ passport_number: str | None = _Field(default=None, description="Passport Number")
142
+ passport_expiry: date | str | None = _Field(
143
+ default=None, union_mode="left_to_right", description="Passport Expiry"
144
+ )
145
+ passport_issue: date | str | None = _Field(
146
+ default=None, union_mode="left_to_right", description="Passport Issued"
147
+ )
148
+ passport_nationality: str | None = _Field(default=None, description="Residence Nationality")
149
+ residence_country: str | None = _Field(default=None, description="Residence Country")
150
+ residence_city: str | None = _Field(default=None, description="Residence City")
151
+ passport_not_needed: bool | None = None
152
+ visa_type: str | None = _Field(default=None, description="Visa Type")
153
+ consulate_country: str | None = _Field(default=None, description="Consulate Country")
154
+ consulate_city: str | None = _Field(default=None, description="Consulate City")
155
+ consulate_interview: bool | None = _Field(default=None, description="Consulate Interview")
156
+ visa_needed: bool | None = None
157
+ entry_airport: str | None = _Field(default=None, description="Entry Airport")
158
+ inst_name: str | None = _Field(default=None, description="Institution Name")
159
+ inst_short_name: str | None = _Field(default=None, description="Institution Short Name")
160
+ inst_native_name: str | None = _Field(default=None, description="Institution Local Name")
161
+ inst_id: int | None = None
162
+ team_ids: str | None = _Field(default=None, description="Team IDs")
163
+ team_ids_out: str | None = None
164
+ teams: str | None = _Field(default=None, description="Teams")
165
+ teams_list: str | None = None
166
+ team_roles: str | None = _Field(default=None, description="Team Roles")
167
+ team_roles_out: str | None = None
168
+ team_sites: str | None = _Field(default=None, description="Team Sites")
169
+ team_sites_out: str | None = None
170
+ workstation_ids: str | None = _Field(default=None, description="Workstation IDs")
171
+ workstation_ids_out: str | None = None
172
+ staff_roles: str | None = _Field(default=None, description="Staff Roles")
173
+ staff_roles_out: str | None = None
174
+ staff_sites: str | None = _Field(default=None, description="Staff Sites")
175
+ staff_sites_out: str | None = None
176
+ labels: str | None = _Field(default=None, description="Labels")
177
+
178
+
179
+ class InstitutionRow(Row):
180
+ """Institutions with at least one team in a contest.
181
+
182
+ Returned by:
183
+ * ``/contest/search/contest/{contest_id}/institution``
184
+ * ``/contest/search/site/{site_id}/institutions``
185
+ """
186
+
187
+ inst_id: int | None = _Field(default=None, description="Inst-ID")
188
+ inst_name: str | None = _Field(default=None, description="Inst-Name")
189
+ inst_native_name: str | None = _Field(default=None, description="Inst-NativeName")
190
+ inst_short_name: str | None = _Field(default=None, description="Inst-ShortName")
191
+ inst_abbreviation: str | None = _Field(default=None, description="Inst-Abbreviation")
192
+ inst_homepage_url: str | None = _Field(default=None, description="Inst-URL")
193
+ inst_unit_id: int | None = _Field(default=None, description="Inst-U-ID")
194
+ inst_unit_name: str | None = _Field(default=None, description="Inst-U-Name")
195
+ inst_unit_native_name: str | None = _Field(default=None, description="Inst-U-NativeName")
196
+ inst_unit_short_name: str | None = _Field(default=None, description="Inst-U-ShortName")
197
+ inst_unit_abbreviation: str | None = _Field(default=None, description="Inst-U-Abbreviation")
198
+ inst_unit_homepage_url: str | None = _Field(default=None, description="Inst-U-URL")
199
+ inst_unit_type: InstitutionUnitType | str | None = _Field(
200
+ default=None, union_mode="left_to_right", description="Offered Degree"
201
+ )
202
+ address_line1: str | None = _Field(default=None, description="AddressLine1")
203
+ address_line2: str | None = _Field(default=None, description="AddressLine2")
204
+ address_line3: str | None = _Field(default=None, description="AddressLine3")
205
+ city: str | None = _Field(default=None, description="City")
206
+ state: str | None = _Field(default=None, description="State")
207
+ zip: str | None = _Field(default=None, description="Postal Code")
208
+ country_name: str | None = _Field(default=None, description="Country")
209
+ longitude: float | None = _Field(default=None, description="Longitude")
210
+ latitude: float | None = _Field(default=None, description="Latitude")
211
+ twitter_name: str | None = _Field(default=None, description="Twitter Name")
212
+ twitter_hash: str | None = _Field(default=None, description="Twitter Hash")
213
+ facebook_page: str | None = _Field(default=None, description="Facebook Page")
214
+
215
+
216
+ class PromoteRow(Row):
217
+ """Teams eligible to be promoted out of a contest.
218
+
219
+ Returned by:
220
+ * ``/team/search/{contest_id}/promote``
221
+ """
222
+
223
+ rank: int | None = _Field(default=None, description="Rank")
224
+ team_id: int | None = _Field(default=None, description="Team Id")
225
+ team_name: str | None = _Field(default=None, description="Team")
226
+ site_id: int | None = None
227
+ site_name: str | None = _Field(default=None, description="Site")
228
+ institution_id: int | None = None
229
+ institution_name: str | None = _Field(default=None, description="Institution")
230
+ promote_to_contest: int | None = None
231
+ promote_to_site: str | None = None
232
+
233
+
234
+ class StaffFundingRow(Row):
235
+ """Staff funding and budget rows.
236
+
237
+ Returned by:
238
+ * ``/contest/staffMember/funding/contest/{contest_id}/search``
239
+ """
240
+
241
+ contest_participant_id: int | None = None
242
+ site: str | None = _Field(default=None, description="Site")
243
+ site_id: int | None = None
244
+ person_id: int | None = None
245
+ first_name: str | None = _Field(default=None, description="First Name")
246
+ last_name: str | None = _Field(default=None, description="Last Name")
247
+ username: str | None = _Field(default=None, description="Email")
248
+ home_town: str | None = _Field(default=None, description="Home Town")
249
+ home_country: str | None = _Field(default=None, description="Home Country")
250
+ residence_country: str | None = None
251
+ funding: str | None = None
252
+ budget: float | None = _Field(default=None, description="Budget")
253
+ budget_adjustment: float | None = _Field(default=None, description="Budget Adjustment")
254
+ residence_town: str | None = None
255
+ initiated: bool | None = _Field(default=None, description="Initiated")
256
+ notes: str | None = _Field(default=None, description="Notes")
257
+ transport: str | None = None
258
+
259
+
260
+ class StaffMemberRow(Row):
261
+ """Staff members of a contest, from the staff administration grid.
262
+
263
+ Returned by:
264
+ * ``/contest/staffmember/contest/{contest_id}/search``
265
+ * ``/contest/staffmember/contest/{contest_id}/public/search``
266
+ """
267
+
268
+ staff_member_id: int | None = None
269
+ site_id: int | None = None
270
+ site: str | None = _Field(default=None, description="Site")
271
+ title: Title | str | None = _Field(
272
+ default=None, union_mode="left_to_right", description="Title"
273
+ )
274
+ first_name: str | None = _Field(default=None, description="First Name")
275
+ last_name: str | None = _Field(default=None, description="Last Name")
276
+ username: str | None = _Field(default=None, description="Email")
277
+ user_id: int | None = None
278
+ badge_role: str | None = _Field(default=None, description="Badge Role")
279
+ certificate_role: str | None = _Field(default=None, description="Certificate Role")
280
+ institution: str | None = _Field(default=None, description="Institution Name")
281
+ inst_id: int | None = None
282
+ registration_complete: bool | None = _Field(default=None, description="Registration Complete")
283
+ show_in_public_pages: bool | None = _Field(default=None, description="Show in Public Pages")
284
+ labels: str | None = _Field(default=None, description="Labels")
285
+ labels_lite: str | None = None
286
+
287
+
288
+ class StaffRow(HasExtraFields, Row):
289
+ """Contest staff, from the contest grid.
290
+
291
+ Returned by:
292
+ * ``/contest/search/contest/{contest_id}/staff``
293
+ """
294
+
295
+ staff_member_id: int | None = None
296
+ username: str | None = _Field(default=None, description="Username")
297
+ first_name: str | None = _Field(default=None, description="First Name")
298
+ last_name: str | None = _Field(default=None, description="Last Name")
299
+ badge_name: str | None = _Field(default=None, description="Badge Name")
300
+ certificate_name: str | None = _Field(default=None, description="Certificate Name")
301
+ roles: str | None = _Field(default=None, description="Roles")
302
+ phone: str | None = _Field(default=None, description="Phone")
303
+ institution: str | None = _Field(default=None, description="Institution Name")
304
+ site: str | None = _Field(default=None, description="Site")
305
+ shirt_size: ShirtSize | str | None = _Field(
306
+ default=None, union_mode="left_to_right", description="Shirt Size"
307
+ )
308
+ special_needs: str | None = _Field(default=None, description="Special Needs")
309
+ sex: Sex | str | None = _Field(default=None, union_mode="left_to_right", description="Sex")
310
+ complete_registration: bool | None = _Field(default=None, description="Registration Complete")
311
+ country: str | None = _Field(default=None, description="Country")
312
+ twitter: str | None = _Field(default=None, description="Twitter")
313
+ labels: str | None = _Field(default=None, description="Labels")
314
+ extra_field: str | None = _Field(default=None, description="Extra Fields")
315
+ person_id: int | None = None
316
+
317
+
318
+ class StaffTshirtRow(Row):
319
+ """Staff t-shirt sizes.
320
+
321
+ Returned by:
322
+ * ``/contest/staffmember/tshirt/contest/{contest_id}/search``
323
+ """
324
+
325
+ contest_participant_id: int | None = None
326
+ staff_member_id: int | None = None
327
+ site: str | None = _Field(default=None, description="Site")
328
+ person_id: int | None = None
329
+ first_name: str | None = _Field(default=None, description="First Name")
330
+ last_name: str | None = _Field(default=None, description="Last Name")
331
+ username: str | None = _Field(default=None, description="Email")
332
+ badge_role: str | None = _Field(default=None, description="Badge Role")
333
+ institution: str | None = _Field(default=None, description="Institution")
334
+ registration_complete: bool | None = _Field(default=None, description="Registration Complete")
335
+ shirt_size: ShirtSize | str | None = _Field(
336
+ default=None, union_mode="left_to_right", description="Shirt size"
337
+ )
338
+ tshirts: str | None = _Field(default=None, description="T-shirts")
339
+
340
+
341
+ class StandingsRow(Row):
342
+ """Uploaded standings documents for a contest (not the results themselves).
343
+
344
+ Returned by:
345
+ * ``/contest/standings/contest/{contest_id}/search``
346
+ """
347
+
348
+ id: int | None = None
349
+ name: str | None = _Field(default=None, description="Standings Name")
350
+ entered_by: str | None = _Field(default=None, description="Entered By")
351
+ date_entered: datetime | str | None = _Field(
352
+ default=None, union_mode="left_to_right", description="Date Entered"
353
+ )
354
+ certified: bool | None = _Field(default=None, description="Certified?")
355
+ certified_by: str | None = _Field(default=None, description="Certified By")
356
+ date_certified: datetime | str | None = _Field(
357
+ default=None, union_mode="left_to_right", description="Date Certified"
358
+ )
359
+ published: bool | None = _Field(default=None, description="Published?")
360
+
361
+
362
+ class TeamMemberRow(HasExtraFields, Row):
363
+ """Every team member in a contest, one row per membership.
364
+
365
+ Returned by:
366
+ * ``/contest/search/contest/{contest_id}/teammember``
367
+ * ``/contest/search/site/{site_id}/teammember``
368
+ """
369
+
370
+ id: int | None = None
371
+ role: MemberRole | str | None = _Field(
372
+ default=None, union_mode="left_to_right", description="Role"
373
+ )
374
+ person_id: int | None = None
375
+ username: str | None = _Field(default=None, description="Username")
376
+ first_name: str | None = _Field(default=None, description="First Name")
377
+ last_name: str | None = _Field(default=None, description="Last Name")
378
+ local_name: str | None = _Field(default=None, description="Local Name")
379
+ phone: str | None = _Field(default=None, description="Phone")
380
+ special_needs: str | None = _Field(default=None, description="Special Needs")
381
+ sex: Sex | str | None = _Field(default=None, union_mode="left_to_right", description="Sex")
382
+ complete_registration: bool | None = _Field(default=None, description="Registration Complete")
383
+ attending_onsite: bool | None = _Field(default=None, description="Attending Onsite")
384
+ dob: date | str | None = _Field(
385
+ default=None, union_mode="left_to_right", description="Date of Birth"
386
+ )
387
+ shirt_size: ShirtSize | str | None = _Field(
388
+ default=None, union_mode="left_to_right", description="Shirt Size"
389
+ )
390
+ country: str | None = _Field(default=None, description="Country")
391
+ twitter: str | None = _Field(default=None, description="Twitter")
392
+ team_member_inst_id: int | None = None
393
+ team_member_inst_name: str | None = _Field(default=None, description="Profile Institution Name")
394
+ area_of_study: str | None = _Field(default=None, description="Area Of Study")
395
+ degree_pursued: str | None = _Field(default=None, description="Degree Pursued")
396
+ began_degree: date | str | None = _Field(
397
+ default=None, union_mode="left_to_right", description="Began Degree"
398
+ )
399
+ expected_grad: date | str | None = _Field(
400
+ default=None, union_mode="left_to_right", description="Expected Graduation"
401
+ )
402
+ include_email: Consent | str | None = _Field(default=None, union_mode="left_to_right")
403
+ employment_opportunities: Consent | str | None = _Field(
404
+ default=None, union_mode="left_to_right", description="Interest - Employment Opportunities"
405
+ )
406
+ inform_other_contests: Consent | str | None = _Field(default=None, union_mode="left_to_right")
407
+ badge_name: str | None = _Field(default=None, description="Badge Name")
408
+ certificate_name: str | None = _Field(default=None, description="Certificate Name")
409
+ team_id: int | None = _Field(default=None, description="Team ID")
410
+ team_name: str | None = _Field(default=None, description="Team Name")
411
+ workstation_id: int | None = _Field(default=None, description="Workstation Id")
412
+ team_status: TeamStatus | str | None = _Field(
413
+ default=None, union_mode="left_to_right", description="Team Status"
414
+ )
415
+ team_rank: int | None = _Field(default=None, description="Team Rank")
416
+ extra_field: str | None = _Field(default=None, description="Extra Fields")
417
+ labels: str | None = _Field(default=None, description="Labels")
418
+ team_inst_id: int | None = None
419
+ team_inst_name: str | None = _Field(default=None, description="Team Institution Name")
420
+ team_inst_short_name: str | None = _Field(
421
+ default=None, description="Team Institution Short Name"
422
+ )
423
+ site_id: int | None = None
424
+ site_name: str | None = _Field(default=None, description="Site")
425
+
426
+
427
+ class TeamRow(HasTeamMembers, HasExtraFields, Row):
428
+ """Teams registered for a contest.
429
+
430
+ Returned by:
431
+ * ``/contest/search/contest/{contest_id}/team``
432
+ * ``/contest/search/site/{site_id}/teams``
433
+ """
434
+
435
+ id: int | None = _Field(default=None, description="Team Id")
436
+ name: str | None = _Field(default=None, description="Team Name")
437
+ team_members: str | None = _Field(default=None, description="Team Members")
438
+ status: TeamStatus | str | None = _Field(
439
+ default=None, union_mode="left_to_right", description="Status"
440
+ )
441
+ extended_state: str | None = _Field(default=None, description="Extended State")
442
+ paid: bool | None = _Field(default=None, description="Paid")
443
+ note: str | None = _Field(default=None, description="Note")
444
+ check_in: str | None = _Field(default=None, description="Check-In")
445
+ workstation_id: int | None = _Field(default=None, description="Workstation Id")
446
+ rank: int | None = _Field(default=None, description="Rank")
447
+ certified: bool | None = _Field(default=None, description="Certified")
448
+ eligibility_status: EligibilityStatus | str | None = _Field(
449
+ default=None, union_mode="left_to_right", description="Eligibility Status"
450
+ )
451
+ eligibility_issue: str | None = _Field(default=None, description="Eligibility Issue")
452
+ eligibility_comment: str | None = _Field(default=None, description="Eligibility Comment")
453
+ inst_id: int | None = None
454
+ inst_name: str | None = _Field(default=None, description="Institution Name")
455
+ inst_short_name: str | None = _Field(default=None, description="Institution Short Name")
456
+ inst_address: str | None = _Field(default=None, description="Institution Address")
457
+ city: str | None = _Field(default=None, description="Institution City")
458
+ country: str | None = _Field(default=None, description="Country")
459
+ a2: str | None = None
460
+ site: str | None = _Field(default=None, description="Site")
461
+ created_when: datetime | str | None = _Field(
462
+ default=None, union_mode="left_to_right", description="Created When"
463
+ )
464
+ extra_field: str | None = _Field(default=None, description="Extra Field")
465
+
466
+
467
+ class TeamSummaryRow(Row):
468
+ """Teams of a contest in the alternate shape used by the team grid: ``teamId``/``teamName`` rather than ``id``/``name``, plus promotion history.
469
+
470
+ Returned by:
471
+ * ``/team/search/{contest_id}/all``
472
+ * ``/contest/search/site/{site_id}/home/teams``
473
+ """
474
+
475
+ team_id: int | None = _Field(default=None, description="Team Id")
476
+ team_name: str | None = _Field(default=None, description="Team Name")
477
+ rank: int | None = _Field(default=None, description="Rank")
478
+ site_id: int | None = None
479
+ site_name: str | None = _Field(default=None, description="Site")
480
+ country: str | None = _Field(default=None, description="Country")
481
+ a2: str | None = None
482
+ inst_id: int | None = None
483
+ inst_name: str | None = _Field(default=None, description="Institution")
484
+ coach_id: int | None = None
485
+ coach_name: str | None = _Field(default=None, description="Coach")
486
+ promoted_from_team_id: int | None = None
487
+ promoted_from_team_name: str | None = _Field(default=None, description="Promoted from Team")
488
+ promoted_from_contest_id: int | None = None
489
+ promoted_from_contest_name: str | None = _Field(
490
+ default=None, description="Promoted from Contest"
491
+ )
492
+ created: datetime | str | None = _Field(
493
+ default=None, union_mode="left_to_right", description="Created"
494
+ )
495
+ status: TeamStatus | str | None = _Field(
496
+ default=None, union_mode="left_to_right", description="Status"
497
+ )
498
+ eligibility_id: int | None = None
499
+ eligibility_status: EligibilityStatus | str | None = _Field(
500
+ default=None, union_mode="left_to_right", description="Eligibility"
501
+ )
502
+ certified: bool | None = _Field(default=None, description="Certified")
503
+ paid: bool | None = _Field(default=None, description="Paid")
504
+ extended_state: str | None = _Field(default=None, description="Extended Status")
505
+
506
+
507
+ class Top20Row(Row):
508
+ """Top-20 participants of a contest.
509
+
510
+ Returned by:
511
+ * ``/contest/search/contest/{contest_id}/top20``
512
+ """
513
+
514
+ area: str | None = None
515
+ contest: str | None = None
516
+ contest_id: int | None = None
517
+ rank: int | None = None
518
+ team: str | None = None
519
+ team_id: int | None = None
520
+ role: str | None = None
521
+ institution: str | None = None
522
+ inst_id: int | None = None
523
+ first_name: str | None = None
524
+ last_name: str | None = None
525
+ username: str | None = None
526
+ user_id: int | None = None
527
+ inform: Consent | str | None = _Field(default=None, union_mode="left_to_right")
528
+
529
+
530
+ class TransportationMissingRow(Row):
531
+ """People who have not filled in their travel details.
532
+
533
+ Returned by:
534
+ * ``/contest/transportation/search/contest/{contest_id}/missing``
535
+ """
536
+
537
+ person_id: int | None = None
538
+ first_name: str | None = _Field(default=None, description="First Name")
539
+ last_name: str | None = _Field(default=None, description="Last Name")
540
+ attending_onsite: bool | None = _Field(default=None, description="Attending Onsite")
541
+ country_name: str | None = _Field(default=None, description="Country")
542
+ country_a2: str | None = None
543
+ email: str | None = _Field(default=None, description="Email")
544
+ modified_when: datetime | str | None = _Field(
545
+ default=None, union_mode="left_to_right", description="Modified"
546
+ )
547
+ participant_id: int | None = None
548
+ site_name: str | None = None
549
+ coach: bool | None = None
550
+
551
+
552
+ class TshirtRow(Row):
553
+ """Coach t-shirt sizes at a site.
554
+
555
+ Returned by:
556
+ * ``/contest/search/site/{site_id}/tshirt/coaches``
557
+ * ``/contest/search/site/{site_id}/tshirt/cocoaches``
558
+ * ``/contest/search/site/{site_id}/tshirt/contestants``
559
+ """
560
+
561
+ institution: str | None = _Field(default=None, description="Institution")
562
+ person_name: str | None = _Field(default=None, description="Name")
563
+ team_name: str | None = _Field(default=None, description="Team")
564
+ tshirt_size: ShirtSize | str | None = _Field(
565
+ default=None, union_mode="left_to_right", description="Shirt Size"
566
+ )
icpc/models/base.py ADDED
@@ -0,0 +1,41 @@
1
+ """Base model shared by every DTO and search row.
2
+
3
+ Two facts about this API drive the configuration:
4
+
5
+ * ``proj:`` does not shape the response — the full DTO always comes back with the
6
+ unprojected fields set to ``null``. So every field of a *search row* is
7
+ optional, always. The non-search endpoints in :mod:`icpc.models.entities` take
8
+ no projection, and the handful of fields observed never to be null there are
9
+ declared required; see that module.
10
+ * The frontend redeploys often and adds columns. ``extra="allow"`` means a new
11
+ server-side field lands in ``model_extra`` instead of breaking the parse.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+
18
+ from pydantic import BaseModel, ConfigDict
19
+ from pydantic.alias_generators import to_camel
20
+
21
+ __all__ = ["Row"]
22
+
23
+
24
+ class Row(BaseModel):
25
+ """A wire object: camelCase on the wire, snake_case in Python."""
26
+
27
+ model_config = ConfigDict(
28
+ alias_generator=to_camel,
29
+ populate_by_name=True,
30
+ extra="allow",
31
+ # Search rows are decoded a thousand at a time; skip re-validating models.
32
+ revalidate_instances="never",
33
+ )
34
+
35
+ def extra(self, name: str) -> Any:
36
+ """Read a field the server sent but this version of the SDK doesn't know."""
37
+ return (self.model_extra or {}).get(name)
38
+
39
+ def unknown_fields(self) -> dict[str, Any]:
40
+ """Fields present on the wire but absent from the model."""
41
+ return dict(self.model_extra or {})