#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ check_goldens.py — C0 · goldens de non-régression du moteur =========================================================== Rend chaque golden_*.yaml présent et compare sa STRUCTURE (nb de slides, nb de shapes par slide) au manifeste goldens_manifest.json. Le PPTX contient des timestamps : un diff binaire est impossible — la structure, elle, est déterministe et attrape les régressions de rendu (shape manquante, layout cassé, exception). python3 check_goldens.py → vérifie (code retour 1 si écart) python3 check_goldens.py --update → (re)génère le manifeste À lancer avant tout push moteur (ou en tâche DSM hebdo). """ import glob import json import subprocess import sys from pathlib import Path MANIFEST = Path("goldens_manifest.json") def structure(pptx_path): from pptx import Presentation prs = Presentation(pptx_path) return [len(list(s.shapes)) for s in prs.slides] def render_all(): out = {} for y in sorted(glob.glob("golden_*.yaml")): pptx = "_check_%s.pptx" % Path(y).stem r = subprocess.run( ["python3", "render_engine_v2.py", y, pptx, "--assets", "assets"], capture_output=True, text=True) if r.returncode != 0: print(" ! %s : le rendu ÉCHOUE\n%s" % (y, r.stdout[-400:])) sys.exit(1) out[y] = structure(pptx) Path(pptx).unlink(missing_ok=True) return out def main(): got = render_all() if "--update" in sys.argv: MANIFEST.write_text(json.dumps(got, indent=2)) print(" + Manifeste écrit : %d goldens, %d slides au total." % (len(got), sum(len(v) for v in got.values()))) return if not MANIFEST.exists(): print(" ! Pas de manifeste — lancer d'abord : " "python3 check_goldens.py --update") sys.exit(1) want = json.loads(MANIFEST.read_text()) ok = True for y, shapes in got.items(): ref = want.get(y) if ref is None: print(" ~ %s : nouveau golden (absent du manifeste)" % y) continue if shapes != ref: ok = False print(" ! %s : ÉCART — slides/shapes %s ≠ attendu %s" % (y, shapes, ref)) for y in want: if y not in got: ok = False print(" ! %s : golden du manifeste INTROUVABLE" % y) print(" %s" % ("✓ goldens conformes (%d fichiers)" % len(got) if ok else "✗ régression détectée")) sys.exit(0 if ok else 1) if __name__ == "__main__": main()