xcpcio 0.76.8__tar.gz → 0.82.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.
- {xcpcio-0.76.8 → xcpcio-0.82.0}/PKG-INFO +1 -1
- {xcpcio-0.76.8 → xcpcio-0.82.0}/tests/test_contest.py +0 -7
- {xcpcio-0.76.8 → xcpcio-0.82.0}/tests/test_team.py +1 -1
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/__version__.py +1 -1
- xcpcio-0.82.0/xcpcio/clics/base/types.py +19 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/reader/contest_package_reader.py +23 -1
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/reader/interface.py +5 -1
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/types.py +13 -5
- xcpcio-0.76.8/xcpcio/clics/base/types.py +0 -9
- {xcpcio-0.76.8 → xcpcio-0.82.0}/.gitignore +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/.python-version +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/README.md +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/pyproject.toml +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/scripts/generate_ccs_models.sh +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/tests/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/tests/test_submission.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/tests/test_types.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/uv.lock +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/api/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/api/client.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/api/models.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/app/clics_archiver.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/app/clics_server.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/app/clics_uploader.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/app.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/dependencies.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/access.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/accounts.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/awards.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/clarifications.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/contests.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/general.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/groups.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/judgement_types.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/judgements.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/languages.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/organizations.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/problems.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/runs.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/submissions.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/routes/teams.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/server.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/services/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/api_server/services/contest_service.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/base/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/clics_api_client.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/contest_archiver.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/contest_uploader.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/model/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/model/model_2023_06/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/model/model_2023_06/model.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/clics/reader/__init__.py +0 -0
- {xcpcio-0.76.8 → xcpcio-0.82.0}/xcpcio/constants.py +0 -0
|
@@ -16,13 +16,11 @@ class TestContest:
|
|
|
16
16
|
assert contest.thaw_time == 0x3F3F3F3F3F3F3F3F
|
|
17
17
|
assert contest.penalty == 20 * 60 # 20 minutes
|
|
18
18
|
assert contest.problem_id is None
|
|
19
|
-
assert contest.organization == "School"
|
|
20
19
|
assert contest.medal is None
|
|
21
20
|
assert contest.balloon_color is None
|
|
22
21
|
assert contest.logo is None
|
|
23
22
|
assert contest.banner is None
|
|
24
23
|
assert contest.banner_mode is None
|
|
25
|
-
assert contest.badge is None
|
|
26
24
|
assert contest.group is None
|
|
27
25
|
assert contest.tag is None
|
|
28
26
|
assert contest.board_link is None
|
|
@@ -46,7 +44,6 @@ class TestContest:
|
|
|
46
44
|
penalty=20 * 60, # 20 minutes
|
|
47
45
|
problem_quantity=12,
|
|
48
46
|
problem_id=["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"],
|
|
49
|
-
organization="ICPC",
|
|
50
47
|
medal="icpc", # Use Literal value
|
|
51
48
|
options=contest_options,
|
|
52
49
|
)
|
|
@@ -57,7 +54,6 @@ class TestContest:
|
|
|
57
54
|
assert len(contest.problem_id) == 12
|
|
58
55
|
assert contest.problem_id[0] == "A"
|
|
59
56
|
assert contest.problem_id[-1] == "L"
|
|
60
|
-
assert contest.organization == "ICPC"
|
|
61
57
|
assert contest.medal == "icpc"
|
|
62
58
|
assert contest.options == contest_options
|
|
63
59
|
|
|
@@ -68,14 +64,12 @@ class TestContest:
|
|
|
68
64
|
start_time=1000000000,
|
|
69
65
|
end_time=1000000000 + 60 * 60 * 5,
|
|
70
66
|
problem_id=["A", "B", "C", "D", "E"],
|
|
71
|
-
organization="Test Org",
|
|
72
67
|
)
|
|
73
68
|
|
|
74
69
|
# Test model_dump
|
|
75
70
|
contest_dict = contest.model_dump()
|
|
76
71
|
assert contest_dict["contest_name"] == "Test Contest"
|
|
77
72
|
assert contest_dict["start_time"] == 1000000000
|
|
78
|
-
assert contest_dict["organization"] == "Test Org"
|
|
79
73
|
|
|
80
74
|
# Test JSON round-trip
|
|
81
75
|
contest_json = contest.model_dump_json()
|
|
@@ -175,7 +169,6 @@ class TestContest:
|
|
|
175
169
|
contest_name="Complex Contest",
|
|
176
170
|
start_time=1234567890,
|
|
177
171
|
end_time=1234567890 + 5 * 60 * 60,
|
|
178
|
-
organization="Complex Org",
|
|
179
172
|
medal="ccpc", # Use preset instead of dict
|
|
180
173
|
)
|
|
181
174
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class FileAttr:
|
|
8
|
+
path: Path
|
|
9
|
+
media_type: str
|
|
10
|
+
name: str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Image:
|
|
15
|
+
base64: str
|
|
16
|
+
|
|
17
|
+
mime_type: Optional[str] = None
|
|
18
|
+
width: Optional[int] = None
|
|
19
|
+
height: Optional[int] = None
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import base64
|
|
1
2
|
import bisect
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
@@ -7,12 +8,20 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
7
8
|
|
|
8
9
|
from fastapi import HTTPException
|
|
9
10
|
|
|
10
|
-
from xcpcio.clics.base.types import FileAttr
|
|
11
|
+
from xcpcio.clics.base.types import FileAttr, Image
|
|
11
12
|
from xcpcio.clics.reader.interface import BaseContestReader
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
def image_to_base64(image_path: Path):
|
|
18
|
+
with open(image_path, "rb") as image_file:
|
|
19
|
+
binary_data = image_file.read()
|
|
20
|
+
base64_bytes = base64.b64encode(binary_data)
|
|
21
|
+
base64_string = base64_bytes.decode("utf-8")
|
|
22
|
+
return base64_string
|
|
23
|
+
|
|
24
|
+
|
|
16
25
|
class ContestPackageReader(BaseContestReader):
|
|
17
26
|
def __init__(self, contest_package_dir: Path):
|
|
18
27
|
self.contest_package_dir = contest_package_dir
|
|
@@ -239,6 +248,19 @@ class ContestPackageReader(BaseContestReader):
|
|
|
239
248
|
detail=f"Organization logo not found. [contest_id={self.contest_id}] [organization_id={organization_id}] [err={e}]",
|
|
240
249
|
)
|
|
241
250
|
|
|
251
|
+
def get_organization_logo_image(self, organization_id: str) -> Optional[Image]:
|
|
252
|
+
org_list = self.get_organization(organization_id).get("logo", [])
|
|
253
|
+
if len(org_list) == 0:
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
org: Dict = org_list[0]
|
|
257
|
+
return Image(
|
|
258
|
+
base64=image_to_base64(self.contest_package_dir / f"organizations/{organization_id}/{org['filename']}"),
|
|
259
|
+
mime_type=str(org.get("mime")),
|
|
260
|
+
width=int(org.get("width")),
|
|
261
|
+
height=int(org.get("height")),
|
|
262
|
+
)
|
|
263
|
+
|
|
242
264
|
# Group operations
|
|
243
265
|
def get_groups(self) -> List[Dict[str, Any]]:
|
|
244
266
|
return self.groups
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from typing import Any, Dict, List, Optional
|
|
3
3
|
|
|
4
|
-
from xcpcio.clics.base.types import FileAttr
|
|
4
|
+
from xcpcio.clics.base.types import FileAttr, Image
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class BaseContestReader(ABC):
|
|
@@ -83,6 +83,10 @@ class BaseContestReader(ABC):
|
|
|
83
83
|
def get_organization_logo(self, organization_id: str) -> FileAttr:
|
|
84
84
|
pass
|
|
85
85
|
|
|
86
|
+
@abstractmethod
|
|
87
|
+
def get_organization_logo_image(self, organization_id: str) -> Optional[Image]:
|
|
88
|
+
pass
|
|
89
|
+
|
|
86
90
|
# Group operations
|
|
87
91
|
@abstractmethod
|
|
88
92
|
def get_groups(self) -> List[Dict[str, Any]]:
|
|
@@ -98,9 +98,11 @@ class Organization(BaseModel):
|
|
|
98
98
|
name: Text
|
|
99
99
|
|
|
100
100
|
logo: Optional[Image] = None
|
|
101
|
+
icpc_id: Optional[str] = None
|
|
101
102
|
|
|
102
103
|
|
|
103
|
-
Organizations
|
|
104
|
+
class Organizations(RootModel[List[Organization]]):
|
|
105
|
+
pass
|
|
104
106
|
|
|
105
107
|
|
|
106
108
|
class BalloonColor(BaseModel):
|
|
@@ -162,7 +164,7 @@ class Team(BaseModel):
|
|
|
162
164
|
id: str = ""
|
|
163
165
|
name: Text = ""
|
|
164
166
|
|
|
165
|
-
organization: str =
|
|
167
|
+
organization: Optional[str] = None
|
|
166
168
|
organization_id: Optional[str] = None
|
|
167
169
|
|
|
168
170
|
group: List[str] = Field(default_factory=list)
|
|
@@ -197,6 +199,7 @@ class Teams(RootModel[List[Team]]):
|
|
|
197
199
|
|
|
198
200
|
|
|
199
201
|
class ContestOptions(BaseModel):
|
|
202
|
+
enable_organization: Optional[bool] = None
|
|
200
203
|
calculation_of_penalty: Optional[CalculationOfPenalty] = None
|
|
201
204
|
submission_timestamp_unit: Optional[TimeUnit] = None
|
|
202
205
|
|
|
@@ -204,6 +207,14 @@ class ContestOptions(BaseModel):
|
|
|
204
207
|
reaction_video_url_template: Optional[str] = None
|
|
205
208
|
|
|
206
209
|
team_photo_url_template: Optional[Image] = None
|
|
210
|
+
team_webcam_stream_url_template: Optional[str] = None
|
|
211
|
+
team_screen_stream_url_template: Optional[str] = None
|
|
212
|
+
|
|
213
|
+
submission_external_url_template: Optional[str] = None
|
|
214
|
+
submission_source_code_url_template: Optional[str] = None
|
|
215
|
+
|
|
216
|
+
realtime_reaction_webcam_stream_url_template: Optional[str] = None
|
|
217
|
+
realtime_reaction_screen_stream_url_template: Optional[str] = None
|
|
207
218
|
|
|
208
219
|
|
|
209
220
|
class Contest(BaseModel):
|
|
@@ -225,9 +236,6 @@ class Contest(BaseModel):
|
|
|
225
236
|
|
|
226
237
|
status_time_display: Dict[str, bool] = constants.FULL_STATUS_TIME_DISPLAY
|
|
227
238
|
|
|
228
|
-
badge: Optional[str] = None
|
|
229
|
-
organization: str = "School"
|
|
230
|
-
|
|
231
239
|
medal: Optional[Union[Dict[str, Dict[str, int]], MedalPreset]] = None
|
|
232
240
|
|
|
233
241
|
group: Optional[Dict[str, str]] = 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
|
|
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
|
|
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
|
|
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
|