"""Run all eight analysis notebooks in their numbered order. This lightweight runner is useful on systems where Jupyter/nbconvert is not installed. It executes the same code cells and writes figures/tables to the top-level outputs directory. """ from __future__ import annotations import json import os from pathlib import Path import traceback ROOT = Path(__file__).resolve().parent OUTPUTS = ROOT / "outputs" NOTEBOOKS = [ *sorted((ROOT / "logistic" / "notebooks").glob("*.ipynb")), *sorted((ROOT / "bayesian" / "notebooks").glob("*.ipynb")), ] def run_notebook(path: Path) -> None: try: import matplotlib.pyplot as plt plt.close("all") except ImportError: pass document = json.loads(path.read_text(encoding="utf-8")) namespace = {"__name__": "__main__", "__file__": str(path)} print(f"\nRUNNING {path.relative_to(ROOT)}", flush=True) for index, cell in enumerate(document["cells"], start=1): if cell.get("cell_type") != "code": continue source = "".join(cell.get("source", [])) exec(compile(source, f"{path}:cell-{index}", "exec"), namespace) print(f"PASSED {path.relative_to(ROOT)}", flush=True) def main() -> None: os.environ.setdefault("MPLBACKEND", "Agg") os.chdir(ROOT) OUTPUTS.mkdir(exist_ok=True) failures = [] for path in NOTEBOOKS: try: run_notebook(path) except Exception: failures.append(str(path.relative_to(ROOT))) traceback.print_exc() if failures: raise SystemExit("Failed notebooks: " + ", ".join(failures)) print("\nALL NOTEBOOK WORKFLOWS PASSED", flush=True) if __name__ == "__main__": main()