xcpcio 0.65.0__tar.gz → 0.65.2__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.0 → xcpcio-0.65.2}/PKG-INFO +1 -1
  2. {xcpcio-0.65.0 → xcpcio-0.65.2}/tests/test_contest.py +10 -16
  3. {xcpcio-0.65.0 → xcpcio-0.65.2}/tests/test_submission.py +1 -2
  4. {xcpcio-0.65.0 → xcpcio-0.65.2}/tests/test_team.py +33 -5
  5. {xcpcio-0.65.0 → xcpcio-0.65.2}/tests/test_types.py +4 -4
  6. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/__version__.py +1 -1
  7. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/types.py +28 -25
  8. {xcpcio-0.65.0 → xcpcio-0.65.2}/.gitignore +0 -0
  9. {xcpcio-0.65.0 → xcpcio-0.65.2}/.python-version +0 -0
  10. {xcpcio-0.65.0 → xcpcio-0.65.2}/README.md +0 -0
  11. {xcpcio-0.65.0 → xcpcio-0.65.2}/pyproject.toml +0 -0
  12. {xcpcio-0.65.0 → xcpcio-0.65.2}/scripts/generate_ccs_models.sh +0 -0
  13. {xcpcio-0.65.0 → xcpcio-0.65.2}/tests/__init__.py +0 -0
  14. {xcpcio-0.65.0 → xcpcio-0.65.2}/uv.lock +0 -0
  15. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/__init__.py +0 -0
  16. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/api/__init__.py +0 -0
  17. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/api/client.py +0 -0
  18. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/api/models.py +0 -0
  19. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/app/clics_archiver.py +0 -0
  20. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/app/clics_server.py +0 -0
  21. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/__init__.py +0 -0
  22. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/__init__.py +0 -0
  23. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/app.py +0 -0
  24. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/dependencies.py +0 -0
  25. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/__init__.py +0 -0
  26. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/access.py +0 -0
  27. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/accounts.py +0 -0
  28. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/awards.py +0 -0
  29. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/clarifications.py +0 -0
  30. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/contests.py +0 -0
  31. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/general.py +0 -0
  32. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/groups.py +0 -0
  33. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/judgement_types.py +0 -0
  34. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/judgements.py +0 -0
  35. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/languages.py +0 -0
  36. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/organizations.py +0 -0
  37. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/problems.py +0 -0
  38. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/runs.py +0 -0
  39. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/submissions.py +0 -0
  40. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/routes/teams.py +0 -0
  41. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/server.py +0 -0
  42. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/services/__init__.py +0 -0
  43. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/api_server/services/contest_service.py +0 -0
  44. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/base/__init__.py +0 -0
  45. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/base/types.py +0 -0
  46. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/clics_api_client.py +0 -0
  47. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/contest_archiver.py +0 -0
  48. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/model/__init__.py +0 -0
  49. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/model/model_2023_06/__init__.py +0 -0
  50. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/model/model_2023_06/model.py +0 -0
  51. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/reader/__init__.py +0 -0
  52. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/reader/contest_package_reader.py +0 -0
  53. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/clics/reader/interface.py +0 -0
  54. {xcpcio-0.65.0 → xcpcio-0.65.2}/xcpcio/constants.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xcpcio
3
- Version: 0.65.0
3
+ Version: 0.65.2
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
@@ -15,8 +15,7 @@ class TestContest:
15
15
  assert contest.frozen_time == 60 * 60 # 1 hour
16
16
  assert contest.unfrozen_time == 0x3F3F3F3F3F3F3F3F
17
17
  assert contest.penalty == 20 * 60 # 20 minutes
18
- assert contest.problem_quantity == 0
19
- assert contest.problem_id == []
18
+ assert contest.problem_id is None
20
19
  assert contest.organization == "School"
21
20
  assert contest.medal is None
22
21
  assert contest.balloon_color is None
@@ -31,7 +30,7 @@ class TestContest:
31
30
 
32
31
  # Check default values
33
32
  assert contest.status_time_display == constants.FULL_STATUS_TIME_DISPLAY
34
- assert isinstance(contest.options, ContestOptions)
33
+ assert contest.options is None
35
34
 
36
35
  def test_contest_creation_with_values(self):
37
36
  """Test Contest creation with provided values"""
@@ -55,7 +54,6 @@ class TestContest:
55
54
  assert contest.contest_name == "ICPC World Finals 2024"
56
55
  assert contest.start_time == 1234567890
57
56
  assert contest.end_time == 1234567890 + 5 * 60 * 60
58
- assert contest.problem_quantity == 12
59
57
  assert len(contest.problem_id) == 12
