xcpcio 0.65.1__tar.gz → 0.66.0__tar.gz

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.

Potentially problematic release.


This version of xcpcio might be problematic. Click here for more details.

Files changed (54) hide show
  1. {xcpcio-0.65.1 → xcpcio-0.66.0}/PKG-INFO +1 -1
  2. {xcpcio-0.65.1 → xcpcio-0.66.0}/tests/test_contest.py +1 -1
  3. {xcpcio-0.65.1 → xcpcio-0.66.0}/tests/test_submission.py +1 -2
  4. {xcpcio-0.65.1 → xcpcio-0.66.0}/tests/test_team.py +33 -5
  5. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/__version__.py +1 -1
  6. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/reader/contest_package_reader.py +7 -7
  7. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/types.py +14 -6
  8. {xcpcio-0.65.1 → xcpcio-0.66.0}/.gitignore +0 -0
  9. {xcpcio-0.65.1 → xcpcio-0.66.0}/.python-version +0 -0
  10. {xcpcio-0.65.1 → xcpcio-0.66.0}/README.md +0 -0
  11. {xcpcio-0.65.1 → xcpcio-0.66.0}/pyproject.toml +0 -0
  12. {xcpcio-0.65.1 → xcpcio-0.66.0}/scripts/generate_ccs_models.sh +0 -0
  13. {xcpcio-0.65.1 → xcpcio-0.66.0}/tests/__init__.py +0 -0
  14. {xcpcio-0.65.1 → xcpcio-0.66.0}/tests/test_types.py +0 -0
  15. {xcpcio-0.65.1 → xcpcio-0.66.0}/uv.lock +0 -0
  16. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/__init__.py +0 -0
  17. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/api/__init__.py +0 -0
  18. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/api/client.py +0 -0
  19. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/api/models.py +0 -0
  20. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/app/clics_archiver.py +0 -0
  21. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/app/clics_server.py +0 -0
  22. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/__init__.py +0 -0
  23. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/__init__.py +0 -0
  24. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/app.py +0 -0
  25. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/dependencies.py +0 -0
  26. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/__init__.py +0 -0
  27. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/access.py +0 -0
  28. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/accounts.py +0 -0
  29. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/awards.py +0 -0
  30. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/clarifications.py +0 -0
  31. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/contests.py +0 -0
  32. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/general.py +0 -0
  33. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/groups.py +0 -0
  34. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/judgement_types.py +0 -0
  35. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/judgements.py +0 -0
  36. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/languages.py +0 -0
  37. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/organizations.py +0 -0
  38. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/problems.py +0 -0
  39. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/runs.py +0 -0
  40. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/submissions.py +0 -0
  41. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/routes/teams.py +0 -0
  42. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/server.py +0 -0
  43. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/services/__init__.py +0 -0
  44. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/api_server/services/contest_service.py +0 -0
  45. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/base/__init__.py +0 -0
  46. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/base/types.py +0 -0
  47. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/clics_api_client.py +0 -0
  48. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/contest_archiver.py +0 -0
  49. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/model/__init__.py +0 -0
  50. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/model/model_2023_06/__init__.py +0 -0
  51. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/model/model_2023_06/model.py +0 -0
  52. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/reader/__init__.py +0 -0
  53. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/clics/reader/interface.py +0 -0
  54. {xcpcio-0.65.1 → xcpcio-0.66.0}/xcpcio/constants.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xcpcio
3
- Version: 0.65.1
3
+ Version: 0.66.0
4
4
  Summary: xcpcio python lib
5
5
  Project-URL: homepage, https://github.com/xcpcio/xcpcio
6
6
  Project-URL: documentation, https://github.com/xcpcio/xcpcio
@@ -30,7 +30,7 @@ class TestContest:
30
30
 
31
31
  # Check default values
32
32
  assert contest.status_time_display == constants.FULL_STATUS_TIME_DISPLAY
33
- assert isinstance(contest.options, ContestOptions)
33
+ assert contest.options is None
34
34
 
35
35
  def test_contest_creation_with_values(self):
36
36
  """Test Contest creation with provided values"""
@@ -13,7 +13,6 @@ class TestSubmission:
13
13
  """Test Submission creation with default values"""
14
14
  submission = Submission()
15
15
  assert submission.id is None
16
- assert submission.submission_id is None
17
16
  assert submission.team_id == ""
18
17
  assert submission.problem_id == 0
19
18
  assert submission.timestamp == 0
@@ -215,7 +214,7 @@ class TestSubmissions:
215
214
  problem_id=1,
216
215
  timestamp=123,
217
216
  ),
218
- Submission(), # All defaults
217
+ Submission(id="sub_default"), # All other defaults
219
218
  ]
220
219
  )
221
220
 
@@ -93,14 +93,21 @@ class TestTeamSerialization:
93
93
  assert team_dict["coaches"] == "Dr. Smith"
94
94
  assert team_dict["location"] == "Building A"
