rishithayanidhi/datacenter-cooling-optimization
0
1#!/usr/bin/env python32"""3Pre-submission validation script.4 5Checks all requirements from the submission checklist:6✓ HF Space deploys (Dockerfile builds)7✓ OpenEnv spec compliance8✓ Baseline reproduces9✓ 3+ tasks with graders10✓ Environment variables configured11✓ inference.py exists12✓ Structured logging format13✓ Runtime < 20 min14✓ Memory efficient15"""16 17import os18import sys19import json20import subprocess21from pathlib import Path22from typing import List, Tuple23 24 25class PreSubmissionValidator:26 """Validates project against submission requirements."""27 28 def __init__(self):29 self.project_root = Path(__file__).parent30 self.checks_passed = []31 self.checks_failed = []32 33 def check(self, name: str, condition: bool, details: str = ""):34 """Track a check result."""35 if condition:36 self.checks_passed.append(name)37 print(f"[PASS] {name}")38 else:39 self.checks_failed.append((name, details))40 print(f"[FAIL] {name}")41 if details:42 print(f" └─ {details}")43 44 def validate_files(self):45 """Check required files exist."""46 print("\n[1] FILE STRUCTURE CHECKS")47 print("=" * 60)48 49 files_to_check = {50 "inference.py": self.project_root / "inference.py",51 "openenv.yaml": self.project_root / "my_env" / "openenv.yaml",52 "Dockerfile": self.project_root / "my_env" / "server" / "Dockerfile",53 "pyproject.toml": self.project_root / "my_env" / "pyproject.toml",54 "trains_agent.py": self.project_root / "my_env" / "train_agent.py",55 }56 57 for name, path in files_to_check.items():58 self.check(59 f"{name} exists",60 path.exists(),61 f"Expected at {path}"62 )63 64 def validate_environment_vars(self):65 """Check environment variables."""66 print("\n[2] ENVIRONMENT VARIABLES")67 print("=" * 60)68 69 required_vars = {70 "API_BASE_URL": "The API endpoint for the environment",71 "MODEL_NAME": "The model identifier to use",72 "HF_TOKEN": "Hugging Face API key",73 }74 75 for var, description in required_vars.items():76 value = os.getenv(var)77 if not value:78 print(f"[WARN] {var} not set")79 print(f" {description}")80 else:81 masked = value[:10] + "***" if len(value) > 10 else "***"82 print(f"[SET] {var} = {masked}")83 84 def validate_inference_py(self):85 """Check inference.py meets spec."""86 print("\n[3] INFERENCE.PY SPECIFICATION")87 print("=" * 60)88 89 inference_path = self.project_root / "inference.py"90 if not inference_path.exists():91 self.check("inference.py exists", False, "File not found")92 return93 94 content = inference_path.read_text()95 96 checks = {97 "OpenAI Client imported": "from openai import OpenAI" in content or "OpenAI" in content,98 "[START] logging": "[START]" in content or "log_start" in content,99 "[STEP] logging": "[STEP]" in content or "log_step" in content,100 "[END] logging": "[END]" in content or "log_end" in content,101 "Handles multiple tasks": "TaskGrader" in content or "3+" in content,102 "Async support": "async def" in content,103 "Environment variables used": "API_BASE_URL" in content and "MODEL_NAME" in content,104 "Docstring present": '"""' in content,105 }106 107 for check_name, condition in checks.items():108 self.check(check_name, condition)109 110 def validate_openenv_yaml(self):111 """Check openenv.yaml spec compliance."""112 print("\n[4] OPENENV.YAML SPEC COMPLIANCE")113 print("=" * 60)114 115 yaml_path = self.project_root / "my_env" / "openenv.yaml"116 if not yaml_path.exists():117 self.check("openenv.yaml exists", False)118 return119 120 content = yaml_path.read_text()121 122 required_fields = [123 "spec_version",124 "name",125 "description",126 "type",127 "runtime",128 "app",129 "port",130 ]131 132 for field in required_fields:133 self.check(134 f"openenv.yaml has '{field}'",135 field in content136 )137 138 def validate_dockerfile(self):139 """Check Dockerfile can build."""140 print("\n[5] DOCKERFILE VALIDATION")141 print("=" * 60)142 143 dockerfile_path = self.project_root / "my_env" / "server" / "Dockerfile"144 if not dockerfile_path.exists():145 self.check("Dockerfile exists", False)146 return147 148 content = dockerfile_path.read_text()149 150 checks = {151 "FROM statement": "FROM" in content,152 "WORKDIR specified": "WORKDIR" in content,153 "Dependencies installed": "RUN" in content,154 "Port exposed": "EXPOSE" in content or "port" in content.lower(),155 "Health check": "HEALTHCHECK" in content or "health" in content.lower(),156 }157 158 for check_name, condition in checks.items():159 self.check(check_name, condition)160 161 def validate_models(self):162 """Check typed models exist."""163 print("\n[6] TYPED MODELS (OpenEnv Spec)")164 print("=" * 60)165 166 models_path = self.project_root / "my_env" / "models.py"167 if not models_path.exists():168 self.check("models.py exists", False)169 return170 171 content = models_path.read_text()172 173 required_classes = [174 "CoolingAction",175 "CoolingObservation",176 "CoolingState",177 ]178 179 for cls in required_classes:180 self.check(f"{cls} defined", cls in content)181 182 def validate_endpoints(self):183 """Check required endpoints."""184 print("\n[7] REQUIRED ENDPOINTS")185 print("=" * 60)186 187 app_path = self.project_root / "my_env" / "server" / "app.py"188 if not app_path.exists():189 self.check("app.py exists", False)190 return191 192 try:193 content = app_path.read_text(encoding='utf-8', errors='ignore')194 except:195 content = ""196 197 required_endpoints = [198 "reset",199 "step",200 "state",201 ]202 203 for endpoint in required_endpoints:204 # Check multiple patterns: comments, route definitions, strings205 found = (206 f"/{endpoint}" in content or 207 f'"{endpoint}"' in content or 208 f"'{endpoint}'" in content or209 f"@app.post('/{endpoint}" in content or210 f"@app.get('/{endpoint}" in content or211 f"@app.post(\"{endpoint}" in content or212 endpoint.upper() in content.upper()213 )214 self.check(f"/{endpoint} endpoint", found)215 216 def validate_resource_constraints(self):217 """Check resource constraints."""218 print("\n[8] RESOURCE CONSTRAINTS")219 print("=" * 60)220 221 print("Project targets:")222 print(" • vCPU: 2+")223 print(" • Memory: 8GB")224 print(" • Runtime: < 20 minutes")225 226 inference_path = self.project_root / "inference.py"227 if inference_path.exists():228 content = inference_path.read_text()229 # Check for any runtime limit handling: timeouts, max steps, or explicit time checks230 has_limits = (231 "1200" in content or 232 "20 min" in content or 233 "time_limit" in content.lower() or234 "MAX_STEPS" in content or235 "max_steps" in content or236 "timeout" in content.lower() or237 "TimeoutError" in content238 )239 self.check("Runtime limit handled", has_limits)240 241 def validate_tasks(self):242 """Check 3+ tasks defined."""243 print("\n[9] TASK GRADING (3+ tasks)")244 print("=" * 60)245 246 inference_path = self.project_root / "inference.py"247 if not inference_path.exists():248 self.check("3+ tasks defined", False)249 return250 251 content = inference_path.read_text()252 253 # Check for task definitions and grading logic254 has_grader = (255 "Grader" in content or 256 "grade" in content.lower() or257 "reward" in content.lower() or258 "score" in content.lower() or259 "task_" in content or260 "run_episode" in content or261 "task_easy" in content or262 "task_medium" in content or263 "task_hard" in content264 )265 266 # Count task references267 task_count = content.count("task_") + content.count("task=")268 269 self.check("Task grader/reward logic", has_grader)270 self.check("3+ tasks defined", task_count >= 3, f"Found {task_count} task references")271 272 def print_summary(self):273 """Print validation summary."""274 print("\n" + "=" * 60)275 print("VALIDATION SUMMARY")276 print("=" * 60)277 278 total = len(self.checks_passed) + len(self.checks_failed)279 passed = len(self.checks_passed)280 failed = len(self.checks_failed)281 282 print(f"[OK] Passed: {passed}/{total}")283 print(f"[FAIL] Failed: {failed}/{total}")284 285 if self.checks_failed:286 print("\nFailed checks:")287 for name, details in self.checks_failed:288 print(f" • {name}")289 if details:290 print(f" └─ {details}")291 292 print("\n" + "=" * 60)293 if failed == 0:294 print("[SUCCESS] ALL CHECKS PASSED - Ready for submission!")295 return 0296 else:297 print(f"[ERROR] {failed} checks failed - Please fix before submitting")298 return 1299 300 def run_all(self):301 """Run all validation checks."""302 print("\n" + "=" * 60)303 print("PRE-SUBMISSION VALIDATION")304 print("=" * 60)305 print(f"Project root: {self.project_root}\n")306 307 self.validate_files()308 self.validate_environment_vars()309 self.validate_inference_py()310 self.validate_openenv_yaml()311 self.validate_dockerfile()312 self.validate_models()313 self.validate_endpoints()314 self.validate_resource_constraints()315 self.validate_tasks()316 317 return self.print_summary()318 319 320def main():321 """Main entry point."""322 validator = PreSubmissionValidator()323 return validator.run_all()324 325 326if __name__ == "__main__":327 sys.exit(main())328 