evalmc 0.0.1__tar.gz → 0.0.3__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.
- evalmc-0.0.3/PKG-INFO +95 -0
- evalmc-0.0.3/README.md +72 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/check_challenge.py +3 -0
- evalmc-0.0.3/evalmc/config_paths.py +9 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/host.py +1 -7
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/login.py +1 -8
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/main.py +3 -4
- evalmc-0.0.3/evalmc/nominate.py +33 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/push_helpers.py +63 -4
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/set_token.py +1 -7
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/submission.py +14 -28
- evalmc-0.0.3/evalmc/submit_onnx.py +49 -0
- evalmc-0.0.3/evalmc.egg-info/PKG-INFO +95 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc.egg-info/SOURCES.txt +5 -2
- {evalmc-0.0.1 → evalmc-0.0.3}/pyproject.toml +2 -2
- evalmc-0.0.3/tests/test_cli_nominate.py +57 -0
- evalmc-0.0.3/tests/test_push_helpers.py +160 -0
- evalmc-0.0.3/tests/test_submission_api_base.py +92 -0
- evalmc-0.0.1/PKG-INFO +0 -89
- evalmc-0.0.1/README.md +0 -66
- evalmc-0.0.1/evalmc/submit.py +0 -88
- evalmc-0.0.1/evalmc/submit_onnx.py +0 -62
- evalmc-0.0.1/evalmc.egg-info/PKG-INFO +0 -89
- evalmc-0.0.1/tests/test_push_helpers.py +0 -32
- {evalmc-0.0.1 → evalmc-0.0.3}/LICENSE +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/__init__.py +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/__main__.py +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/check_registered.py +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/register.py +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/status.py +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc/utils.py +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc.egg-info/dependency_links.txt +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc.egg-info/entry_points.txt +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc.egg-info/requires.txt +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/evalmc.egg-info/top_level.txt +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/setup.cfg +0 -0
- {evalmc-0.0.1 → evalmc-0.0.3}/tests/test_cli_smoke.py +0 -0
evalmc-0.0.3/PKG-INFO
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: evalmc
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Submit ONNX policies and Docker agents to MyoChallenge
|
|
5
|
+
Author-email: MyoChallenge Team <caggiano@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/MyoHub/mcEvalProd-CLI
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: click>=8.0.0
|
|
19
|
+
Requires-Dist: docker>=6.0.0
|
|
20
|
+
Requires-Dist: requests>=2.25.0
|
|
21
|
+
Requires-Dist: boto3>=1.26.0
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# evalmc
|
|
25
|
+
|
|
26
|
+
MyoChallenge submission CLI — upload ONNX policies or Docker agent images to
|
|
27
|
+
[mc26.myosuite.org](https://mc26.myosuite.org).
|
|
28
|
+
|
|
29
|
+
[](https://pypi.org/project/evalmc/)
|
|
30
|
+
[](https://pypi.org/project/evalmc/)
|
|
31
|
+
[](https://pypi.org/project/evalmc/)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install -U evalmc
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Default API: `https://api.mc.myosuite.org`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
evalmc host --set-host https://api.mc.myosuite.org
|
|
45
|
+
evalmc login
|
|
46
|
+
evalmc status
|
|
47
|
+
evalmc submit-onnx model.onnx -t chasetag -p 1
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`evalmc login` stores the email and auth token from the dashboard.
|
|
51
|
+
Credentials live in `~/.myochallenge/`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Commands
|
|
56
|
+
|
|
57
|
+
| Command | Purpose |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `evalmc host` | Show or set the API host |
|
|
60
|
+
| `evalmc login` | Save email + auth token |
|
|
61
|
+
| `evalmc status` | Confirm host and team |
|
|
62
|
+
| `evalmc submit-onnx` | Upload an ONNX policy |
|
|
63
|
+
| `evalmc nominate` | Pick a scored artifact for title-cycle finals |
|
|
64
|
+
| `evalmc push` | Submit a Docker / ECR agent image |
|
|
65
|
+
|
|
66
|
+
### ONNX
|
|
67
|
+
|
|
68
|
+
Recommended for ChaseTag. The graph is `obs → action`; no `policy.py` required.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
evalmc submit-onnx model.onnx -t chasetag -p 1
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Title-cycle nomination
|
|
75
|
+
|
|
76
|
+
Before freeze, choose which scored in-window submission plays in finals.
|
|
77
|
+
If you skip this, the platform uses your best score.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
evalmc nominate -t chasetag -p 1 --submission-id 123
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Docker
|
|
84
|
+
|
|
85
|
+
For custom Python around the policy. The image must ship `policy.py` and/or
|
|
86
|
+
`model.onnx` under `/policy` (or `/app`).
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
evalmc push my-agent:tag -t chasetag -p 1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
Some tracks are invitation-only. Registration and submission are rejected until
|
|
95
|
+
the team is on the whitelist. Leaderboards stay public.
|
evalmc-0.0.3/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# evalmc
|
|
2
|
+
|
|
3
|
+
MyoChallenge submission CLI — upload ONNX policies or Docker agent images to
|
|
4
|
+
[mc26.myosuite.org](https://mc26.myosuite.org).
|
|
5
|
+
|
|
6
|
+
[](https://pypi.org/project/evalmc/)
|
|
7
|
+
[](https://pypi.org/project/evalmc/)
|
|
8
|
+
[](https://pypi.org/project/evalmc/)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install -U evalmc
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Default API: `https://api.mc.myosuite.org`
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
evalmc host --set-host https://api.mc.myosuite.org
|
|
22
|
+
evalmc login
|
|
23
|
+
evalmc status
|
|
24
|
+
evalmc submit-onnx model.onnx -t chasetag -p 1
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`evalmc login` stores the email and auth token from the dashboard.
|
|
28
|
+
Credentials live in `~/.myochallenge/`.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
| Command | Purpose |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `evalmc host` | Show or set the API host |
|
|
37
|
+
| `evalmc login` | Save email + auth token |
|
|
38
|
+
| `evalmc status` | Confirm host and team |
|
|
39
|
+
| `evalmc submit-onnx` | Upload an ONNX policy |
|
|
40
|
+
| `evalmc nominate` | Pick a scored artifact for title-cycle finals |
|
|
41
|
+
| `evalmc push` | Submit a Docker / ECR agent image |
|
|
42
|
+
|
|
43
|
+
### ONNX
|
|
44
|
+
|
|
45
|
+
Recommended for ChaseTag. The graph is `obs → action`; no `policy.py` required.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
evalmc submit-onnx model.onnx -t chasetag -p 1
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Title-cycle nomination
|
|
52
|
+
|
|
53
|
+
Before freeze, choose which scored in-window submission plays in finals.
|
|
54
|
+
If you skip this, the platform uses your best score.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
evalmc nominate -t chasetag -p 1 --submission-id 123
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Docker
|
|
61
|
+
|
|
62
|
+
For custom Python around the policy. The image must ship `policy.py` and/or
|
|
63
|
+
`model.onnx` under `/policy` (or `/app`).
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
evalmc push my-agent:tag -t chasetag -p 1
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
Some tracks are invitation-only. Registration and submission are rejected until
|
|
72
|
+
the team is on the whitelist. Leaderboards stay public.
|
|
@@ -18,6 +18,8 @@ def check_task_phase(api_url, task, phase):
|
|
|
18
18
|
"score_names": data.get("score_names"),
|
|
19
19
|
"display_name": data.get("display_name"),
|
|
20
20
|
"visible": data.get("visible"),
|
|
21
|
+
"evaluation_mode": data.get("evaluation_mode", "absolute"),
|
|
22
|
+
"access_mode": data.get("access_mode", "open"),
|
|
21
23
|
"created_at": data.get("created_at"),
|
|
22
24
|
}
|
|
23
25
|
else:
|
|
@@ -112,6 +114,7 @@ def main():
|
|
|
112
114
|
total_score_metrics += tp.get("num_scores", 0)
|
|
113
115
|
label = tp.get("display_name") or f"{tp['task']} phase {tp['phase']}"
|
|
114
116
|
print(f"✅ {label}: {tp['num_scores']} score metrics")
|
|
117
|
+
print(f" Format: {tp.get('evaluation_mode', 'absolute')} | Access: {tp.get('access_mode', 'open')}")
|
|
115
118
|
print(f" Score Names: {', '.join(tp.get('score_names', []))}")
|
|
116
119
|
print()
|
|
117
120
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Shared local config file locations for the evalmc CLI."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
CONFIG_DIR = Path.home() / ".myochallenge"
|
|
6
|
+
HOST_URL_FILE = CONFIG_DIR / "host_url"
|
|
7
|
+
AUTH_TOKEN_FILE = CONFIG_DIR / "auth_token.json"
|
|
8
|
+
|
|
9
|
+
CONFIG_DIR.mkdir(exist_ok=True)
|
|
@@ -4,16 +4,10 @@ MyoChallenge Host - Configure API host URL
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
7
|
|
|
9
8
|
import click
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
CONFIG_DIR = Path.home() / ".myochallenge"
|
|
13
|
-
HOST_URL_FILE = CONFIG_DIR / "host_url"
|
|
14
|
-
|
|
15
|
-
# Ensure config directory exists
|
|
16
|
-
CONFIG_DIR.mkdir(exist_ok=True)
|
|
10
|
+
from .config_paths import HOST_URL_FILE
|
|
17
11
|
|
|
18
12
|
|
|
19
13
|
@click.command()
|
|
@@ -5,18 +5,11 @@ MyoChallenge Login - Interactive authentication and credential storage
|
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
7
|
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
8
|
|
|
10
9
|
import click
|
|
11
10
|
import requests
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
CONFIG_DIR = Path.home() / ".myochallenge"
|
|
15
|
-
HOST_URL_FILE = CONFIG_DIR / "host_url"
|
|
16
|
-
AUTH_TOKEN_FILE = CONFIG_DIR / "auth_token.json"
|
|
17
|
-
|
|
18
|
-
# Ensure config directory exists
|
|
19
|
-
CONFIG_DIR.mkdir(exist_ok=True)
|
|
12
|
+
from .config_paths import AUTH_TOKEN_FILE, HOST_URL_FILE
|
|
20
13
|
|
|
21
14
|
|
|
22
15
|
def get_default_host():
|
|
@@ -10,8 +10,8 @@ from .login import login
|
|
|
10
10
|
from .set_token import set_token
|
|
11
11
|
from .status import status
|
|
12
12
|
from .submission import push
|
|
13
|
-
from .submit import submit
|
|
14
13
|
from .submit_onnx import submit_onnx
|
|
14
|
+
from .nominate import nominate
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
@click.group()
|
|
@@ -23,8 +23,7 @@ def main():
|
|
|
23
23
|
Two submission paths are available:
|
|
24
24
|
|
|
25
25
|
\b
|
|
26
|
-
evalmc submit
|
|
27
|
-
evalmc submit-onnx model.onnx -p 1 -t elbowflexion # ONNX upload
|
|
26
|
+
evalmc submit-onnx model.onnx -p 1 -t elbowflexion # ONNX (elbow / ChaseTag)
|
|
28
27
|
evalmc push my-image:tag -p 1 -t tabletennis # Docker/ECR image push
|
|
29
28
|
"""
|
|
30
29
|
pass
|
|
@@ -34,6 +33,6 @@ main.add_command(host)
|
|
|
34
33
|
main.add_command(login)
|
|
35
34
|
main.add_command(set_token)
|
|
36
35
|
main.add_command(push)
|
|
37
|
-
main.add_command(submit)
|
|
38
36
|
main.add_command(submit_onnx)
|
|
37
|
+
main.add_command(nominate)
|
|
39
38
|
main.add_command(status)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Select a scored title-cycle submission for the upcoming finals."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from .login import get_default_host
|
|
7
|
+
from .push_helpers import http_error_detail, resolve_credentials
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command()
|
|
11
|
+
@click.option("-t", "--task", required=True)
|
|
12
|
+
@click.option("-p", "--phase", required=True, type=int)
|
|
13
|
+
@click.option("--submission-id", required=True, type=int)
|
|
14
|
+
@click.option("-e", "--email", default=None)
|
|
15
|
+
@click.option("-a", "--auth-token", default=None)
|
|
16
|
+
def nominate(task, phase, submission_id, email, auth_token):
|
|
17
|
+
"""Use SUBMISSION_ID for this title cycle's finals."""
|
|
18
|
+
email, auth_token = resolve_credentials(email, auth_token)
|
|
19
|
+
try:
|
|
20
|
+
response = requests.put(
|
|
21
|
+
f"{get_default_host()}/title-cycle/{task}/{phase}/nominate",
|
|
22
|
+
json={"submission_id": submission_id},
|
|
23
|
+
headers={"X-User-Email": email, "X-Auth-Token": auth_token},
|
|
24
|
+
timeout=20,
|
|
25
|
+
)
|
|
26
|
+
response.raise_for_status()
|
|
27
|
+
except requests.exceptions.HTTPError as exc:
|
|
28
|
+
raise click.ClickException(
|
|
29
|
+
f"Could not nominate submission: {http_error_detail(exc.response)}"
|
|
30
|
+
)
|
|
31
|
+
except requests.exceptions.RequestException as exc:
|
|
32
|
+
raise click.ClickException(f"Could not reach the API: {exc}")
|
|
33
|
+
click.echo(f"Submission {submission_id} will be used for finals.")
|
|
@@ -4,6 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from urllib.parse import urlparse
|
|
6
6
|
|
|
7
|
+
import click
|
|
8
|
+
import requests
|
|
9
|
+
|
|
7
10
|
POLICY_PATHS = (
|
|
8
11
|
"/policy/policy.py",
|
|
9
12
|
"/policy/model.onnx",
|
|
@@ -51,7 +54,7 @@ def image_not_found_help(image: str, build_hint: str | None = None) -> str:
|
|
|
51
54
|
lines.extend(
|
|
52
55
|
[
|
|
53
56
|
"",
|
|
54
|
-
"For elbow flexion,
|
|
57
|
+
"For elbow flexion, ONNX submission is usually simpler:",
|
|
55
58
|
" evalmc submit-onnx model.onnx -t elbowflexion -p 1",
|
|
56
59
|
]
|
|
57
60
|
)
|
|
@@ -95,9 +98,8 @@ def local_push_remote_warning(api_base: str, local_tag: str) -> str:
|
|
|
95
98
|
f"\n"
|
|
96
99
|
f"Expected outcome: submission status 'submitted' → 'failed' (no leaderboard entry).\n"
|
|
97
100
|
f"\n"
|
|
98
|
-
f"Recommended
|
|
101
|
+
f"Recommended alternative for elbow flexion:\n"
|
|
99
102
|
f" evalmc submit-onnx model.onnx -t elbowflexion -p 1\n"
|
|
100
|
-
f" evalmc submit policy.zip -t elbowflexion -p 1\n"
|
|
101
103
|
f"\n"
|
|
102
104
|
f"For Docker on production, the server needs USE_LOCAL_STORAGE=false and ECR push.\n"
|
|
103
105
|
f"Contact the organizers if ECR upload is required."
|
|
@@ -121,6 +123,63 @@ def policy_missing_help(image: str) -> str:
|
|
|
121
123
|
)
|
|
122
124
|
|
|
123
125
|
|
|
126
|
+
def resolve_credentials(email: str | None, auth_token: str | None) -> tuple[str, str]:
|
|
127
|
+
"""Fill in email/auth_token from stored credentials when omitted.
|
|
128
|
+
|
|
129
|
+
Raises click.ClickException if neither the args nor stored credentials
|
|
130
|
+
provide both values.
|
|
131
|
+
"""
|
|
132
|
+
from .login import get_stored_auth
|
|
133
|
+
|
|
134
|
+
if not email or not auth_token:
|
|
135
|
+
stored = get_stored_auth()
|
|
136
|
+
if not stored:
|
|
137
|
+
raise click.ClickException(
|
|
138
|
+
"No credentials found. Run 'evalmc login' or pass --email and --auth-token."
|
|
139
|
+
)
|
|
140
|
+
email = email or stored["email"]
|
|
141
|
+
auth_token = auth_token or stored["auth_token"]
|
|
142
|
+
return email, auth_token
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def post_submission_file(
|
|
146
|
+
api_base: str,
|
|
147
|
+
endpoint: str,
|
|
148
|
+
task: str,
|
|
149
|
+
phase: int,
|
|
150
|
+
email: str,
|
|
151
|
+
auth_token: str,
|
|
152
|
+
file_field: str,
|
|
153
|
+
file_name: str,
|
|
154
|
+
file_obj,
|
|
155
|
+
content_type: str,
|
|
156
|
+
) -> dict:
|
|
157
|
+
"""POST a submission file to the API; raise ClickException on failure."""
|
|
158
|
+
try:
|
|
159
|
+
resp = requests.post(
|
|
160
|
+
f"{api_base}{endpoint}",
|
|
161
|
+
data={"task": task, "phase": phase, "email": email, "auth_token": auth_token},
|
|
162
|
+
files={file_field: (file_name, file_obj, content_type)},
|
|
163
|
+
timeout=120,
|
|
164
|
+
)
|
|
165
|
+
resp.raise_for_status()
|
|
166
|
+
except requests.exceptions.HTTPError as e:
|
|
167
|
+
detail = http_error_detail(e.response)
|
|
168
|
+
if e.response.status_code == 403 and "invitation-only" in detail.lower():
|
|
169
|
+
detail = f"{detail} Ask an organizer to approve your team for this track."
|
|
170
|
+
raise click.ClickException(f"Server error {e.response.status_code}: {detail}")
|
|
171
|
+
except requests.exceptions.RequestException as e:
|
|
172
|
+
raise click.ClickException(f"Request failed: {e}")
|
|
173
|
+
return resp.json()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def echo_submission_result(data: dict) -> None:
|
|
177
|
+
click.echo("Submitted successfully!")
|
|
178
|
+
click.echo(f" Submission ID : {data['submission_id']}")
|
|
179
|
+
click.echo(f" Type : {data['submission_type']}")
|
|
180
|
+
click.echo(f" Status : {data['status']}")
|
|
181
|
+
|
|
182
|
+
|
|
124
183
|
def post_submit_local_remote_note(submission_id, local_tag: str, api_base: str) -> str:
|
|
125
184
|
return (
|
|
126
185
|
f"\n⚠️ Submission {submission_id} recorded, but evaluation may fail on the server.\n"
|
|
@@ -132,5 +191,5 @@ def post_submit_local_remote_note(submission_id, local_tag: str, api_base: str)
|
|
|
132
191
|
f" curl -s {api_base}/submissions/team/YOUR_TEAM | python3 -m json.tool\n"
|
|
133
192
|
f"\n"
|
|
134
193
|
f"If status becomes 'failed', the server could not run your local Docker tag.\n"
|
|
135
|
-
f"Use evalmc submit-onnx
|
|
194
|
+
f"Use evalmc submit-onnx instead."
|
|
136
195
|
)
|
|
@@ -5,16 +5,10 @@ MyoChallenge Set Token - Directly configure authentication token
|
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
7
|
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
8
|
|
|
10
9
|
import click
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
CONFIG_DIR = Path.home() / ".myochallenge"
|
|
14
|
-
AUTH_TOKEN_FILE = CONFIG_DIR / "auth_token.json"
|
|
15
|
-
|
|
16
|
-
# Ensure config directory exists
|
|
17
|
-
CONFIG_DIR.mkdir(exist_ok=True)
|
|
11
|
+
from .config_paths import AUTH_TOKEN_FILE
|
|
18
12
|
|
|
19
13
|
|
|
20
14
|
@click.command()
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
MyoChallenge Submission Script - ECR-based Docker image submission
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import json
|
|
7
|
+
import shutil
|
|
6
8
|
import subprocess
|
|
7
9
|
import sys
|
|
10
|
+
import tempfile
|
|
11
|
+
import time
|
|
8
12
|
import uuid
|
|
9
|
-
from pathlib import Path
|
|
10
13
|
|
|
11
14
|
import click
|
|
12
15
|
import docker
|
|
@@ -25,14 +28,6 @@ from .push_helpers import (
|
|
|
25
28
|
upload_mode_summary,
|
|
26
29
|
)
|
|
27
30
|
|
|
28
|
-
# Configuration file paths
|
|
29
|
-
CONFIG_DIR = Path.home() / ".myochallenge"
|
|
30
|
-
HOST_URL_FILE = CONFIG_DIR / "host_url"
|
|
31
|
-
AUTH_TOKEN_FILE = CONFIG_DIR / "auth_token.json"
|
|
32
|
-
|
|
33
|
-
# Ensure config directory exists
|
|
34
|
-
CONFIG_DIR.mkdir(exist_ok=True)
|
|
35
|
-
|
|
36
31
|
|
|
37
32
|
# Configuration
|
|
38
33
|
LOCAL_DOCKER_REGISTRY_URI = "localhost:5000"
|
|
@@ -134,8 +129,8 @@ def _run_subprocess(cmd: list[str], step: str) -> None:
|
|
|
134
129
|
@click.option(
|
|
135
130
|
"--api-base",
|
|
136
131
|
help="API base URL",
|
|
137
|
-
default=
|
|
138
|
-
show_default=
|
|
132
|
+
default=None,
|
|
133
|
+
show_default="stored host, or https://api.mc.myosuite.org",
|
|
139
134
|
)
|
|
140
135
|
@click.option(
|
|
141
136
|
"--skip-policy-check",
|
|
@@ -177,7 +172,7 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
177
172
|
if not public and not private:
|
|
178
173
|
private = True # Default to private
|
|
179
174
|
|
|
180
|
-
api_base = get_default_host()
|
|
175
|
+
api_base = api_base or get_default_host()
|
|
181
176
|
|
|
182
177
|
click.echo(f"🚀 Starting submission for {image} to {task} phase {phase}")
|
|
183
178
|
click.echo(f"🌐 API host: {api_base}")
|
|
@@ -250,15 +245,6 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
250
245
|
except requests.exceptions.RequestException as e:
|
|
251
246
|
_fail(f"Authentication request failed: {e}")
|
|
252
247
|
|
|
253
|
-
# Collect submission metadata (not used in ECR flow)
|
|
254
|
-
# submission_metadata = {
|
|
255
|
-
# "is_public": json.dumps(public),
|
|
256
|
-
# "method_name": "",
|
|
257
|
-
# "method_description": "",
|
|
258
|
-
# "project_url": "",
|
|
259
|
-
# "publication_url": "",
|
|
260
|
-
# }
|
|
261
|
-
|
|
262
248
|
# Generate unique tag for submission
|
|
263
249
|
submission_tag = str(uuid.uuid4())
|
|
264
250
|
click.echo(f"🏷️ Generated submission tag: {submission_tag}")
|
|
@@ -290,7 +276,7 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
290
276
|
if not click.confirm("Continue with local Docker tag anyway?", default=False):
|
|
291
277
|
_fail(
|
|
292
278
|
"Submission cancelled",
|
|
293
|
-
"Use evalmc submit-onnx
|
|
279
|
+
"Use evalmc submit-onnx, or re-run with --yes.",
|
|
294
280
|
)
|
|
295
281
|
elif not is_local_api(api_base):
|
|
296
282
|
click.echo(local_push_remote_warning(api_base, local_tag))
|
|
@@ -327,6 +313,8 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
327
313
|
"task": task,
|
|
328
314
|
"phase": phase,
|
|
329
315
|
"image_uri": image_uri,
|
|
316
|
+
"email": email,
|
|
317
|
+
"auth_token": auth_token,
|
|
330
318
|
},
|
|
331
319
|
timeout=10,
|
|
332
320
|
)
|
|
@@ -376,6 +364,8 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
376
364
|
"task": task,
|
|
377
365
|
"phase": phase,
|
|
378
366
|
"image_uri": image_uri,
|
|
367
|
+
"email": email,
|
|
368
|
+
"auth_token": auth_token,
|
|
379
369
|
},
|
|
380
370
|
timeout=10,
|
|
381
371
|
)
|
|
@@ -412,8 +402,6 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
412
402
|
f"Server returned: {ecr_data}",
|
|
413
403
|
)
|
|
414
404
|
|
|
415
|
-
import time
|
|
416
|
-
|
|
417
405
|
submission_id = str(uuid.uuid4())[
|
|
418
406
|
:8
|
|
419
407
|
] # Use first 8 chars of UUID for uniqueness
|
|
@@ -425,10 +413,6 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
425
413
|
click.echo(f"⏰ Timestamp: {timestamp}")
|
|
426
414
|
|
|
427
415
|
try:
|
|
428
|
-
import json
|
|
429
|
-
import shutil
|
|
430
|
-
import tempfile
|
|
431
|
-
|
|
432
416
|
temp_dir = tempfile.mkdtemp()
|
|
433
417
|
dockerfile_path = f"{temp_dir}/Dockerfile"
|
|
434
418
|
|
|
@@ -485,6 +469,8 @@ def push(image, phase, task, email, auth_token, url, public, private, api_base,
|
|
|
485
469
|
"task": task,
|
|
486
470
|
"phase": phase,
|
|
487
471
|
"image_uri": image_uri,
|
|
472
|
+
"email": email,
|
|
473
|
+
"auth_token": auth_token,
|
|
488
474
|
},
|
|
489
475
|
timeout=10,
|
|
490
476
|
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""evalmc submit-onnx — upload a standalone ONNX model to MyoChallenge."""
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from .login import get_default_host
|
|
9
|
+
from .push_helpers import echo_submission_result, post_submission_file, resolve_credentials
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.command("submit-onnx")
|
|
13
|
+
@click.argument("onnx_path", type=click.Path(exists=True, path_type=Path))
|
|
14
|
+
@click.option("-p", "--phase", required=True, type=int, help="Challenge phase number")
|
|
15
|
+
@click.option("-t", "--task", required=True, help="Challenge task name (e.g. elbowflexion)")
|
|
16
|
+
@click.option("-e", "--email", default=None, help="Team email")
|
|
17
|
+
@click.option("-a", "--auth-token", default=None, help="Auth token")
|
|
18
|
+
def submit_onnx(onnx_path, phase, task, email, auth_token):
|
|
19
|
+
"""Submit a standalone ONNX model (no policy.py required).
|
|
20
|
+
|
|
21
|
+
Works for elbow flexion and ChaseTag (obs→action graphs).
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
evalmc submit-onnx my_model.onnx -t elbowflexion -p 1
|
|
25
|
+
evalmc submit-onnx chase.onnx -t chasetag -p 1
|
|
26
|
+
"""
|
|
27
|
+
if onnx_path.suffix.lower() != ".onnx":
|
|
28
|
+
raise click.ClickException("File must have .onnx extension")
|
|
29
|
+
|
|
30
|
+
api_base = get_default_host()
|
|
31
|
+
email, auth_token = resolve_credentials(email, auth_token)
|
|
32
|
+
|
|
33
|
+
click.echo(f"Submitting {onnx_path.name} → task={task} phase={phase}")
|
|
34
|
+
|
|
35
|
+
with open(onnx_path, "rb") as f:
|
|
36
|
+
data = post_submission_file(
|
|
37
|
+
api_base,
|
|
38
|
+
"/submit/onnx",
|
|
39
|
+
task,
|
|
40
|
+
phase,
|
|
41
|
+
email,
|
|
42
|
+
auth_token,
|
|
43
|
+
file_field="onnx_model",
|
|
44
|
+
file_name=onnx_path.name,
|
|
45
|
+
file_obj=f,
|
|
46
|
+
content_type="application/octet-stream",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
echo_submission_result(data)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: evalmc
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Submit ONNX policies and Docker agents to MyoChallenge
|
|
5
|
+
Author-email: MyoChallenge Team <caggiano@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/MyoHub/mcEvalProd-CLI
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: click>=8.0.0
|
|
19
|
+
Requires-Dist: docker>=6.0.0
|
|
20
|
+
Requires-Dist: requests>=2.25.0
|
|
21
|
+
Requires-Dist: boto3>=1.26.0
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# evalmc
|
|
25
|
+
|
|
26
|
+
MyoChallenge submission CLI — upload ONNX policies or Docker agent images to
|
|
27
|
+
[mc26.myosuite.org](https://mc26.myosuite.org).
|
|
28
|
+
|
|
29
|
+
[](https://pypi.org/project/evalmc/)
|
|
30
|
+
[](https://pypi.org/project/evalmc/)
|
|
31
|
+
[](https://pypi.org/project/evalmc/)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install -U evalmc
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Default API: `https://api.mc.myosuite.org`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
evalmc host --set-host https://api.mc.myosuite.org
|
|
45
|
+
evalmc login
|
|
46
|
+
evalmc status
|
|
47
|
+
evalmc submit-onnx model.onnx -t chasetag -p 1
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`evalmc login` stores the email and auth token from the dashboard.
|
|
51
|
+
Credentials live in `~/.myochallenge/`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Commands
|
|
56
|
+
|
|
57
|
+
| Command | Purpose |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `evalmc host` | Show or set the API host |
|
|
60
|
+
| `evalmc login` | Save email + auth token |
|
|
61
|
+
| `evalmc status` | Confirm host and team |
|
|
62
|
+
| `evalmc submit-onnx` | Upload an ONNX policy |
|
|
63
|
+
| `evalmc nominate` | Pick a scored artifact for title-cycle finals |
|
|
64
|
+
| `evalmc push` | Submit a Docker / ECR agent image |
|
|
65
|
+
|
|
66
|
+
### ONNX
|
|
67
|
+
|
|
68
|
+
Recommended for ChaseTag. The graph is `obs → action`; no `policy.py` required.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
evalmc submit-onnx model.onnx -t chasetag -p 1
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Title-cycle nomination
|
|
75
|
+
|
|
76
|
+
Before freeze, choose which scored in-window submission plays in finals.
|
|
77
|
+
If you skip this, the platform uses your best score.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
evalmc nominate -t chasetag -p 1 --submission-id 123
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Docker
|
|
84
|
+
|
|
85
|
+
For custom Python around the policy. The image must ship `policy.py` and/or
|
|
86
|
+
`model.onnx` under `/policy` (or `/app`).
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
evalmc push my-agent:tag -t chasetag -p 1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
Some tracks are invitation-only. Registration and submission are rejected until
|
|
95
|
+
the team is on the whitelist. Leaderboards stay public.
|