60
58
  assert contest.problem_id[0] == "A"
61
59
  assert contest.problem_id[-1] == "L"
@@ -69,7 +67,6 @@ class TestContest:
69
67
  contest_name="Test Contest",
70
68
  start_time=1000000000,
71
69
  end_time=1000000000 + 60 * 60 * 5,
72
- problem_quantity=5,
73
70
  problem_id=["A", "B", "C", "D", "E"],
74
71
  organization="Test Org",
75
72
  )
@@ -78,7 +75,6 @@ class TestContest:
78
75
  contest_dict = contest.model_dump()
79
76
  assert contest_dict["contest_name"] == "Test Contest"
80
77
  assert contest_dict["start_time"] == 1000000000
81
- assert contest_dict["problem_quantity"] == 5
82
78
  assert contest_dict["organization"] == "Test Org"
83
79
 
84
80
  # Test JSON round-trip
@@ -97,7 +93,6 @@ class TestContest:
97
93
 
98
94
  contest = Contest(
99
95
  contest_name="Contest with Media",
100
- problem_quantity=2,
101
96
  balloon_color=colors,
102
97
  logo=logo,
103
98
  banner=banner,
@@ -135,32 +130,32 @@ class TestContest:
135
130
 
136
131
  def test_fill_problem_id(self):
137
132
  """Test fill_problem_id method"""
138
- contest = Contest(problem_quantity=5)
133
+ contest = Contest()
139
134
 
140
135
  # Initially empty
141
- assert contest.problem_id == []
136
+ assert contest.problem_id is None
142
137
 
143
138
  # Fill with A-E
144
- contest.fill_problem_id()
139
+ contest.fill_problem_id(5)
145
140
 
146
141
  assert len(contest.problem_id) == 5
147
142
  assert contest.problem_id == ["A", "B", "C", "D", "E"]
148
143
 
149
144
  # Test with larger quantity
150
- contest.problem_quantity = 10
151
- contest.fill_problem_id()
145
+ contest.fill_problem_id(10)
152
146
 
153
147
  assert len(contest.problem_id) == 10
154
148
  assert contest.problem_id == ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
155
149
 
156
150
  def test_fill_balloon_color(self):
157
151
  """Test fill_balloon_color method"""
158
- contest = Contest(problem_quantity=3)
152
+ contest = Contest()
159
153
 
160
154
  # Initially no colors
161
155
  assert contest.balloon_color is None
162
156
 
163
- # Fill with default colors
157
+ # Fill problem IDs first, then balloon colors
158
+ contest.fill_problem_id(3)
164
159
  contest.fill_balloon_color()
165
160
 
166
161
  assert contest.balloon_color is not None
@@ -180,13 +175,12 @@ class TestContest:
180
175
  contest_name="Complex Contest",
181
176
  start_time=1234567890,
182
177
  end_time=1234567890 + 5 * 60 * 60,
183
- problem_quantity=3,
184
178
  organization="Complex Org",
185
179
  medal="ccpc", # Use preset instead of dict
186
180
  )
187
181
 
188
182
  # Add problem IDs and colors
189
- contest.fill_problem_id()
183
+ contest.fill_problem_id(3)
190
184
  contest.fill_balloon_color()
191
185
 
192
186
  # Add logo
