xcpcio 0.63.2__tar.gz → 0.63.4__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.
- xcpcio-0.63.4/.gitignore +8 -0
- xcpcio-0.63.4/.python-version +1 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/PKG-INFO +12 -6
- xcpcio-0.63.4/cli/ccs_archiver_cli.py +122 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/pyproject.toml +21 -2
- xcpcio-0.63.4/scripts/generate_ccs_models.sh +69 -0
- xcpcio-0.63.4/tests/__init__.py +0 -0
- xcpcio-0.63.4/uv.lock +1551 -0
- xcpcio-0.63.4/xcpcio/__init__.py +4 -0
- xcpcio-0.63.4/xcpcio/__version__.py +1 -0
- xcpcio-0.63.4/xcpcio/ccs/__init__.py +3 -0
- xcpcio-0.63.4/xcpcio/ccs/contest_archiver.py +439 -0
- xcpcio-0.63.2/setup.cfg +0 -4
- xcpcio-0.63.2/xcpcio/__init__.py +0 -5
- xcpcio-0.63.2/xcpcio/ccs/__init__.py +0 -3
- xcpcio-0.63.2/xcpcio.egg-info/PKG-INFO +0 -21
- xcpcio-0.63.2/xcpcio.egg-info/SOURCES.txt +0 -18
- xcpcio-0.63.2/xcpcio.egg-info/dependency_links.txt +0 -1
- xcpcio-0.63.2/xcpcio.egg-info/requires.txt +0 -1
- xcpcio-0.63.2/xcpcio.egg-info/top_level.txt +0 -1
- {xcpcio-0.63.2 → xcpcio-0.63.4}/README.md +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/tests/test_contest.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/tests/test_submission.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/tests/test_team.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/tests/test_types.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/xcpcio/ccs/model/__init__.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/xcpcio/ccs/model/model_2023_06/__init__.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/xcpcio/ccs/model/model_2023_06/model.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/xcpcio/constants.py +0 -0
- {xcpcio-0.63.2 → xcpcio-0.63.4}/xcpcio/types.py +0 -0
xcpcio-0.63.4/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12.11
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xcpcio
|
|
3
|
-
Version: 0.63.
|
|
3
|
+
Version: 0.63.4
|
|
4
4
|
Summary: xcpcio python lib
|
|
5
|
-
Author-email: Dup4 <hi@dup4.com>
|
|
6
|
-
License-Expression: MIT
|
|
7
5
|
Project-URL: homepage, https://github.com/xcpcio/xcpcio
|
|
8
6
|
Project-URL: documentation, https://github.com/xcpcio/xcpcio
|
|
9
7
|
Project-URL: repository, https://github.com/xcpcio/xcpcio
|
|
8
|
+
Author-email: Dup4 <hi@dup4.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
10
|
Keywords: xcpcio
|
|
11
|
-
Classifier: Topic :: Software Development :: Build Tools
|
|
12
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
13
11
|
Classifier: Programming Language :: Python :: 3
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
17
|
Requires-Python: >=3.11
|
|
18
|
-
|
|
18
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
19
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
20
|
+
Requires-Dist: click>=8.0.0
|
|
19
21
|
Requires-Dist: pydantic>=2.11.7
|
|
22
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
23
|
+
Requires-Dist: semver>=3.0.0
|
|
24
|
+
Requires-Dist: tenacity>=8.0.0
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
20
26
|
|
|
21
27
|
# xcpcio-python
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from xcpcio.ccs.contest_archiver import APICredentials, ArchiveConfig, ContestArchiver
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def setup_logging(level: str = "INFO"):
|
|
12
|
+
"""Setup logging configuration"""
|
|
13
|
+
logging.basicConfig(
|
|
14
|
+
level=getattr(logging, level.upper()),
|
|
15
|
+
format="%(asctime)s [%(name)s] %(filename)s:%(lineno)d %(levelname)s: %(message)s",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.command()
|
|
20
|
+
@click.option("--base-url", required=True, help="Base URL of the CCS API (e.g., https://example.com/api)")
|
|
21
|
+
@click.option("--contest-id", required=True, help="Contest ID to dump")
|
|
22
|
+
@click.option(
|
|
23
|
+
"--output-dir", required=True, type=click.Path(path_type=Path), help="Output directory for contest package"
|
|
24
|
+
)
|
|
25
|
+
@click.option("--username", "-u", help="HTTP Basic Auth username")
|
|
26
|
+
@click.option("--password", "-p", help="HTTP Basic Auth password")
|
|
27
|
+
@click.option("--token", "-t", help="Bearer token for authentication")
|
|
28
|
+
@click.option("--no-files", is_flag=True, help="Skip downloading files")
|
|
29
|
+
@click.option("--no-event-feed", is_flag=True, help="Skip dump event-feed(large aggregated data)")
|
|
30
|
+
@click.option("--endpoints", "-e", multiple=True, help="Specific endpoints to dump (can be used multiple times)")
|
|
31
|
+
@click.option("--timeout", default=30, type=int, help="Request timeout in seconds")
|
|
32
|
+
@click.option("--max-concurrent", default=10, type=int, help="Max concurrent requests")
|
|
33
|
+
@click.option(
|
|
34
|
+
"--log-level",
|
|
35
|
+
default="INFO",
|
|
36
|
+
type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR"], case_sensitive=False),
|
|
37
|
+
help="Log level",
|
|
38
|
+
)
|
|
39
|
+
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose logging (same as --log-level DEBUG)")
|
|
40
|
+
def main(
|
|
41
|
+
base_url: str,
|
|
42
|
+
contest_id: str,
|
|
43
|
+
output_dir: Path,
|
|
44
|
+
username: Optional[str],
|
|
45
|
+
password: Optional[str],
|
|
46
|
+
token: Optional[str],
|
|
47
|
+
no_files: bool,
|
|
48
|
+
no_event_feed: bool,
|
|
49
|
+
endpoints: tuple,
|
|
50
|
+
timeout: int,
|
|
51
|
+
max_concurrent: int,
|
|
52
|
+
log_level: str,
|
|
53
|
+
verbose: bool,
|
|
54
|
+
):
|
|
55
|
+
"""
|
|
56
|
+
Archive CCS Contest API data to contest package format.
|
|
57
|
+
|
|
58
|
+
This tool fetches contest data from a CCS API and organizes it into the standard
|
|
59
|
+
contest package format as specified by the CCS Contest Package specification.
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
|
|
63
|
+
# Basic usage with authentication
|
|
64
|
+
ccs-archiver --base-url https://api.example.com/api --contest-id contest123 --output-dir ./output --username admin --password secret
|
|
65
|
+
|
|
66
|
+
# Use bearer token authentication
|
|
67
|
+
ccs-archiver --base-url https://api.example.com/api --contest-id contest123 --output-dir ./output --token abc123
|
|
68
|
+
|
|
69
|
+
# Only archive specific endpoints
|
|
70
|
+
ccs-archiver --base-url https://api.example.com/api --contest-id contest123 --output-dir ./output -u admin -p secret -e teams -e problems
|
|
71
|
+
|
|
72
|
+
# Skip file downloads
|
|
73
|
+
ccs-archiver --base-url https://api.example.com/api --contest-id contest123 --output-dir ./output --no-files
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
if verbose:
|
|
77
|
+
log_level = "DEBUG"
|
|
78
|
+
|
|
79
|
+
setup_logging(log_level)
|
|
80
|
+
|
|
81
|
+
# Validate authentication
|
|
82
|
+
if not (username and password) and not token:
|
|
83
|
+
click.echo("Warning: No authentication provided. Some endpoints may not be accessible.", err=True)
|
|
84
|
+
|
|
85
|
+
# Setup configuration
|
|
86
|
+
credentials = APICredentials(username=username, password=password, token=token)
|
|
87
|
+
|
|
88
|
+
config = ArchiveConfig(
|
|
89
|
+
base_url=base_url.rstrip("/"), # Remove trailing slash
|
|
90
|
+
contest_id=contest_id,
|
|
91
|
+
credentials=credentials,
|
|
92
|
+
output_dir=output_dir,
|
|
93
|
+
include_files=not no_files,
|
|
94
|
+
endpoints=list(endpoints) if endpoints else None,
|
|
95
|
+
timeout=timeout,
|
|
96
|
+
max_concurrent=max_concurrent,
|
|
97
|
+
include_event_feed=not no_event_feed,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
click.echo(f"Archiving contest '{contest_id}' from {base_url}")
|
|
101
|
+
click.echo(f"Output directory: {output_dir}")
|
|
102
|
+
if config.endpoints:
|
|
103
|
+
click.echo(f"Endpoints: {', '.join(config.endpoints)}")
|
|
104
|
+
|
|
105
|
+
# Run the archiver
|
|
106
|
+
async def run_archive():
|
|
107
|
+
async with ContestArchiver(config) as archiver:
|
|
108
|
+
await archiver.dump_all()
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
asyncio.run(run_archive())
|
|
112
|
+
click.echo(click.style(f"Contest package created successfully in: {config.output_dir}", fg="green"))
|
|
113
|
+
except KeyboardInterrupt:
|
|
114
|
+
click.echo(click.style("Archive interrupted by user", fg="yellow"), err=True)
|
|
115
|
+
raise click.Abort()
|
|
116
|
+
except Exception as e:
|
|
117
|
+
click.echo(click.style(f"Error during archive: {e}", fg="red"), err=True)
|
|
118
|
+
raise click.ClickException(str(e))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
main()
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "xcpcio"
|
|
3
|
-
version = "0.63.2"
|
|
4
3
|
description = "xcpcio python lib"
|
|
5
4
|
readme = "README.md"
|
|
6
5
|
authors = [ { name = "Dup4", email = "hi@dup4.com" } ]
|
|
@@ -15,19 +14,39 @@ classifiers = [
|
|
|
15
14
|
"Programming Language :: Python :: 3.13",
|
|
16
15
|
]
|
|
17
16
|
requires-python = ">=3.11"
|
|
18
|
-
dependencies = [
|
|
17
|
+
dependencies = [
|
|
18
|
+
"pydantic>=2.11.7",
|
|
19
|
+
"aiohttp>=3.8.0",
|
|
20
|
+
"aiofiles>=23.0.0",
|
|
21
|
+
"click>=8.0.0",
|
|
22
|
+
"pyyaml>=6.0.0",
|
|
23
|
+
"semver>=3.0.0",
|
|
24
|
+
"tenacity>=8.0.0",
|
|
25
|
+
]
|
|
26
|
+
dynamic = ["version"]
|
|
19
27
|
|
|
20
28
|
[project.urls]
|
|
21
29
|
homepage = "https://github.com/xcpcio/xcpcio"
|
|
22
30
|
documentation = "https://github.com/xcpcio/xcpcio"
|
|
23
31
|
repository = "https://github.com/xcpcio/xcpcio"
|
|
24
32
|
|
|
33
|
+
[project.scripts]
|
|
34
|
+
ccs-archiver = "cli.ccs_archiver_cli:main"
|
|
35
|
+
|
|
25
36
|
[tool.ruff]
|
|
26
37
|
line-length = 120
|
|
27
38
|
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["hatchling"]
|
|
41
|
+
build-backend = "hatchling.build"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.version]
|
|
44
|
+
path = "xcpcio/__version__.py"
|
|
45
|
+
|
|
28
46
|
[dependency-groups]
|
|
29
47
|
dev = [
|
|
30
48
|
"datamodel-code-generator[http]>=0.33.0",
|
|
49
|
+
"hatch>=1.14.2",
|
|
31
50
|
"pytest>=8.4.2",
|
|
32
51
|
"ruff>=0.4.0",
|
|
33
52
|
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
CUR_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
|
|
6
|
+
PYTHON_DIR="$(dirname "${CUR_DIR}")"
|
|
7
|
+
CCS_SPECS_DIR="${PYTHON_DIR}/ccs-specs"
|
|
8
|
+
CCS_MODELS_DIR="${PYTHON_DIR}/xcpcio/ccs/model"
|
|
9
|
+
|
|
10
|
+
BRANCH="${1:-2023-06}"
|
|
11
|
+
CCS_REPO_URL="https://github.com/icpc/ccs-specs.git"
|
|
12
|
+
|
|
13
|
+
MODEL_DIR_NAME="model_${BRANCH//-/_}"
|
|
14
|
+
OUTPUT_DIR="${CCS_MODELS_DIR}/${MODEL_DIR_NAME}"
|
|
15
|
+
|
|
16
|
+
if [[ -d "${CCS_SPECS_DIR}" ]]; then
|
|
17
|
+
echo "Please remove existing ${CCS_SPECS_DIR} directory first"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
if [[ -d "${OUTPUT_DIR}" ]]; then
|
|
22
|
+
echo "Please remove existing ${OUTPUT_DIR} directory first"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
echo "Generating CCS models for branch: ${BRANCH}"
|
|
27
|
+
|
|
28
|
+
pushd "${PYTHON_DIR}"
|
|
29
|
+
|
|
30
|
+
echo "Cloning CCS specs repository (branch: ${BRANCH})..."
|
|
31
|
+
git clone --branch "${BRANCH}" --depth 1 "${CCS_REPO_URL}" ccs-specs
|
|
32
|
+
|
|
33
|
+
echo "Creating output directory: ${OUTPUT_DIR}"
|
|
34
|
+
mkdir -p "${OUTPUT_DIR}"
|
|
35
|
+
|
|
36
|
+
ENTRY_POINT="${CCS_SPECS_DIR}/json-schema/event-feed-array.json"
|
|
37
|
+
|
|
38
|
+
if [[ ! -f "${ENTRY_POINT}" ]]; then
|
|
39
|
+
echo "Error: ${ENTRY_POINT} not found in ccs-specs directory"
|
|
40
|
+
exit 2
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
echo "Generating Python models using datamodel-codegen..."
|
|
44
|
+
uv run datamodel-codegen \
|
|
45
|
+
--input "${ENTRY_POINT}" \
|
|
46
|
+
--input-file-type jsonschema \
|
|
47
|
+
--output-model-type pydantic_v2.BaseModel \
|
|
48
|
+
--target-python-version "3.11" \
|
|
49
|
+
--output "${OUTPUT_DIR}/model.py"
|
|
50
|
+
|
|
51
|
+
echo "Creating __init__.py file..."
|
|
52
|
+
cat >"${OUTPUT_DIR}/__init__.py" <<EOF
|
|
53
|
+
"""
|
|
54
|
+
CCS (Contest Control System) models for branch ${BRANCH}.
|
|
55
|
+
|
|
56
|
+
Auto-generated from https://github.com/icpc/ccs-specs/tree/${BRANCH}
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
from .model import * # noqa: F403
|
|
60
|
+
EOF
|
|
61
|
+
|
|
62
|
+
echo "CCS models generated successfully!"
|
|
63
|
+
echo "Output directory: ${OUTPUT_DIR}"
|
|
64
|
+
echo "Generated files:"
|
|
65
|
+
ls -la "${OUTPUT_DIR}"
|
|
66
|
+
|
|
67
|
+
echo "Done!"
|
|
68
|
+
|
|
69
|
+
popd
|
|
File without changes
|