Python 75.9%
TeX 24%
1#!/usr/bin/env python32"""3================================================================4Auteur : Simon-Pierre Boucher5Contact : contact@spboucher.ai6Projet : Prévision de volatilité réalisée multi-actifs7 (HAR-RV vs GARCH vs Machine Learning)8Fichier : 09_build_paper.py9Description : Étape 09 — Vérification des headers de tous les10 fichiers de code, présence des tables/figures11 référencées, et compilation du PDF (latexmk).12Usage : python scripts/09_build_paper.py [--no-compile]13================================================================14"""1516from __future__ import annotations1718import argparse19import logging20import re21import subprocess22import sys23from pathlib import Path2425sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))2627from wp12 import config # noqa: E4022829logger = logging.getLogger("09_build_paper")3031ROOT = config.ROOT32HEADER_MARK = "Auteur : Simon-Pierre Boucher"333435def check_headers() -> bool:36 """Every .py / config / paper source file must carry the project header."""37 ok = True38 files = (39 list((ROOT / "src").rglob("*.py"))40 + list((ROOT / "scripts").glob("*.py"))41 + list((ROOT / "tests").glob("*.py"))42 + [ROOT / "config.yaml", ROOT / "requirements.txt"]43 + list((ROOT / "paper").glob("*.tex"))44 + list((ROOT / "paper" / "sections").glob("*.tex"))45 )46 for f in files:47 if "__pycache__" in str(f):48 continue49 head = f.read_text(encoding="utf-8", errors="ignore")[:600]50 if HEADER_MARK not in head:51 logger.error("MISSING HEADER: %s", f.relative_to(ROOT))52 ok = False53 logger.info("header check: %d files, %s", len(files), "OK" if ok else "FAILURES")54 return ok555657def check_inputs() -> bool:58 """All tables/figures referenced by the paper must exist on disk."""59 ok = True60 tex = ""61 for f in [ROOT / "paper" / "main.tex", *(ROOT / "paper" / "sections").glob("*.tex")]:62 tex += f.read_text(encoding="utf-8")63 for m in re.finditer(r"\\input\{(\.\./results/tables/[^}]+)\}", tex):64 p = (ROOT / "paper" / m.group(1)).resolve()65 p = p if p.suffix else p.with_suffix(".tex")66 if not p.exists():67 logger.error("missing table: %s", m.group(1))68 ok = False69 for m in re.finditer(r"\\includegraphics\[[^\]]*\]\{([^}]+)\}", tex):70 name = m.group(1)71 if name.startswith("uq_logo"):72 continue73 if not (ROOT / "figures" / name).exists():74 logger.error("missing figure: %s", name)75 ok = False76 logger.info("inputs check: %s", "OK" if ok else "FAILURES")77 return ok787980def compile_pdf() -> bool:81 """Compile the paper with latexmk (pdflatex + bibtex)."""82 res = subprocess.run(83 ["latexmk", "-pdf", "-interaction=nonstopmode", "main.tex"],84 cwd=ROOT / "paper", capture_output=True, text=True, timeout=600,85 )86 if res.returncode != 0:87 logger.error("latexmk failed:\n%s", res.stdout[-3000:])88 return False89 logger.info("PDF compiled: paper/main.pdf")90 return True919293def main() -> None:94 """Run all pre-flight checks, then compile."""95 ap = argparse.ArgumentParser()96 ap.add_argument("--no-compile", action="store_true")97 args = ap.parse_args()98 config.setup_logging()99 ok = check_headers() & check_inputs()100 if not args.no_compile:101 ok &= compile_pdf()102 sys.exit(0 if ok else 1)103104105if __name__ == "__main__":106 main()107