- Nouvelle règle de tension dialectique (section 2), avec encadré du 03/08 rappelant que les seuils sont des instruments de diagnostic, pas des lois. - Reconstruction dialectique de l'introduction et des chapitres 1 à 3 (arcs argumentatifs, coutures, invariants restaurés). - Réécriture stylistique par l'API Gemini (bloc par bloc) des chapitres 1 à 3, suivie des contrôles de littéralité et de rythme. - Motif du tuyau installé une seconde fois au chapitre 4 ; six arbitrages du plan narratif tranchés et consignés. - Suppression de la préface (jamais rédigée) ; le fichier devient table-des-matieres.md, seul porteur du sommaire. - Archivage des quatre ouvertures de partie en prose, non compilées et redondantes avec l'annonce du plan dans l'introduction. - Essai de comparaison Gemini/Qwen consigné dans 00_REECRITURE_GEMINI.md section 10 (sorties jetables supprimées, outil conservé). - Audit de cohérence complet de la Partie 1 : invariants, renvois, appareil de notes, registre des sources, motifs, contrôles automatisés. Fichiers de méthode versionnés pour la première fois : 00_PLAN_NARRATIF.md, 00_PROMPTS_RECHERCHE.md, 00_REECRITURE_GEMINI.md.
502 lines
20 KiB
Python
502 lines
20 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
verifier-tuilage.py — mesure du TISSU CONJONCTIF (section 3 duodecies, règles B, C, D).
|
||
|
||
Troisième instrument du manuscrit, et il comble le trou nommé en propres termes
|
||
dans 00-COORDINATION.md : « le script n'a aucun indicateur de tissu conjonctif ».
|
||
|
||
· `detecteur-ia.py` mesure le RYTHME (longueurs, couperets, tirets)
|
||
· `verifier-litteralite.py` mesure la FORMULATION (survalorisation, gabarits)
|
||
· `verifier-tuilage.py` mesure L'ARTICULATION (ce qui relie une phrase à la suivante)
|
||
|
||
Le défaut visé est celui relevé par l'auteur le 30/07/2026 : « une suite de
|
||
phrases sans lien fort qui guide le lecteur ». Il est invisible aux deux autres
|
||
scripts, qui délivrent un verdict « conforme » sur un texte dont chaque phrase
|
||
est posée à plat à côté de la précédente.
|
||
|
||
QUATRE MESURES
|
||
|
||
1. PHRASES ORPHELINES — une phrase est accrochée à celle qui la précède par au
|
||
moins un de ces trois liens : une reprise lexicale (un mot plein commun),
|
||
une entrée anaphorique (« Ce silence… », « Elle… », « Cette prudence… »),
|
||
ou une articulation explicite autorisée par la règle B (`parce que`,
|
||
`puisque`, `alors que`, deux-points…). Aucun des trois : la phrase est
|
||
orpheline, et c'est au lecteur de deviner le rapport.
|
||
|
||
2. TUILAGE STRICT — forme exigeante du même contrôle, celle de la consigne de
|
||
l'auteur : le concept qui CLÔT une phrase doit amorcer la suivante. On ne
|
||
regarde donc que la queue de la phrase N (six mots pleins) et la tête de la
|
||
phrase N+1 (cinq mots pleins). Un texte peut n'avoir aucune orpheline et un
|
||
taux de tuilage médiocre : les liens y sont réels mais lointains, et le
|
||
lecteur avance sans être porté.
|
||
|
||
3. PHRASES PLATES — phrases de douze mots ou plus sans aucune subordination :
|
||
ni relative, ni conjonction, ni deux-points, ni point-virgule. Deux
|
||
propositions coordonnées par « et » restent plates. C'est la trace directe
|
||
du défaut décrit en section 3 duodecies : les tirets et les antithèses
|
||
supprimés ont été soldés par des points, et la subordination logique n'est
|
||
jamais revenue. La règle B l'autorise explicitement à l'intérieur d'une
|
||
phrase ; seules les charnières scolaires en TÊTE sont proscrites, et
|
||
celles-là sont comptées par `detecteur-ia.py`.
|
||
|
||
4. COUTURES SÈCHES (règle D, le gond) — passage d'un paragraphe au suivant sans
|
||
aucun lien lexical ni anaphorique. Le contrôle s'arrête aux frontières de
|
||
section : une couture sèche après un `##` est légitime.
|
||
|
||
Le rapport est découpé en BLOCS DE 500 À 800 MOTS, parce que c'est l'unité de
|
||
réécriture (voir .kiro/skills/reecrire-un-bloc/SKILL.md). Les blocs sont ensuite
|
||
classés du pire au meilleur : c'est la file de travail.
|
||
|
||
CE QUE CE SCRIPT NE VOIT PAS
|
||
— si le panneau indicateur (règle C) dit la bonne chose : il extrait la
|
||
première phrase de chaque paragraphe (`--fil`), la lecture reste à faire ;
|
||
— la qualité d'une reprise : « Cette chose » accroche formellement et
|
||
n'informe personne ;
|
||
— la musicalité, qui se juge à voix haute. Le CV local par bloc en donne un
|
||
indice, pas un verdict.
|
||
|
||
Usage :
|
||
python3 verifier-tuilage.py # tout le manuscrit
|
||
python3 verifier-tuilage.py Manuscrit/00-introduction.md # une section
|
||
python3 verifier-tuilage.py --detail Manuscrit/00-introduction.md # + les phrases fautives
|
||
python3 verifier-tuilage.py --fil Manuscrit/00-introduction.md # contrôle règle C
|
||
python3 verifier-tuilage.py --bloc 700 Manuscrit/01-*.md # autre taille de bloc
|
||
"""
|
||
|
||
import glob
|
||
import os
|
||
import re
|
||
import statistics
|
||
import sys
|
||
import unicodedata
|
||
from importlib.machinery import SourceFileLoader
|
||
|
||
_ICI = os.path.dirname(os.path.abspath(__file__))
|
||
_D = SourceFileLoader("_d", os.path.join(_ICI, "detecteur-ia.py")).load_module()
|
||
|
||
nettoyer = _D.nettoyer
|
||
paragraphes = _D.paragraphes
|
||
phrases = _D.phrases
|
||
mots = _D.mots
|
||
MANUSCRIT = _D.MANUSCRIT
|
||
|
||
# --- Mots vides : ils ne comptent jamais comme reprise lexicale --------------
|
||
# Verbes supports et adverbes de haute fréquence inclus : deux phrases qui
|
||
# partagent « faire » ou « déjà » ne sont pas tuilées pour autant.
|
||
|
||
VIDES = set("""
|
||
a ai ait aient as au aux aucun aucune aura auraient aurait auront aussi autant
|
||
autre autres avaient avais avait avant avec avoir avons ayant beaucoup bien
|
||
c car ce ceci cela celle celles celui cependant ces cet cette ceux chacun chaque
|
||
chez comme comment d dans de dedans dehors deja depuis des deux devait devant
|
||
devenir devient devrait doit doivent donc dont du duquel elle elles en encore
|
||
enfin entre es est et etaient etais etait etant ete etes etre eu eux fait faire
|
||
fais faisait fait faites fut furent grand grande ici il ils j jamais je jusqu
|
||
jusque l la laquelle le lequel les lesquels leur leurs lors lorsque lui m ma
|
||
mais me meme memes mes moi moins mon n ne ni non nos notre nous nul on ont ou
|
||
oui par parce pas peu peut peuvent plus plusieurs plutot pour pourquoi pourtant
|
||
pouvait pouvoir premier premiere pres pris puis puisque qu quand que quel quelle
|
||
quelles quelque quels qui quoi rien s sa sans se sera serait seront ses seul
|
||
seule si sien soit son sont sous souvent soi sur t ta tant te tel telle telles
|
||
tels tes toi ton toujours tous tout toute toutes tres trop tu un une va vais
|
||
vers veut voici voila voir vont vos votre vous y etait avait sera aurait
|
||
alors ainsi donc alors chose choses fois cas point points facon maniere
|
||
""".split())
|
||
|
||
# --- Reprises anaphoriques : la phrase désigne ce qui précède -----------------
|
||
# Elles sont cherchées dans les SIX PREMIERS MOTS, pas au seul premier : « Metz y
|
||
# lit que… » et « Le chiffre leur a paru petit » reprennent tous deux la phrase
|
||
# d'avant, sans commencer par le mot qui le fait.
|
||
|
||
ANAPHORIQUES = set("""
|
||
ce cet cette ces c celui celle ceux celles cela ca il elle ils elles on lui
|
||
leur leurs son sa ses y dont tel telle tels telles pareil pareille
|
||
chacun chacune aucun aucune rien voila meme memes
|
||
""".split())
|
||
|
||
FENETRE_ANAPHORE = 6
|
||
|
||
# --- Articulations autorisées par la règle B (subordination interne) ---------
|
||
|
||
ARTICULATION = re.compile(
|
||
r"\b(?:parce qu|puisqu?|car|au motif qu|alors qu|tandis qu|si bien qu|"
|
||
r"c'est-à-dire|de sorte qu|à mesure qu|dès qu|lorsqu?|quand|sauf qu|"
|
||
r"tant qu|au point qu|pour qu|afin qu|bien qu|quoiqu?|même si|comme si|"
|
||
r"sans qu|jusqu'à ce qu|d'autant qu|faute d|si\b.{0,40}\balors)"
|
||
r"|\b(?:qui|que|qu'|dont|où|lequel|laquelle|auquel|duquel|lesquels|"
|
||
r"desquels|auxquels)\b"
|
||
r"|[:;]",
|
||
re.I)
|
||
|
||
ARTICULATION_TETE = re.compile(
|
||
r"^(?:parce qu|puisqu|car|alors qu|tandis qu|si bien qu|c'est-à-dire|"
|
||
r"de sorte qu|à mesure qu|dès qu|lorsqu|quand|tant qu|pour qu|afin qu|"
|
||
r"bien qu|quoiqu|même si|comme si|sans qu|jusqu'à ce qu|d'autant qu|"
|
||
r"faute d|reste|restait|restent)",
|
||
re.I)
|
||
|
||
# --- Repères mesurés (calibrage : voir 00-COORDINATION.md, section 3 quaterdecies)
|
||
|
||
SEUILS = {
|
||
"pct_orphelines": 12.0, # PLAFOND : part de phrases sans aucun lien amont
|
||
"pct_tuilage": 62.0, # PLANCHER : queue de phrase reprise en tête de la suivante
|
||
"pct_plates": 30.0, # PLAFOND : phrases longues sans subordination
|
||
"pct_coutures": 18.0, # PLAFOND : passages de paragraphe sans gond
|
||
}
|
||
|
||
BLOC_DEFAUT = 650
|
||
BLOC_MIN, BLOC_MAX = 500, 800
|
||
|
||
|
||
# --- Outillage lexical -------------------------------------------------------
|
||
|
||
|
||
def sans_accent(mot):
|
||
return "".join(c for c in unicodedata.normalize("NFD", mot)
|
||
if unicodedata.category(c) != "Mn")
|
||
|
||
|
||
def pleins(phrase):
|
||
"""Racines approchées des mots pleins d'une phrase, dans l'ordre."""
|
||
sortie = []
|
||
for m in mots(phrase):
|
||
base = sans_accent(m.lower())
|
||
if base in VIDES or len(base) < 3:
|
||
continue
|
||
sortie.append(base[:5] if len(base) > 5 else base)
|
||
return sortie
|
||
|
||
|
||
def corps_seul(brut):
|
||
return brut.split("<!-- Notes de bas de page")[0]
|
||
|
||
|
||
def anaphorique(phrase):
|
||
"""Une reprise pronominale ou démonstrative dans les six premiers mots."""
|
||
for m in mots(phrase)[:FENETRE_ANAPHORE]:
|
||
for part in re.split(r"['’]", sans_accent(m.lower())):
|
||
if part in ANAPHORIQUES:
|
||
return True
|
||
return False
|
||
|
||
|
||
def articulee(phrase):
|
||
return bool(ARTICULATION.search(phrase))
|
||
|
||
|
||
def plate(phrase, longueur):
|
||
"""Phrase ample posée à plat : aucune subordination, aucune ponctuation forte."""
|
||
return longueur >= 12 and not articulee(phrase)
|
||
|
||
|
||
# --- Découpage en sections puis en paragraphes --------------------------------
|
||
|
||
|
||
def sections(texte):
|
||
"""Découpe la prose aux titres : une couture sèche après un `##` est licite."""
|
||
blocs, courant = [], []
|
||
for ligne in texte.split("\n"):
|
||
if ligne.lstrip().startswith("#"):
|
||
if courant:
|
||
blocs.append("\n".join(courant))
|
||
courant = []
|
||
continue
|
||
courant.append(ligne)
|
||
if courant:
|
||
blocs.append("\n".join(courant))
|
||
return [paragraphes(b) for b in blocs if paragraphes(b)]
|
||
|
||
|
||
def ligne_de(lignes, extrait):
|
||
cle = re.sub(r"\s+", " ", extrait).strip()[:28]
|
||
return next((i + 1 for i, l in enumerate(lignes) if cle and cle in l), 0)
|
||
|
||
|
||
# --- Analyse -----------------------------------------------------------------
|
||
|
||
|
||
def analyser(chemin, taille_bloc=BLOC_DEFAUT):
|
||
with open(chemin, encoding="utf-8") as f:
|
||
brut = f.read()
|
||
lignes = brut.split("\n")
|
||
texte = nettoyer(corps_seul(brut))
|
||
|
||
orphelines, plates_l, coutures = [], [], []
|
||
tuilees = liaisons = 0 # tuilage strict : numérateur / dénominateur
|
||
n_phrases = n_amples = 0
|
||
n_coutures = 0
|
||
blocs = []
|
||
bloc = None
|
||
|
||
def ouvrir():
|
||
return {"mots": 0, "phrases": 0, "orphelines": 0, "amples": 0,
|
||
"plates": 0, "tuilees": 0, "liaisons": 0, "coutures": 0,
|
||
"seches": 0, "longueurs": [], "ligne": 0, "para": 0}
|
||
|
||
for paras in sections(texte):
|
||
if bloc is not None: # un titre ferme toujours le bloc courant
|
||
blocs.append(bloc)
|
||
bloc = None
|
||
fin_precedente = None # queue du paragraphe précédent
|
||
for para in paras:
|
||
ph = [p for p in phrases(para) if mots(p)]
|
||
if not ph:
|
||
continue
|
||
if bloc is None:
|
||
bloc = ouvrir()
|
||
bloc["ligne"] = ligne_de(lignes, para)
|
||
bloc["para"] += 1
|
||
|
||
# --- couture avec le paragraphe précédent (règle D) ---
|
||
if fin_precedente is not None:
|
||
n_coutures += 1
|
||
bloc["coutures"] += 1
|
||
amont = set(fin_precedente)
|
||
if not (amont & set(pleins(ph[0]))) and not anaphorique(ph[0]):
|
||
bloc["seches"] += 1
|
||
coutures.append((ligne_de(lignes, para), ph[0]))
|
||
|
||
precedente = None
|
||
for p in ph:
|
||
longueur = len(mots(p))
|
||
n_phrases += 1
|
||
bloc["phrases"] += 1
|
||
bloc["mots"] += longueur
|
||
bloc["longueurs"].append(longueur)
|
||
|
||
if longueur >= 12:
|
||
n_amples += 1
|
||
bloc["amples"] += 1
|
||
if plate(p, longueur):
|
||
bloc["plates"] += 1
|
||
plates_l.append((ligne_de(lignes, para), p))
|
||
|
||
if precedente is not None:
|
||
liaisons += 1
|
||
bloc["liaisons"] += 1
|
||
amont = pleins(precedente)
|
||
aval = pleins(p)
|
||
ana = anaphorique(p)
|
||
art = bool(ARTICULATION_TETE.match(p.lstrip("«\"' ")))
|
||
lexical = bool(set(amont) & set(aval))
|
||
if not (lexical or ana or art):
|
||
bloc["orphelines"] += 1
|
||
orphelines.append((ligne_de(lignes, para), p))
|
||
# tuilage strict : la queue amorce la tête
|
||
if ana or (set(amont[-6:]) & set(aval[:5])):
|
||
tuilees += 1
|
||
bloc["tuilees"] += 1
|
||
precedente = p
|
||
|
||
fin_precedente = pleins(" ".join(ph[-2:]))
|
||
|
||
if bloc["mots"] >= taille_bloc:
|
||
blocs.append(bloc)
|
||
bloc = None
|
||
|
||
if bloc is not None:
|
||
blocs.append(bloc)
|
||
if not n_phrases:
|
||
return None
|
||
|
||
# fusion d'un dernier bloc résiduel trop court avec son voisin
|
||
if len(blocs) > 1 and blocs[-1]["mots"] < BLOC_MIN // 2:
|
||
queue = blocs.pop()
|
||
for cle in ("mots", "phrases", "orphelines", "amples", "plates",
|
||
"tuilees", "liaisons", "coutures", "seches", "para"):
|
||
blocs[-1][cle] += queue[cle]
|
||
blocs[-1]["longueurs"].extend(queue["longueurs"])
|
||
|
||
for b in blocs:
|
||
b["pct_orphelines"] = 100 * b["orphelines"] / b["liaisons"] if b["liaisons"] else 0
|
||
b["pct_tuilage"] = 100 * b["tuilees"] / b["liaisons"] if b["liaisons"] else 0
|
||
b["pct_plates"] = 100 * b["plates"] / b["amples"] if b["amples"] else 0
|
||
b["pct_seches"] = 100 * b["seches"] / b["coutures"] if b["coutures"] else 0
|
||
moy = statistics.mean(b["longueurs"]) if b["longueurs"] else 0
|
||
ec = statistics.pstdev(b["longueurs"]) if len(b["longueurs"]) > 1 else 0
|
||
b["cv"] = ec / moy if moy else 0
|
||
|
||
total_plates = sum(b["plates"] for b in blocs)
|
||
total_orph = len(orphelines)
|
||
total_seches = sum(b["seches"] for b in blocs)
|
||
|
||
return {
|
||
"fichier": os.path.basename(chemin),
|
||
"phrases": n_phrases,
|
||
"liaisons": liaisons,
|
||
"orphelines": orphelines,
|
||
"pct_orphelines": 100 * total_orph / liaisons if liaisons else 0,
|
||
"tuilees": tuilees,
|
||
"pct_tuilage": 100 * tuilees / liaisons if liaisons else 0,
|
||
"amples": n_amples,
|
||
"plates": plates_l,
|
||
"pct_plates": 100 * total_plates / n_amples if n_amples else 0,
|
||
"coutures": n_coutures,
|
||
"seches": coutures,
|
||
"pct_seches": 100 * total_seches / n_coutures if n_coutures else 0,
|
||
"blocs": blocs,
|
||
"texte": texte,
|
||
"lignes": lignes,
|
||
}
|
||
|
||
|
||
def verdict(r):
|
||
a = []
|
||
if r["pct_orphelines"] > SEUILS["pct_orphelines"]:
|
||
a.append("phrases juxtaposées sans lien amont")
|
||
if r["pct_tuilage"] < SEUILS["pct_tuilage"]:
|
||
a.append("tuilage insuffisant (la queue de phrase n'amorce pas la suivante)")
|
||
if r["pct_plates"] > SEUILS["pct_plates"]:
|
||
a.append("phrases amples posées à plat (subordination absente)")
|
||
if r["pct_seches"] > SEUILS["pct_coutures"]:
|
||
a.append("coutures de paragraphe sans gond")
|
||
return a
|
||
|
||
|
||
# --- Restitution -------------------------------------------------------------
|
||
|
||
|
||
def afficher(r, detail=False):
|
||
print("=" * 78)
|
||
print(r["fichier"])
|
||
print("=" * 78)
|
||
print(" Phrases analysées / liaisons internes : %d / %d"
|
||
% (r["phrases"], r["liaisons"]))
|
||
print(" PHRASES ORPHELINES : %-4d (%.1f %%) (plafond %.0f %%)"
|
||
% (len(r["orphelines"]), r["pct_orphelines"], SEUILS["pct_orphelines"]))
|
||
print(" TUILAGE STRICT : %-4d (%.1f %%) (plancher %.0f %%)"
|
||
% (r["tuilees"], r["pct_tuilage"], SEUILS["pct_tuilage"]))
|
||
print(" PHRASES PLATES (≥12 mots, sans subordination) : %-4d (%.1f %% des amples)"
|
||
" (plafond %.0f %%)"
|
||
% (len(r["plates"]), r["pct_plates"], SEUILS["pct_plates"]))
|
||
print(" COUTURES SÈCHES : %-4d sur %d passages (%.1f %%) (plafond %.0f %%)"
|
||
% (len(r["seches"]), r["coutures"], r["pct_seches"], SEUILS["pct_coutures"]))
|
||
|
||
print("\n Blocs de rédaction (%d à %d mots) — la file de travail :"
|
||
% (BLOC_MIN, BLOC_MAX))
|
||
print(" %-4s%-7s%-7s%-8s%-9s%-9s%-8s%s"
|
||
% ("n°", "ligne", "mots", "orph.", "tuilage", "plates", "CV", "état"))
|
||
for i, b in enumerate(r["blocs"], 1):
|
||
alertes = []
|
||
if b["pct_orphelines"] > SEUILS["pct_orphelines"]:
|
||
alertes.append("orph")
|
||
if b["pct_tuilage"] < SEUILS["pct_tuilage"]:
|
||
alertes.append("tuil")
|
||
if b["pct_plates"] > SEUILS["pct_plates"]:
|
||
alertes.append("plat")
|
||
if b["pct_seches"] > SEUILS["pct_coutures"]:
|
||
alertes.append("gond")
|
||
print(" %-4d%-7d%-7d%-8s%-9s%-9s%-8.2f%s"
|
||
% (i, b["ligne"], b["mots"],
|
||
"%.0f %%" % b["pct_orphelines"],
|
||
"%.0f %%" % b["pct_tuilage"],
|
||
"%.0f %%" % b["pct_plates"],
|
||
b["cv"],
|
||
" ".join(alertes) if alertes else "ok"))
|
||
|
||
pires = sorted(r["blocs"], key=lambda b: (b["pct_tuilage"] - b["pct_orphelines"]
|
||
- b["pct_plates"] / 2))[:5]
|
||
faibles = [b for b in pires if b["pct_tuilage"] < SEUILS["pct_tuilage"]
|
||
or b["pct_orphelines"] > SEUILS["pct_orphelines"]
|
||
or b["pct_plates"] > SEUILS["pct_plates"]]
|
||
if faibles:
|
||
print("\n À reprendre en priorité : "
|
||
+ ", ".join("bloc %d (l.%d)" % (r["blocs"].index(b) + 1, b["ligne"])
|
||
for b in faibles))
|
||
|
||
if detail:
|
||
if r["orphelines"]:
|
||
print("\n — Phrases orphelines (aucune reprise, aucune anaphore,"
|
||
" aucune articulation) :")
|
||
for ligne, p in r["orphelines"]:
|
||
print(" l.%-5d %s" % (ligne, re.sub(r"\s+", " ", p)[:150]))
|
||
if r["seches"]:
|
||
print("\n — Coutures sèches (règle D : poser un gond) :")
|
||
for ligne, p in r["seches"]:
|
||
print(" l.%-5d %s" % (ligne, re.sub(r"\s+", " ", p)[:150]))
|
||
if r["plates"]:
|
||
print("\n — Phrases amples sans subordination (règle B) :")
|
||
for ligne, p in r["plates"][:40]:
|
||
print(" l.%-5d %s" % (ligne, re.sub(r"\s+", " ", p)[:150]))
|
||
|
||
a = verdict(r)
|
||
print("\n → VERDICT : " + ("; ".join(a) if a else
|
||
"articulation conforme aux règles B, C et D"))
|
||
return not a
|
||
|
||
|
||
def afficher_fil(r):
|
||
"""Contrôle de la règle C : les premières phrases de paragraphe, à la file."""
|
||
print("=" * 78)
|
||
print("%s — LE FIL (premières phrases de paragraphe)" % r["fichier"])
|
||
print("=" * 78)
|
||
print(" Lues à la suite, elles doivent raconter le mouvement de la section.")
|
||
print(" Un trou dans ce récit est un panneau indicateur manquant.\n")
|
||
for paras in sections(r["texte"]):
|
||
for para in paras:
|
||
ph = phrases(para)
|
||
if not ph:
|
||
continue
|
||
print(" %s" % re.sub(r"\s+", " ", ph[0])[:150])
|
||
print()
|
||
|
||
|
||
def main():
|
||
args = [a for a in sys.argv[1:] if not a.startswith("--")]
|
||
detail = "--detail" in sys.argv
|
||
fil = "--fil" in sys.argv
|
||
taille = BLOC_DEFAUT
|
||
for a in sys.argv[1:]:
|
||
if a.startswith("--bloc"):
|
||
reste = a.split("=")[-1]
|
||
if reste.isdigit():
|
||
taille = int(reste)
|
||
if "--bloc" in sys.argv:
|
||
i = sys.argv.index("--bloc")
|
||
if i + 1 < len(sys.argv) and sys.argv[i + 1].isdigit():
|
||
taille = int(sys.argv[i + 1])
|
||
args = [a for a in args if a != sys.argv[i + 1]]
|
||
|
||
if args:
|
||
cibles = []
|
||
for a in args:
|
||
cibles.extend(sorted(glob.glob(a)) or [a])
|
||
else:
|
||
cibles = [f for f in MANUSCRIT
|
||
if os.path.exists(f) and os.path.getsize(f) > 1500]
|
||
|
||
tous_ok, resultats = True, []
|
||
for c in cibles:
|
||
if not os.path.exists(c):
|
||
print("[introuvable] %s" % c)
|
||
continue
|
||
r = analyser(c, taille)
|
||
if not r:
|
||
continue
|
||
resultats.append(r)
|
||
if fil:
|
||
afficher_fil(r)
|
||
else:
|
||
tous_ok &= afficher(r, detail)
|
||
|
||
if len(resultats) > 1 and not fil:
|
||
print("\n" + "=" * 78)
|
||
print("SYNTHÈSE")
|
||
print("=" * 78)
|
||
print("%-40s%9s%9s%9s%9s" % ("Fichier", "%orph", "%tuil", "%plates", "%sèches"))
|
||
for r in resultats:
|
||
print("%-40s%8.1f%%%8.1f%%%8.1f%%%8.1f%%"
|
||
% (r["fichier"], r["pct_orphelines"], r["pct_tuilage"],
|
||
r["pct_plates"], r["pct_seches"]))
|
||
print("\nRepères : orphelines ≤ %.0f %%, tuilage ≥ %.0f %%,"
|
||
" plates ≤ %.0f %%, coutures sèches ≤ %.0f %%"
|
||
% (SEUILS["pct_orphelines"], SEUILS["pct_tuilage"],
|
||
SEUILS["pct_plates"], SEUILS["pct_coutures"]))
|
||
|
||
sys.exit(0 if tous_ok else 1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|