@@ -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"""
@@ -101,8 +101,8 @@ class TestSubmissionReaction:
101
101
 
102
102
  def test_reaction_empty(self):
103
103
  """Test SubmissionReaction with default values"""
104
- reaction = SubmissionReaction()
105
- assert reaction.url is None
104
+ reaction = SubmissionReaction(url="")
105
+ assert reaction.url == ""
106
106
 
107
107
  def test_reaction_with_url(self):
108
108
  """Test SubmissionReaction with URL"""
@@ -124,10 +124,10 @@ class TestSubmissionReaction:
124
124
 
125
125
  def test_reaction_no_url_serialization(self):
126
126
  """Test SubmissionReaction serialization with no URL"""
127
- reaction = SubmissionReaction()
127
+ reaction = SubmissionReaction(url="")
128
128
 
129
129
  reaction_dict = reaction.model_dump()
130
- assert reaction_dict["url"] is None
130
+ assert reaction_dict["url"] == ""
131
131
 
132
132
  # Test JSON round-trip
133
133
  reaction_json = reaction.model_dump_json()
@@ -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.0'
4
+ __version__ = VERSION = '0.65.2'
@@ -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
 
@@ -74,15 +74,6 @@ class I18NStringSet(BaseModel):
74
74
  Text = Union[str, I18NStringSet]
75
75
 
76
76
 
77
- class Person(BaseModel):
78
- name: Text
79
- cf_id: Optional[str] = None
80
- icpc_id: Optional[str] = None
81
-
82
-
83
- Persons = List[Person]
84
-
85
-
86
77
  class Image(BaseModel):
87
78
  url: Optional[str] = None
88
79
  base64: Optional[str] = None
@@ -95,12 +86,25 @@ class BalloonColor(BaseModel):
95
86
  background_color: str
96
87
 
97
88
 
89
+ class Person(BaseModel):
90
+ name: Text
91
+
92
+ cf_id: Optional[str] = None
93
+ icpc_id: Optional[str] = None
94
+
95
+
96
+ Persons = List[Person]
97
+
98
+
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
 
@@ -108,12 +112,11 @@ Problems = List[Problem]
108
112
 
109
113
 
110
114
  class SubmissionReaction(BaseModel):
111
- url: Optional[str] = None
115
+ url: str
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
@@ -129,7 +132,7 @@ class Submission(BaseModel):
129
132
 
130
133
 
131
134
  class Submissions(RootModel[List[Submission]]):
132
- root: List[Submission]
135
+ pass
133
136
 
134
137
 
135
138
  class Team(BaseModel):
@@ -138,7 +141,7 @@ class Team(BaseModel):
138
141
 
139
142
  organization: str = ""
140
143
  group: List[str] = Field(default_factory=list)
141
- tag: List[str] = Field(default_factory=list)
144
+ tag: Optional[List[str]] = None
142
145
 
143
146
  coaches: Optional[Union[Text, List[Text], Persons]] = None
144
147
  members: Optional[Union[Text, List[Text], Persons]] = None
@@ -148,7 +151,7 @@ class Team(BaseModel):
148
151
  location: Optional[str] = None
149
152
  icpc_id: Optional[str] = None
150
153
 
151
- extra: Dict[str, str] = Field(default_factory=dict)
154
+ extra: Dict[str, Any] = Field(default_factory=dict, exclude=True)
152
155
 
153
156
  def add_group(self, group: str):
154
157
  if group not in self.group:
@@ -179,14 +182,13 @@ class Contest(BaseModel):
179
182
 
180
183
  freeze_time: Optional[Union[int, DateTimeISO8601String]] = None
181
184
  frozen_time: int = 60 * 60 # unit: seconds
182
- unfrozen_time: int = 0x3F3F3F3F3F3F3F3F
183
185
 
184
186
  problems: Optional[Problems] = None
185
- problem_quantity: int = 0
186
- problem_id: List[str] = Field(default_factory=list)
187
+
188
+ problem_id: Optional[List[str]] = None
187
189
  balloon_color: Optional[List[BalloonColor]] = None
188
190
 
189
- status_time_display: Optional[Dict[str, bool]] = constants.FULL_STATUS_TIME_DISPLAY
191
+ status_time_display: Dict[str, bool] = constants.FULL_STATUS_TIME_DISPLAY
190
192
 
191
193
  badge: Optional[str] = None
192
194
  organization: str = "School"
@@ -203,7 +205,9 @@ class Contest(BaseModel):
203
205
 
204
206
  version: Optional[str] = None
205
207
 
206
- options: ContestOptions = Field(default_factory=ContestOptions)
208
+ options: Optional[ContestOptions] = None
209
+
210
+ unfrozen_time: int = Field(default=0x3F3F3F3F3F3F3F3F, exclude=True)
207
211
 
208
212
  def append_balloon_color(self, color: BalloonColor):
209
213
  if self.balloon_color is None:
@@ -211,8 +215,8 @@ class Contest(BaseModel):
211
215
  self.balloon_color.append(color)
212
216
  return self
213
217
 
214
- def fill_problem_id(self):
215
- self.problem_id = [chr(ord("A") + i) for i in range(self.problem_quantity)]
218
+ def fill_problem_id(self, problem_quantity: int):
219
+ self.problem_id = [chr(ord("A") + i) for i in range(problem_quantity)]
216
220
  return self
217
221
 
218
222
  def fill_balloon_color(self):
@@ -232,7 +236,6 @@ class Contest(BaseModel):
232
236
  BalloonColor(background_color="rgba(144, 238, 144, 0.7)", color="#000"),
233
237
  BalloonColor(background_color="rgba(77, 57, 0, 0.7)", color="#fff"),
234
238
  ]
235
-
236
- self.balloon_color = default_balloon_color_list[: self.problem_quantity]
239
+ self.balloon_color = default_balloon_color_list[: len(self.problem_id)]
237
240
 
238
241
  return self
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