Source code for spino.runner
"""
runner: headless subprocess entry point that executes the scheduling pipeline.
Usage::
python -m spino.runner /path/to/settings.json
It overlays the JSON settings onto the pipeline's ``phase_config`` module and
then calls ``phase_scheduler.main()``. The GUI launches this in a subprocess
and streams its stdout into the log pane; running it by hand is also the
recommended headless smoke test.
Why overlay-then-import: ``phase_scheduler`` binds ``CUSTOM_PLANETS`` at
*import* time (``from phase_config import CUSTOM_PLANETS``), so every override
must be applied to ``phase_config`` **before** ``phase_scheduler`` is imported.
The remaining globals are re-read inside ``main()`` and pick up the overrides
regardless.
"""
from __future__ import annotations
import os
import sys
# Force a headless matplotlib backend before any pipeline module imports pyplot.
import matplotlib
matplotlib.use("Agg")
_HERE = os.path.dirname(os.path.abspath(__file__))
PIPELINE_DIR = os.path.join(_HERE, "pipeline")
# Keys stored as JSON lists that the pipeline expects as tuples.
_TUPLE_KEYS = ("TELLURIC_LAMBDA_RANGE_NM", "TELLURIC_RV_GRID_KMS")
[docs]
def run(settings_path: str) -> int:
"""Apply *settings_path* to phase_config and run the pipeline.
Returns a process-style exit code (0 on success).
"""
if PIPELINE_DIR not in sys.path:
sys.path.insert(0, PIPELINE_DIR)
import json
with open(settings_path) as f:
settings = json.load(f)
import phase_config
for key, val in settings.items():
if key in _TUPLE_KEYS and isinstance(val, list):
val = tuple(val)
setattr(phase_config, key, val)
os.makedirs(phase_config.OUTPUT_DIR, exist_ok=True)
print(f"[runner] output dir: {phase_config.OUTPUT_DIR}", flush=True)
# Import AFTER overrides so the module-level CUSTOM_PLANETS binding is current.
import phase_scheduler
phase_scheduler.main()
print("[runner] done.", flush=True)
return 0
[docs]
def main() -> None:
if len(sys.argv) != 2:
print("usage: python -m spino.runner <settings.json>",
file=sys.stderr)
sys.exit(2)
sys.exit(run(sys.argv[1]))
if __name__ == "__main__":
main()