Creates the isolated venv for an extension by running its setup.py. Called automatically after installing an extension from GitHub. Runs setup.py with Modly's embedded Python and the detected GPU SM.
(ext_id: str)
| 23 | |
| 24 | @router.post("/setup/{ext_id}") |
| 25 | async def setup_extension(ext_id: str): |
| 26 | """ |
| 27 | Creates the isolated venv for an extension by running its setup.py. |
| 28 | Called automatically after installing an extension from GitHub. |
| 29 | Runs setup.py with Modly's embedded Python and the detected GPU SM. |
| 30 | """ |
| 31 | from services.generator_registry import EXTENSIONS_DIR |
| 32 | |
| 33 | if EXTENSIONS_DIR is None or not EXTENSIONS_DIR.exists(): |
| 34 | raise HTTPException(400, "EXTENSIONS_DIR not configured") |
| 35 | |
| 36 | ext_dir = EXTENSIONS_DIR / ext_id |
| 37 | setup_py = ext_dir / "setup.py" |
| 38 | |
| 39 | if not ext_dir.exists(): |
| 40 | raise HTTPException(404, f"Extension '{ext_id}' not found in {EXTENSIONS_DIR}") |
| 41 | if not setup_py.exists(): |
| 42 | # No setup.py → legacy extension, nothing to do |
| 43 | return {"status": "skipped", "reason": "no setup.py"} |
| 44 | |
| 45 | # Detect GPU compute capability |
| 46 | gpu_sm = _detect_gpu_sm() |
| 47 | |
| 48 | # Run setup.py using Modly's embedded Python (sys.executable) |
| 49 | loop = asyncio.get_running_loop() |
| 50 | result = await loop.run_in_executor( |
| 51 | None, |
| 52 | lambda: subprocess.run( |
| 53 | [sys.executable, str(setup_py), sys.executable, str(ext_dir), str(gpu_sm)], |
| 54 | capture_output=True, |
| 55 | text=True, |
| 56 | ) |
| 57 | ) |
| 58 | |
| 59 | if result.returncode != 0: |
| 60 | raise HTTPException(500, f"setup.py failed:\n{result.stderr}") |
| 61 | |
| 62 | return { |
| 63 | "status": "ok", |
| 64 | "gpu_sm": gpu_sm, |
| 65 | "output": result.stdout, |
| 66 | } |
| 67 | |
| 68 | |
| 69 | @router.get("/errors") |
nothing calls this directly
no test coverage detected