run_all_notebooks.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. """Run all eight analysis notebooks in their numbered order.
  2. This lightweight runner is useful on systems where Jupyter/nbconvert is not
  3. installed. It executes the same code cells and writes figures/tables to the
  4. top-level outputs directory.
  5. """
  6. from __future__ import annotations
  7. import json
  8. import os
  9. from pathlib import Path
  10. import traceback
  11. ROOT = Path(__file__).resolve().parent
  12. OUTPUTS = ROOT / "outputs"
  13. NOTEBOOKS = [
  14. *sorted((ROOT / "logistic" / "notebooks").glob("*.ipynb")),
  15. *sorted((ROOT / "bayesian" / "notebooks").glob("*.ipynb")),
  16. ]
  17. def run_notebook(path: Path) -> None:
  18. try:
  19. import matplotlib.pyplot as plt
  20. plt.close("all")
  21. except ImportError:
  22. pass
  23. document = json.loads(path.read_text(encoding="utf-8"))
  24. namespace = {"__name__": "__main__", "__file__": str(path)}
  25. print(f"\nRUNNING {path.relative_to(ROOT)}", flush=True)
  26. for index, cell in enumerate(document["cells"], start=1):
  27. if cell.get("cell_type") != "code":
  28. continue
  29. source = "".join(cell.get("source", []))
  30. exec(compile(source, f"{path}:cell-{index}", "exec"), namespace)
  31. print(f"PASSED {path.relative_to(ROOT)}", flush=True)
  32. def main() -> None:
  33. os.environ.setdefault("MPLBACKEND", "Agg")
  34. os.chdir(ROOT)
  35. OUTPUTS.mkdir(exist_ok=True)
  36. failures = []
  37. for path in NOTEBOOKS:
  38. try:
  39. run_notebook(path)
  40. except Exception:
  41. failures.append(str(path.relative_to(ROOT)))
  42. traceback.print_exc()
  43. if failures:
  44. raise SystemExit("Failed notebooks: " + ", ".join(failures))
  45. print("\nALL NOTEBOOK WORKFLOWS PASSED", flush=True)
  46. if __name__ == "__main__":
  47. main()