xcpcio 0.63.3__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.

Files changed (30) hide show
  1. xcpcio-0.63.4/.gitignore +8 -0
  2. xcpcio-0.63.4/.python-version +1 -0
  3. {xcpcio-0.63.3 → xcpcio-0.63.4}/PKG-INFO +12 -6
  4. xcpcio-0.63.4/cli/ccs_archiver_cli.py +122 -0
  5. {xcpcio-0.63.3 → xcpcio-0.63.4}/pyproject.toml +21 -2
  6. xcpcio-0.63.4/scripts/generate_ccs_models.sh +69 -0
  7. xcpcio-0.63.4/tests/__init__.py +0 -0
  8. xcpcio-0.63.4/uv.lock +1551 -0
  9. xcpcio-0.63.4/xcpcio/__init__.py +4 -0
  10. xcpcio-0.63.4/xcpcio/__version__.py +1 -0
  11. xcpcio-0.63.4/xcpcio/ccs/__init__.py +3 -0
  12. xcpcio-0.63.4/xcpcio/ccs/contest_archiver.py +439 -0
  13. xcpcio-0.63.3/setup.cfg +0 -4
  14. xcpcio-0.63.3/xcpcio/__init__.py +0 -5
  15. xcpcio-0.63.3/xcpcio/ccs/__init__.py +0 -3
  16. xcpcio-0.63.3/xcpcio.egg-info/PKG-INFO +0 -21
  17. xcpcio-0.63.3/xcpcio.egg-info/SOURCES.txt +0 -18
  18. xcpcio-0.63.3/xcpcio.egg-info/dependency_links.txt +0 -1
  19. xcpcio-0.63.3/xcpcio.egg-info/requires.txt +0 -1
  20. xcpcio-0.63.3/xcpcio.egg-info/top_level.txt +0 -1
  21. {xcpcio-0.63.3 → xcpcio-0.63.4}/README.md +0 -0
  22. {xcpcio-0.63.3 → xcpcio-0.63.4}/tests/test_contest.py +0 -0
  23. {xcpcio-0.63.3 → xcpcio-0.63.4}/tests/test_submission.py +0 -0
  24. {xcpcio-0.63.3 → xcpcio-0.63.4}/tests/test_team.py +0 -0
  25. {xcpcio-0.63.3 → xcpcio-0.63.4}/tests/test_types.py +0 -0
  26. {xcpcio-0.63.3 → xcpcio-0.63.4}/xcpcio/ccs/model/__init__.py +0 -0
  27. {xcpcio-0.63.3 → xcpcio-0.63.4}/xcpcio/ccs/model/model_2023_06/__init__.py +0 -0
  28. {xcpcio-0.63.3 → xcpcio-0.63.4}/xcpcio/ccs/model/model_2023_06/model.py +0 -0
  29. {xcpcio-0.63.3 → xcpcio-0.63.4}/xcpcio/constants.py +0 -0
  30. {xcpcio-0.63.3 → xcpcio-0.63.4}/xcpcio/types.py +0 -0
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ __pycache__/
5
+ ccs-specs/
6
+ output/
7
+
8
+ .env
@@ -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
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
- Description-Content-Type: text/markdown
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.3"
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 = [ "pydantic>=2.11.7", ]
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