95
95
  assert team_dict["group"] == ["undergraduate", "local"]
96
- assert team_dict["extra"] == {"room": "101", "contact": "alice@test.edu"}
96
+ assert "extra" not in team_dict # extra field is excluded from serialization
97
97
 
98
98
  def test_model_validate(self, sample_team: Team):
99
99
  """Test Team model_validate method"""
100
100
  team_dict = sample_team.model_dump()
101
101
  reconstructed_team = Team.model_validate(team_dict)
102
102
 
103
- assert reconstructed_team == sample_team
103
+ assert reconstructed_team.id == sample_team.id
104
+ assert reconstructed_team.name == sample_team.name
105
+ assert reconstructed_team.organization == sample_team.organization
106
+ assert reconstructed_team.members == sample_team.members
107
+ assert reconstructed_team.coaches == sample_team.coaches
108
+ assert reconstructed_team.location == sample_team.location
109
+ assert reconstructed_team.group == sample_team.group
110
+ assert reconstructed_team.extra == {} # extra is not serialized
104
111
 
105
112
  def test_model_dump_json(self, sample_team: Team):
106
113
  """Test Team model_dump_json method"""
@@ -117,21 +124,42 @@ class TestTeamSerialization:
117
124
  team_json = sample_team.model_dump_json()
118
125
  reconstructed_team = Team.model_validate_json(team_json)
119
126
 
120
- assert reconstructed_team == sample_team
127
+ assert reconstructed_team.id == sample_team.id
128
+ assert reconstructed_team.name == sample_team.name
129
+ assert reconstructed_team.organization == sample_team.organization
130
+ assert reconstructed_team.members == sample_team.members
131
+ assert reconstructed_team.coaches == sample_team.coaches
132
+ assert reconstructed_team.location == sample_team.location
133
+ assert reconstructed_team.group == sample_team.group
134
+ assert reconstructed_team.extra == {} # extra is not serialized
121
135
 
122
136
  def test_round_trip_dict(self, sample_team: Team):
123
137
  """Test complete round-trip through dict serialization"""
124
138
  team_dict = sample_team.model_dump()
125
139
  reconstructed_team = Team.model_validate(team_dict)
126
140
 
127
- assert reconstructed_team == sample_team
141
+ assert reconstructed_team.id == sample_team.id
142
+ assert reconstructed_team.name == sample_team.name
143
+ assert reconstructed_team.organization == sample_team.organization
144
+ assert reconstructed_team.members == sample_team.members
145
+ assert reconstructed_team.coaches == sample_team.coaches
146
+ assert reconstructed_team.location == sample_team.location
147
+ assert reconstructed_team.group == sample_team.group
148
+ assert reconstructed_team.extra == {} # extra is excluded and won't round-trip
128
149
 
129
150
  def test_round_trip_json(self, sample_team: Team):
130
151
  """Test complete round-trip through JSON serialization"""
131
152
  team_json = sample_team.model_dump_json()
132
153
  reconstructed_team = Team.model_validate_json(team_json)
133
154
 
134
- assert reconstructed_team == sample_team
155
+ assert reconstructed_team.id == sample_team.id
156
+ assert reconstructed_team.name == sample_team.name
157
+ assert reconstructed_team.organization == sample_team.organization
158
+ assert reconstructed_team.members == sample_team.members
159
+ assert reconstructed_team.coaches == sample_team.coaches
160
+ assert reconstructed_team.location == sample_team.location
161
+ assert reconstructed_team.group == sample_team.group
162
+ assert reconstructed_team.extra == {} # extra is excluded and won't round-trip
135
163
 
136
164
  def test_minimal_team_serialization(self):
137
165
  """Test serialization of team with default/minimal values"""
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.65.1'
4
+ __version__ = VERSION = '0.66.0'
@@ -54,15 +54,15 @@ class ContestPackageReader(BaseContestReader):
54
54
  self.access = self._load_json_file("access.json")
55
55
 
56
56
  self.accounts = self._load_json_file("accounts.json")
57
- self.accounts_by_id = {account["id"] for account in self.accounts}
57
+ self.accounts_by_id = {account["id"]: account for account in self.accounts}
58
58
 
59
59
  self.api_info = self._load_json_file("api.json")
60
60
 
61
61
  self.awards = self._load_json_file("awards.json")
62
- self.awards_by_id = {award["id"] for award in self.awards}
62
+ self.awards_by_id = {award["id"]: award for award in self.awards}
63
63
 
64
64
  self.clarifications = self._load_json_file("clarifications.json")
65
- self.clarifications_by_id = {clarification["id"] for clarification in self.clarifications}
65
+ self.clarifications_by_id = {clarification["id"]: clarification for clarification in self.clarifications}
66
66
 
67
67
  self.contest = self._load_json_file("contest.json")
68
68
  self.contest_state = self._load_json_file("state.json")
