KChad commited on
Commit
e7005d5
·
1 Parent(s): 5f8c2e8

added something necessary

Browse files
Files changed (1) hide show
  1. pre_submission_check.py +218 -0
pre_submission_check.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import site
7
+ import socket
8
+ import subprocess
9
+ import sys
10
+ import time
11
+ import urllib.error
12
+ import urllib.request
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List
15
+
16
+
17
+ REPO_ROOT = Path(__file__).resolve().parent
18
+ REQUIRED_FILES = [
19
+ "inference.py",
20
+ "openenv.yaml",
21
+ "Dockerfile",
22
+ "uv.lock",
23
+ ]
24
+
25
+
26
+ def build_pythonpath() -> str:
27
+ parts: List[str] = []
28
+ candidates = [
29
+ REPO_ROOT,
30
+ REPO_ROOT / "src",
31
+ REPO_ROOT / ".deps",
32
+ ]
33
+ for candidate in candidates:
34
+ if candidate.exists():
35
+ parts.append(str(candidate))
36
+
37
+ try:
38
+ user_site = Path(site.getusersitepackages())
39
+ if user_site.exists():
40
+ parts.append(str(user_site))
41
+ except Exception:
42
+ pass
43
+
44
+ existing = os.environ.get("PYTHONPATH", "").strip()
45
+ if existing:
46
+ parts.append(existing)
47
+ return os.pathsep.join(parts)
48
+
49
+
50
+ def command_env() -> Dict[str, str]:
51
+ env = os.environ.copy()
52
+ env["PYTHONPATH"] = build_pythonpath()
53
+ return env
54
+
55
+
56
+ def run_command(args: List[str], timeout: int = 120, check: bool = False) -> subprocess.CompletedProcess[str]:
57
+ return subprocess.run(
58
+ args,
59
+ cwd=REPO_ROOT,
60
+ env=command_env(),
61
+ capture_output=True,
62
+ text=True,
63
+ timeout=timeout,
64
+ check=check,
65
+ )
66
+
67
+
68
+ def file_checks() -> Dict[str, Any]:
69
+ missing = [path for path in REQUIRED_FILES if not (REPO_ROOT / path).exists()]
70
+ return {
71
+ "name": "required_artifacts",
72
+ "passed": not missing,
73
+ "missing": missing,
74
+ }
75
+
76
+
77
+ def local_openenv_validation() -> Dict[str, Any]:
78
+ result = run_command([sys.executable, "-m", "openenv.cli", "validate", "--json"])
79
+ payload: Dict[str, Any]
80
+ try:
81
+ payload = json.loads(result.stdout.strip() or "{}")
82
+ except json.JSONDecodeError:
83
+ payload = {"raw_stdout": result.stdout}
84
+
85
+ return {
86
+ "name": "local_openenv_validate",
87
+ "passed": result.returncode == 0 and bool(payload.get("passed", False)),
88
+ "returncode": result.returncode,
89
+ "report": payload,
90
+ "stderr": result.stderr.strip(),
91
+ }
92
+
93
+
94
+ def pick_port() -> int:
95
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
96
+ sock.bind(("127.0.0.1", 0))
97
+ return int(sock.getsockname()[1])
98
+
99
+
100
+ def wait_for_health(url: str, timeout_s: float = 20.0) -> bool:
101
+ deadline = time.time() + timeout_s
102
+ while time.time() < deadline:
103
+ try:
104
+ with urllib.request.urlopen(f"{url}/health", timeout=2) as response:
105
+ payload = json.loads(response.read().decode("utf-8"))
106
+ if payload.get("status") in {"healthy", "ok"}:
107
+ return True
108
+ except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, ValueError):
109
+ time.sleep(0.5)
110
+ return False
111
+
112
+
113
+ def runtime_openenv_validation() -> Dict[str, Any]:
114
+ port = pick_port()
115
+ url = f"http://127.0.0.1:{port}"
116
+ env = command_env()
117
+ server = subprocess.Popen(
118
+ [
119
+ sys.executable,
120
+ "-m",
121
+ "uvicorn",
122
+ "server.app:app",
123
+ "--host",
124
+ "127.0.0.1",
125
+ "--port",
126
+ str(port),
127
+ ],
128
+ cwd=REPO_ROOT,
129
+ env=env,
130
+ stdout=subprocess.DEVNULL,
131
+ stderr=subprocess.DEVNULL,
132
+ text=True,
133
+ )
134
+
135
+ try:
136
+ if not wait_for_health(url):
137
+ return {
138
+ "name": "runtime_openenv_validate",
139
+ "passed": False,
140
+ "url": url,
141
+ "error": "Server did not become healthy in time.",
142
+ }
143
+
144
+ result = run_command(
145
+ [sys.executable, "-m", "openenv.cli", "validate", "--url", url],
146
+ timeout=120,
147
+ )
148
+ payload: Dict[str, Any]
149
+ try:
150
+ payload = json.loads(result.stdout.strip() or "{}")
151
+ except json.JSONDecodeError:
152
+ payload = {"raw_stdout": result.stdout}
153
+
154
+ return {
155
+ "name": "runtime_openenv_validate",
156
+ "passed": result.returncode == 0 and bool(payload.get("passed", False)),
157
+ "url": url,
158
+ "returncode": result.returncode,
159
+ "report": payload,
160
+ "stderr": result.stderr.strip(),
161
+ }
162
+ finally:
163
+ if server.poll() is None:
164
+ server.terminate()
165
+ try:
166
+ server.wait(timeout=10)
167
+ except subprocess.TimeoutExpired:
168
+ server.kill()
169
+
170
+
171
+ def summarize(results: List[Dict[str, Any]]) -> Dict[str, Any]:
172
+ failed = [result["name"] for result in results if not result.get("passed", False)]
173
+ return {
174
+ "passed": not failed,
175
+ "failed_checks": failed,
176
+ "checks": results,
177
+ }
178
+
179
+
180
+ def parse_args() -> argparse.Namespace:
181
+ parser = argparse.ArgumentParser(description="Run local pre-submission checks for the IDPI benchmark.")
182
+ parser.add_argument("--skip-runtime", action="store_true", help="Skip live runtime validation against a local server.")
183
+ parser.add_argument("--json", action="store_true", help="Emit a JSON report instead of a human summary.")
184
+ return parser.parse_args()
185
+
186
+
187
+ def print_human_report(report: Dict[str, Any]) -> None:
188
+ status = "PASS" if report["passed"] else "FAIL"
189
+ print(f"[{status}] Pre-submission check")
190
+ for check in report["checks"]:
191
+ check_status = "PASS" if check.get("passed", False) else "FAIL"
192
+ print(f"- {check_status}: {check['name']}")
193
+ if check["name"] == "required_artifacts" and check.get("missing"):
194
+ print(f" missing: {', '.join(check['missing'])}")
195
+ if check["name"].endswith("openenv_validate") and not check.get("passed", False):
196
+ if check.get("stderr"):
197
+ print(f" stderr: {check['stderr']}")
198
+ if check.get("error"):
199
+ print(f" error: {check['error']}")
200
+
201
+
202
+ def main() -> None:
203
+ args = parse_args()
204
+ results = [file_checks(), local_openenv_validation()]
205
+ if not args.skip_runtime:
206
+ results.append(runtime_openenv_validation())
207
+
208
+ report = summarize(results)
209
+ if args.json:
210
+ print(json.dumps(report, indent=2))
211
+ else:
212
+ print_human_report(report)
213
+
214
+ raise SystemExit(0 if report["passed"] else 1)
215
+
216
+
217
+ if __name__ == "__main__":
218
+ main()