Resolve giant condor wrapper from the active venv, not a hardcoded path
CI / Format (ruff format) (push) Successful in 29s
CI / Lint (ruff check) (push) Successful in 30s
CI / Sync project version with tag (push) Has been skipped
CI / Type check (ty) (push) Successful in 24s
CI / Tests (push) Failing after 58s

write_submit baked in cfg.repo_dir/.venv/bin/giant unconditionally, which
breaks when submitting from a differently-named or non-default venv (e.g.
--extra cuda). Prefer the giant executable next to sys.executable (the venv
actually running the submit), falling back to repo_dir/.venv/bin/giant.
This commit is contained in:
2026-08-03 14:46:54 +02:00
parent dae6451203
commit c3e5956718
+29 -9
View File
@@ -43,6 +43,7 @@ from __future__ import annotations
import json import json
import shutil import shutil
import sys
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
@@ -356,7 +357,7 @@ class SubmitConfig:
_WRAPPER = """#!/bin/bash _WRAPPER = """#!/bin/bash
set -euo pipefail set -euo pipefail
cd {repo_dir} cd {repo_dir}
exec {repo_dir}/.venv/bin/giant analyze compute-one --id "$1" --chunk "$2" --run-dir {run_dir} exec {giant_exe} analyze compute-one --id "$1" --chunk "$2" --run-dir {run_dir}
""" """
@@ -405,6 +406,29 @@ def _job_walltimes(
return jobs return jobs
def _resolve_giant_executable(repo_dir: Path) -> Path:
"""Path to the ``giant`` entry point to bake into the condor wrapper script.
Prefers the venv currently running this process (``sys.executable``'s
sibling ``giant``) so a submit from a non-default venv (e.g. ``--extra
cuda`` on a dev box) doesn't silently pick up a different one; falls back
to ``repo_dir/.venv/bin/giant`` for the case this is invoked from outside
any venv (e.g. a system Python).
"""
active = Path(sys.executable).parent / "giant"
if active.exists():
return active
venv_giant = repo_dir / ".venv" / "bin" / "giant"
if not venv_giant.exists():
raise FileNotFoundError(
f"no `giant` executable found next to {sys.executable} or at "
f"{venv_giant} — condor jobs run it directly (no `uv` on the "
f"worker image), so run `uv sync --extra cpu` in {repo_dir} "
"before submitting."
)
return venv_giant
def write_submit(cfg: SubmitConfig, ids: list[str] | None = None) -> Path: def write_submit(cfg: SubmitConfig, ids: list[str] | None = None) -> Path:
"""Write the wrapper script, (plot, chunk) job list, and HTCondor submit """Write the wrapper script, (plot, chunk) job list, and HTCondor submit
description. description.
@@ -422,13 +446,7 @@ def write_submit(cfg: SubmitConfig, ids: list[str] | None = None) -> Path:
independent values — checked equal up front so a mismatch is a clear error independent values — checked equal up front so a mismatch is a clear error
here rather than an ``IndexError`` out of ``_job_walltimes``. here rather than an ``IndexError`` out of ``_job_walltimes``.
""" """
venv_giant = cfg.repo_dir / ".venv" / "bin" / "giant" giant_exe = _resolve_giant_executable(cfg.repo_dir)
if not venv_giant.exists():
raise FileNotFoundError(
f"{venv_giant} not found — condor jobs run it directly (no `uv` on "
f"the worker image), so run `uv sync --extra cpu` in {cfg.repo_dir} "
"before submitting."
)
ids = ids or catalog_ids() ids = ids or catalog_ids()
run_dir = cfg.run_dir run_dir = cfg.run_dir
@@ -446,7 +464,9 @@ def write_submit(cfg: SubmitConfig, ids: list[str] | None = None) -> Path:
(run_dir / "reduced_partial").mkdir(parents=True, exist_ok=True) (run_dir / "reduced_partial").mkdir(parents=True, exist_ok=True)
wrapper = run_dir / "run_compute.sh" wrapper = run_dir / "run_compute.sh"
wrapper.write_text(_WRAPPER.format(repo_dir=cfg.repo_dir, run_dir=run_dir)) wrapper.write_text(
_WRAPPER.format(repo_dir=cfg.repo_dir, giant_exe=giant_exe, run_dir=run_dir)
)
wrapper.chmod(0o755) wrapper.chmod(0o755)
jobs = _job_walltimes(run_dir, ids, cfg.n_chunks) jobs = _job_walltimes(run_dir, ids, cfg.n_chunks)