@@ -71,14 +71,14 @@ class ContestPackageReader(BaseContestReader):
71
71
  self.groups_by_id = {group["id"]: group for group in self.groups}
72
72
 
73
73
  self.judgement_types = self._load_json_file("judgement-types.json")
74
- self.judgement_types_by_id = {judgement_type["id"] for judgement_type in self.judgement_types}
74
+ self.judgement_types_by_id = {judgement_type["id"]: judgement_type for judgement_type in self.judgement_types}
75
75
 
76
76
  self.judgements = self._load_json_file("judgements.json")
77
- self.judgements_by_id = {judgement["id"] for judgement in self.judgements}
77
+ self.judgements_by_id = {judgement["id"]: judgement for judgement in self.judgements}
78
78
  self.judgements_by_submission_id = self._create_index_by_id(self.judgements, "submission_id")
79
79
 
80
80
  self.languages = self._load_json_file("languages.json")
81
- self.languages_by_id = {language["id"] for language in self.languages}
81
+ self.languages_by_id = {language["id"]: language for language in self.languages}
82
82
 
83
83
  self.organizations = self._load_json_file("organizations.json")
84
84
  self.organizations_by_id = {org["id"]: org for org in self.organizations}
@@ -87,7 +87,7 @@ class ContestPackageReader(BaseContestReader):
87
87
  self.problems_by_id = {problem["id"]: problem for problem in self.problems}
88
88
 
89
89
  self.runs = self._load_json_file("runs.json")
90
- self.runs_by_id = {run["id"] for run in self.runs}
90
+ self.runs_by_id = {run["id"]: run for run in self.runs}
91
91
  self.runs_by_judgement_id = self._create_index_by_id(self.runs, "judgement_id")
92
92
 
93
93
  self.submissions = self._load_json_file("submissions.json")
@@ -1,4 +1,4 @@
1
- from typing import Dict, List, Literal, Optional, Union
1
+ from typing import Any, Dict, List, Literal, Optional, Union
2
2
 
3
3
  from pydantic import BaseModel, Field, RootModel
4
4
 
@@ -88,6 +88,7 @@ class BalloonColor(BaseModel):
88
88
 
89
89
  class Person(BaseModel):
90
90
  name: Text
91
+
91
92
  cf_id: Optional[str] = None
92
93
  icpc_id: Optional[str] = None
93
94
 
@@ -98,9 +99,12 @@ Persons = List[Person]
98
99
  class Problem(BaseModel):
99
100
  id: str
100
101
  label: str
102
+
101
103
  name: Optional[Text] = None
104
+
102
105
  time_limit: Optional[str] = None
103
106
  memory_limit: Optional[str] = None
107
+
104
108
  balloon_color: Optional[BalloonColor] = None
105
109
 
106
110
 
@@ -112,8 +116,7 @@ class SubmissionReaction(BaseModel):
112
116
 
113
117
 
114
118
  class Submission(BaseModel):
115
- id: Optional[str] = None
116
- submission_id: Optional[str] = None
119
+ id: str = None
117
120
 
118
121
  team_id: str = ""
119
122
  problem_id: Union[int, str] = 0
@@ -144,11 +147,12 @@ class Team(BaseModel):
144
147
  members: Optional[Union[Text, List[Text], Persons]] = None
145
148
 
146
149
  badge: Optional[Image] = None
150
+ photo: Optional[Image] = None
147
151
 
148
152
  location: Optional[str] = None
149
153
  icpc_id: Optional[str] = None
150
154
 
151
- extra: Dict[str, str] = Field(default_factory=dict)
155
+ extra: Dict[str, Any] = Field(default_factory=dict, exclude=True)
152
156
 
153
157
  def add_group(self, group: str):
154
158
  if group not in self.group:
@@ -166,9 +170,13 @@ class Teams(RootModel[List[Team]]):
166
170
  class ContestOptions(BaseModel):
167
171
  calculation_of_penalty: Optional[CalculationOfPenalty] = None
168
172
  submission_timestamp_unit: Optional[TimeUnit] = None
173
+
169
174
  has_reaction_videos: Optional[bool] = None
170
175
  reaction_video_url_template: Optional[str] = None
171
176
 
177
+ has_team_photos: Optional[bool] = None
178
+ team_photo_url_template: Optional[Image] = None
179
+
172
180
 
173
181
  class Contest(BaseModel):
174
182
  contest_name: Text = ""
@@ -202,9 +210,9 @@ class Contest(BaseModel):
202
210
 
203
211
  version: Optional[str] = None
204
212
 
205
- options: ContestOptions = Field(default_factory=ContestOptions)
213
+ options: Optional[ContestOptions] = None
206
214
 
207
- unfrozen_time: int = 0x3F3F3F3F3F3F3F3F
215
+ unfrozen_time: int = Field(default=0x3F3F3F3F3F3F3F3F, exclude=True)
208
216
 
209
217
  def append_balloon_color(self, color: BalloonColor):
210
218
  if self.balloon_color is None:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes