Files

121 lines
4.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
patch_layouts_c5a.py — Chantier C5 · lot 1 (catalogue : charts natifs)
======================================================================
Ajoute bar_chart (L42), line_chart (L43) et donut_split (L44) à
layouts_v2.yaml par APPEND sécurisé (même mécanique que le patch C4 :
parse avant, contrôle de fin de bloc, backup, re-parse, restauration
automatique en cas d'échec — le fichier n'est jamais reformaté).
Après ce patch, propager : python3 prompt_injection_v2.py && python3
build_gallery.py
Usage (dossier du pipeline, single-line) :
python3 patch_layouts_c5a.py
"""
import shutil
import sys
from pathlib import Path
import yaml
TARGET = Path("layouts_v2.yaml")
FRAGMENT = """
# ── Chantier C5 lot 1 — charts natifs (éditables dans PowerPoint) ──
bar_chart:
id: L42
famille: Données
mode: light
champs: [titre, categories, series, unite, source, horizontal]
champs_requis: [titre, categories, series]
agent_hint: >-
Comparaison de valeurs par catégories — graphique NATIF éditable.
Max 8 catégories × 3 séries. series = liste de {label, values} ;
values = nombres SANS guillemets, alignés sur categories.
horizontal: true pour des barres (libellés longs). unite (ex M€)
et source optionnels. Couleurs imposées : navy, coral, glacier.
line_chart:
id: L43
famille: Données
mode: light
champs: [titre, points_x, series, unite, source]
champs_requis: [titre, points_x, series]
agent_hint: >-
Évolution temporelle — graphique NATIF éditable. Max 12 points ×
3 séries. points_x = libellés d'axe (mois, années...) ; series =
{label, values}, nombres sans guillemets. Le dernier point de la
première série est automatiquement mis en valeur (corail).
donut_split:
id: L44
famille: Données
mode: light
champs: [titre, segments, valeur_centrale, source]
champs_requis: [titre, segments]
agent_hint: >-
Répartition d'un tout : anneau à gauche + légende détaillée à
droite. 2 à 6 segments = {label, valeur} (nombres sans
guillemets). valeur_centrale (optionnelle) s'affiche au centre de
l'anneau (ex : total « 120 M€ »). Couleurs = cycle PR imposé.
"""
def fail(msg):
print(" ! %s" % msg)
sys.exit(1)
def main():
if not TARGET.exists():
fail("%s introuvable — lancer depuis le dossier du pipeline."
% TARGET)
raw = TARGET.read_text(encoding="utf-8")
try:
data = yaml.safe_load(raw)
except yaml.YAMLError as e:
fail("layouts_v2.yaml actuel illisible : %s" % e)
layouts = (data or {}).get("layouts")
if not isinstance(layouts, dict):
fail("Bloc layouts: introuvable dans le fichier.")
for key in ("bar_chart", "line_chart", "donut_split"):
if key in layouts:
fail("'%s' déjà présent — rien à faire." % key)
last = next((l for l in reversed(raw.splitlines())
if l.strip() and not l.strip().startswith("#")), "")
if not last.startswith(" "):
fail("Le fichier ne se termine pas dans le bloc layouts: "
"(dernière ligne non indentée : %r) — fusion manuelle "
"requise." % last[:40])
shutil.copy2(TARGET, str(TARGET) + ".bak-c5a")
print(" + Sauvegarde : %s.bak-c5a" % TARGET)
with open(TARGET, "a", encoding="utf-8") as f:
if not raw.endswith("\n"):
f.write("\n")
f.write(FRAGMENT)
try:
check = yaml.safe_load(TARGET.read_text(encoding="utf-8"))
nl = check["layouts"]
assert all(k in nl for k in ("bar_chart", "line_chart",
"donut_split"))
assert len(nl) == len(layouts) + 3
except Exception as e:
shutil.copy2(str(TARGET) + ".bak-c5a", TARGET)
fail("Contrôle post-append échoué (%s) — fichier restauré." % e)
print(" + bar_chart (L42), line_chart (L43), donut_split (L44) "
"ajoutés (%d layouts au total)." % (len(layouts) + 3))
print("\n Propager : python3 prompt_injection_v2.py && python3 "
"build_gallery.py")
if __name__ == "__main__":
main()