codabench-client 0.1.0__py3-none-any.whl
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.
- codabench/__init__.py +56 -0
- codabench/__main__.py +8 -0
- codabench/auth.py +133 -0
- codabench/cli.py +428 -0
- codabench/client.py +423 -0
- codabench/competitions.py +200 -0
- codabench/downloads.py +80 -0
- codabench/errors.py +29 -0
- codabench/text.py +59 -0
- codabench_client-0.1.0.dist-info/METADATA +258 -0
- codabench_client-0.1.0.dist-info/RECORD +15 -0
- codabench_client-0.1.0.dist-info/WHEEL +5 -0
- codabench_client-0.1.0.dist-info/entry_points.txt +2 -0
- codabench_client-0.1.0.dist-info/licenses/LICENSE +21 -0
- codabench_client-0.1.0.dist-info/top_level.txt +1 -0
codabench/downloads.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Writing downloaded bytes to disk.
|
|
2
|
+
|
|
3
|
+
Every Codabench artifact arrives as a zip (datasets, submissions, prediction
|
|
4
|
+
and scoring output), so the default is to extract; anything that is not a zip
|
|
5
|
+
is written as-is.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import io
|
|
11
|
+
import json
|
|
12
|
+
import zipfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def save_bytes(content: bytes, dest_dir: "str | Path", filename: str,
|
|
17
|
+
extract: bool = True) -> Path:
|
|
18
|
+
"""Write ``content`` into ``dest_dir`` and return what was created.
|
|
19
|
+
|
|
20
|
+
When ``content`` is a zip and ``extract`` is set, it is unpacked into a
|
|
21
|
+
directory named after ``filename`` (without the ``.zip`` suffix) and that
|
|
22
|
+
directory is returned; otherwise the saved file path is returned.
|
|
23
|
+
"""
|
|
24
|
+
dest = Path(dest_dir)
|
|
25
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
if extract and zipfile.is_zipfile(io.BytesIO(content)):
|
|
27
|
+
target = dest / filename[:-4] if filename.lower().endswith(".zip") else dest / filename
|
|
28
|
+
with zipfile.ZipFile(io.BytesIO(content)) as zf:
|
|
29
|
+
zf.extractall(target)
|
|
30
|
+
return target
|
|
31
|
+
path = dest / filename
|
|
32
|
+
path.write_bytes(content)
|
|
33
|
+
return path
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def save_json(data: object, path: "str | Path") -> Path:
|
|
37
|
+
"""Write ``data`` as indented UTF-8 JSON, creating parent directories."""
|
|
38
|
+
target = Path(path)
|
|
39
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
40
|
+
target.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
41
|
+
return target
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def read_scores(content: bytes) -> dict:
|
|
45
|
+
"""Best-effort ``metric -> value`` extraction from a scoring output zip.
|
|
46
|
+
|
|
47
|
+
Reads any JSON/txt/YAML member: JSON objects are merged as-is, other files
|
|
48
|
+
are scanned for ``key: value`` / ``key= value`` lines (the ``scores.txt``
|
|
49
|
+
convention). Used as a fallback when the API returns no inline scores.
|
|
50
|
+
"""
|
|
51
|
+
out: dict = {}
|
|
52
|
+
try:
|
|
53
|
+
zf = zipfile.ZipFile(io.BytesIO(content))
|
|
54
|
+
except zipfile.BadZipFile:
|
|
55
|
+
return out
|
|
56
|
+
for name in zf.namelist():
|
|
57
|
+
if not name.lower().endswith((".json", ".txt", ".yaml", ".yml")):
|
|
58
|
+
continue
|
|
59
|
+
raw = zf.read(name).decode("utf-8", errors="replace")
|
|
60
|
+
if name.lower().endswith(".json"):
|
|
61
|
+
try:
|
|
62
|
+
data = json.loads(raw)
|
|
63
|
+
if isinstance(data, dict):
|
|
64
|
+
out.update(data)
|
|
65
|
+
continue
|
|
66
|
+
except json.JSONDecodeError:
|
|
67
|
+
pass # fall through to line parsing
|
|
68
|
+
for line in raw.splitlines():
|
|
69
|
+
line = line.strip()
|
|
70
|
+
for sep in (":", "="):
|
|
71
|
+
if sep in line:
|
|
72
|
+
key, _, value = line.partition(sep)
|
|
73
|
+
key, value = key.strip(), value.strip()
|
|
74
|
+
if key:
|
|
75
|
+
try:
|
|
76
|
+
out[key] = float(value)
|
|
77
|
+
except ValueError:
|
|
78
|
+
out[key] = value
|
|
79
|
+
break
|
|
80
|
+
return out
|
codabench/errors.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Exceptions raised by the client.
|
|
2
|
+
|
|
3
|
+
The library raises; the CLI catches :class:`CodabenchError` at the top level and
|
|
4
|
+
turns it into a one-line ``error: ...`` message. Nothing here calls ``sys.exit``,
|
|
5
|
+
so the package stays usable from a notebook or another program.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CodabenchError(Exception):
|
|
12
|
+
"""Base class for every error this package raises."""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AuthError(CodabenchError):
|
|
16
|
+
"""Credentials are missing, rejected, or insufficient for the request."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ApiError(CodabenchError):
|
|
20
|
+
"""The API returned an unexpected status code.
|
|
21
|
+
|
|
22
|
+
``status`` and ``body`` are kept so callers can branch on them (e.g. treat
|
|
23
|
+
403/404 as "not authorized for this account" rather than a hard failure).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, message: str, status: int = 0, body: str = "") -> None:
|
|
27
|
+
super().__init__(message)
|
|
28
|
+
self.status = status
|
|
29
|
+
self.body = body
|
codabench/text.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Small text helpers: HTML to readable text, slugs, human-readable sizes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
_TAG_RE = re.compile(r"<[^>]+>")
|
|
8
|
+
_BLANK_RUNS_RE = re.compile(r"[ \t]*\n[ \t]*\n[ \t]*\n+")
|
|
9
|
+
_ENTITIES = {
|
|
10
|
+
" ": " ", "&": "&", "<": "<", ">": ">",
|
|
11
|
+
""": '"', "'": "'",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def strip_html(text: str) -> str:
|
|
16
|
+
"""Best-effort HTML -> readable text: drop tags, collapse blank runs.
|
|
17
|
+
|
|
18
|
+
Codabench pages are authored in markdown but served as HTML, so this is
|
|
19
|
+
enough to make them readable in a terminal or a .md file.
|
|
20
|
+
"""
|
|
21
|
+
if not text:
|
|
22
|
+
return ""
|
|
23
|
+
text = re.sub(r"<br\s*/?>", "\n", text, flags=re.I)
|
|
24
|
+
text = re.sub(r"</p>", "\n\n", text, flags=re.I)
|
|
25
|
+
text = _TAG_RE.sub("", text)
|
|
26
|
+
for entity, char in _ENTITIES.items():
|
|
27
|
+
text = text.replace(entity, char)
|
|
28
|
+
return _BLANK_RUNS_RE.sub("\n\n", text).strip()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def slug(text: str) -> str:
|
|
32
|
+
"""Lowercase, hyphenated, filesystem-safe version of ``text``."""
|
|
33
|
+
s = re.sub(r"[^a-z0-9]+", "-", (text or "").lower()).strip("-")
|
|
34
|
+
return s or "page"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def safe_name(text: str, fallback: str = "file") -> str:
|
|
38
|
+
"""Filesystem-safe filename that keeps the original casing and spaces."""
|
|
39
|
+
name = re.sub(r"[^\w.\- ]+", "_", (text or "").strip()).strip()
|
|
40
|
+
return name or fallback
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def human_size(size: object) -> str:
|
|
44
|
+
"""Format a byte count as ``12.3 MB``; ``?`` when it is not a number."""
|
|
45
|
+
try:
|
|
46
|
+
value = float(size) # type: ignore[arg-type]
|
|
47
|
+
except (TypeError, ValueError):
|
|
48
|
+
return "?"
|
|
49
|
+
for unit in ("B", "KB", "MB", "GB"):
|
|
50
|
+
if value < 1024 or unit == "GB":
|
|
51
|
+
return f"{value:,.1f} {unit}"
|
|
52
|
+
value /= 1024
|
|
53
|
+
return "?"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def truncate(text: str, limit: int) -> str:
|
|
57
|
+
"""One-line preview of ``text``, ellipsised at ``limit`` characters."""
|
|
58
|
+
flat = " ".join((text or "").split())
|
|
59
|
+
return flat if len(flat) <= limit else flat[:limit] + "..."
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codabench-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A small, readable Python client and CLI for the Codabench API.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/amoujar/codabench-client
|
|
7
|
+
Project-URL: Issues, https://github.com/amoujar/codabench-client/issues
|
|
8
|
+
Keywords: codabench,codalab,benchmark,competition,machine-learning
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: requests>=2.25
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# codabench-client
|
|
22
|
+
|
|
23
|
+
A small, readable Python client and CLI for the [Codabench](https://www.codabench.org/) API.
|
|
24
|
+
|
|
25
|
+
Codabench is a great benchmark platform, but a lot of what you can do in its web UI —
|
|
26
|
+
grabbing a starting kit, submitting a zip, pulling the scoring logs of a failed run —
|
|
27
|
+
is tedious to click through and awkward to automate. This package does all of it from
|
|
28
|
+
the terminal or from Python.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
codabench show 17363 # everything about a competition
|
|
32
|
+
codabench files 16161 # download the starting kit & public data
|
|
33
|
+
codabench submit 17525 -z run.zip --wait # submit and watch the score come back
|
|
34
|
+
codabench outputs 17525 # fetch the prediction & scoring output
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/<you>/api-codabench.git
|
|
43
|
+
cd api-codabench
|
|
44
|
+
pip install -e .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Python 3.9+ and `requests` are the only requirements. Without installing, everything
|
|
48
|
+
also works as `python -m codabench ...` and `python examples/01_show_competition.py`.
|
|
49
|
+
|
|
50
|
+
## Credentials
|
|
51
|
+
|
|
52
|
+
Copy the template and fill it in:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cp .env.example .env
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```ini
|
|
59
|
+
CODABENCH_USERNAME=your_username
|
|
60
|
+
CODABENCH_PASSWORD=your_password
|
|
61
|
+
# CODABENCH_URL=https://dev.codabench.org/ # optional; default is www.codabench.org
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`.env` is gitignored. Environment variables win over the file, so CI can just set
|
|
65
|
+
`CODABENCH_USERNAME` / `CODABENCH_PASSWORD`. Reading a **public** competition needs no
|
|
66
|
+
credentials at all.
|
|
67
|
+
|
|
68
|
+
> **Accounts are per-instance.** A `www.codabench.org` login does not work on
|
|
69
|
+
> `dev.codabench.org`, and vice versa.
|
|
70
|
+
|
|
71
|
+
## Commands
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
| Command | What it does |
|
|
75
|
+
| ---------------------------------------------- | ---------------------------------------------------------- |
|
|
76
|
+
| `codabench competitions [--search TEXT]` | List competitions |
|
|
77
|
+
| `codabench show <id|url>` | Pages, phases, tasks, files, leaderboard |
|
|
78
|
+
| `codabench files <id|url>` | List / download the "Files" tab |
|
|
79
|
+
| `codabench submit <id|url> -z FILE` | Upload a submission, optionally wait for the score |
|
|
80
|
+
| `codabench outputs <id|url>` | Download a submission's zip, prediction & scoring output |
|
|
81
|
+
| `codabench rerun --submission ID --task KEY` | Re-run a submission on another task (robot accounts) |
|
|
82
|
+
| `codabench create -b bundle.zip` | Create a competition from a bundle |
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
| Command | What it does |
|
|
86
|
+
| ------------------------------------------------ | ---------------------------------------------------------- |
|
|
87
|
+
| `codabench competitions [--search TEXT]` | List competitions |
|
|
88
|
+
| `codabench show <id|url>` | Pages, phases, tasks, files, leaderboard |
|
|
89
|
+
| `codabench files <id|url>` | List / download the "Files" tab |
|
|
90
|
+
| `codabench submit <id|url> -z FILE` | Upload a submission, optionally wait for the score |
|
|
91
|
+
| `codabench outputs <id|url>` | Download a submission's zip, prediction & scoring output |
|
|
92
|
+
| `codabench rerun --submission ID --task KEY` | Re-run a submission on another task (robot accounts) |
|
|
93
|
+
| `codabench create -b bundle.zip` | Create a competition from a bundle |
|
|
94
|
+
|
|
95
|
+
Every command takes `--url`, `--username`, `--password`, `--env`, and `--help`.
|
|
96
|
+
|
|
97
|
+
### Inspect a competition
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
codabench show 17363 # or the full https://www.codabench.org/competitions/17363/ URL
|
|
101
|
+
codabench show 17363 --pages # full text of every page
|
|
102
|
+
codabench show 17363 --json # raw API payload
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Save the whole thing — description, one markdown file per page, and every file you are
|
|
106
|
+
allowed to download:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
codabench show 17363 --save-dir workdir/17363
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
workdir/17363/
|
|
114
|
+
├── description.md
|
|
115
|
+
├── pages/
|
|
116
|
+
│ ├── 00-overview.md
|
|
117
|
+
│ ├── 01-data.md
|
|
118
|
+
│ └── ...
|
|
119
|
+
└── input/
|
|
120
|
+
└── Track 1 Starting Kit V5/
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Add `--no-download` for the text only.
|
|
124
|
+
|
|
125
|
+
### Download competition files
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
codabench files 16161 --list # see what exists first
|
|
129
|
+
codabench files 16161 # download into files/16161/
|
|
130
|
+
codabench files 16161 --only starting_kit # filter by type or name
|
|
131
|
+
codabench files 16161 --no-extract # keep the zips
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Submit and get scored
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
codabench submit 17525 -z submission.zip --wait
|
|
138
|
+
codabench submit 17525 -z submission.zip --wait \
|
|
139
|
+
--results-json results.json --download-dir outputs
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The phase is resolved automatically (the only one, or the currently open one); pass
|
|
143
|
+
`--phase <id>` or `--phase-index <n>` when a competition has several open at once.
|
|
144
|
+
Submitting **consumes your daily quota** — the command checks eligibility first and
|
|
145
|
+
tells you if you are out.
|
|
146
|
+
|
|
147
|
+
### Get a submission's output
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
codabench outputs 17525 --list # your submissions on the phase
|
|
151
|
+
codabench outputs 17525 # newest submission
|
|
152
|
+
codabench outputs 17525 --last 2 # the one before it
|
|
153
|
+
codabench outputs --submission 856524 # a specific id
|
|
154
|
+
codabench outputs 17525 --only scoring # just the scoring step
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Everything lands in `outputs/<submission id>/` with the zips extracted, plus a
|
|
158
|
+
`details.json` holding the scores, logs and exit statuses — which is usually where the
|
|
159
|
+
answer is when a submission fails.
|
|
160
|
+
|
|
161
|
+
## Python API
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from codabench import CodabenchClient, collect_files, find_phase
|
|
165
|
+
|
|
166
|
+
client = CodabenchClient() # reads .env / environment
|
|
167
|
+
|
|
168
|
+
competition = client.competition(17363) # id or URL
|
|
169
|
+
phase = find_phase(competition) # the open phase
|
|
170
|
+
|
|
171
|
+
for entry in collect_files(competition):
|
|
172
|
+
path = client.download_dataset(entry.key, "input/", entry.filename)
|
|
173
|
+
print(entry.name, "->", path or "not authorized")
|
|
174
|
+
|
|
175
|
+
submission = client.submit(phase["id"], "run.zip")
|
|
176
|
+
client.wait_for_submission(submission["id"])
|
|
177
|
+
print(client.results(submission["id"])["metrics"])
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The client raises `CodabenchError` (with `AuthError` and `ApiError` subclasses) and
|
|
181
|
+
never calls `sys.exit`, so it is safe to use inside a notebook or a larger program.
|
|
182
|
+
|
|
183
|
+
## What you can actually download
|
|
184
|
+
|
|
185
|
+
This trips everyone up, so it is worth stating plainly. Codabench decides per file, and
|
|
186
|
+
this tool cannot widen what your account is allowed to see:
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
| File | Who can download it |
|
|
190
|
+
| --------------------------------- | ----------------------------------------------------------------------- |
|
|
191
|
+
| Starting kit, public data | Any approved participant |
|
|
192
|
+
| Ingestion / scoring program | Participants**only if** the organizer set `make_programs_available` |
|
|
193
|
+
| Input data | Participants**only if** the organizer set `make_input_data_available` |
|
|
194
|
+
| Reference data (the answer key) | Organizers only, always |
|
|
195
|
+
| Competition bundle | Organizers only |
|
|
196
|
+
|
|
197
|
+
Files your account may not fetch are skipped, not treated as an error. `codabench show`
|
|
198
|
+
prints the organizer's two flags so you can see why something is missing.
|
|
199
|
+
|
|
200
|
+
## How authentication works
|
|
201
|
+
|
|
202
|
+
Codabench uses **two** mechanisms and you need both — the reason `CodabenchClient` holds
|
|
203
|
+
a token *and* a session:
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
| Endpoint | Auth |
|
|
207
|
+
| ----------------------------- | ------------------------------------------------------- |
|
|
208
|
+
| `/api/...` | Token from`POST /api/api-token-auth/` |
|
|
209
|
+
| `/datasets/download/<key>/` | Django**session cookie** from `POST /accounts/login/` |
|
|
210
|
+
|
|
211
|
+
The download route behind the "Files" tab is a plain Django view that ignores the API
|
|
212
|
+
token, which is why a token-only client gets 403s on files a participant can plainly
|
|
213
|
+
download in the browser. Both schemes read the same credentials, so callers never have
|
|
214
|
+
to think about it.
|
|
215
|
+
|
|
216
|
+
(There is also `GET /api/competitions/{id}/get_files/`, but it is organizer-only and
|
|
217
|
+
returns 403 for participants — this package does not rely on it.)
|
|
218
|
+
|
|
219
|
+
## Repository layout
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
codabench/ the library
|
|
223
|
+
├── auth.py credentials, token auth, session login
|
|
224
|
+
├── client.py CodabenchClient — every API call
|
|
225
|
+
├── competitions.py pure helpers over a competition payload
|
|
226
|
+
├── downloads.py saving & extracting artifacts
|
|
227
|
+
├── text.py HTML→text, slugs, sizes
|
|
228
|
+
├── errors.py CodabenchError / AuthError / ApiError
|
|
229
|
+
└── cli.py the `codabench` command
|
|
230
|
+
|
|
231
|
+
examples/ the same flows as standalone scripts
|
|
232
|
+
├── 01_show_competition.py
|
|
233
|
+
├── 02_download_competition_files.py
|
|
234
|
+
├── 03_submit_and_wait.py
|
|
235
|
+
├── 04_download_submission_outputs.py
|
|
236
|
+
├── 05_create_competition.py
|
|
237
|
+
└── 06_rerun_submission.py
|
|
238
|
+
|
|
239
|
+
assets/ a sample submission zip and competition bundle
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Run any example directly — no install needed:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
python examples/01_show_competition.py 17363
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Notes
|
|
249
|
+
|
|
250
|
+
* **Organizers**: `codabench create -b bundle.zip` uploads a competition bundle and polls
|
|
251
|
+
until it is unpacked. Try it on `https://dev.codabench.org/` first.
|
|
252
|
+
* **Robot accounts**: `codabench rerun` re-runs an existing submission against another
|
|
253
|
+
task, reusing the uploaded data. It needs an account flagged `is_bot`, or the API
|
|
254
|
+
answers 403.
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
codabench/__init__.py,sha256=6rJotiXXjeK3-zUbZ7Vp5zGrnZnYYyhFghORV2llXOc,1436
|
|
2
|
+
codabench/__main__.py,sha256=SSJn1Vk2bz0YcQ3Lj88--r4OlSenyLJys-u90bQ2PVk,168
|
|
3
|
+
codabench/auth.py,sha256=cNOpoFGAYyiPdszDrkRLXWb1bxy47k9QJ_1bySlAiZs,4967
|
|
4
|
+
codabench/cli.py,sha256=3p-5CZkBsvuMGFVmGnnvD2RxLYTnnKsexEysReMsyd4,19744
|
|
5
|
+
codabench/client.py,sha256=sjPx-J6K2RcfKh_ijEcfLYUkpcItBDlNaLNCdQ3rRFs,19896
|
|
6
|
+
codabench/competitions.py,sha256=fR33cqUqAxnp042vplwXEu_A8KSHh1wLWm5ETfY34Jg,7547
|
|
7
|
+
codabench/downloads.py,sha256=zjOrXX56XsDp77Bh7aYaHUGhGl1Pozd-ouYtz3A1SzA,2935
|
|
8
|
+
codabench/errors.py,sha256=O_WeQKU5vbOa07-TUePwKuZWwSmMqXrOM08T4ZhTcCg,929
|
|
9
|
+
codabench/text.py,sha256=sHKqndmiHHvkGxI0rSyUZtFCLVaIf5_u9FrMb260myA,1943
|
|
10
|
+
codabench_client-0.1.0.dist-info/licenses/LICENSE,sha256=bGA7ejoo0kQpP4K6XI2WnirG-Gti6yUweTkzLs-Lup4,1087
|
|
11
|
+
codabench_client-0.1.0.dist-info/METADATA,sha256=SDLQymbyc3lYcru5GAWi3wec_22uwdIkgrf4dBM1gUk,10656
|
|
12
|
+
codabench_client-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
13
|
+
codabench_client-0.1.0.dist-info/entry_points.txt,sha256=64iHq5EG8HYK6ViGLMGWJIb8iK_QdseY6LkEeuM6YKI,49
|
|
14
|
+
codabench_client-0.1.0.dist-info/top_level.txt,sha256=awRAA61v-tCAS1QeTIEgMlDeLq0CmWfTK1oAKmruCZ8,10
|
|
15
|
+
codabench_client-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abderrahmane Moujar [Scarface]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
codabench
|