feat(gui): add GUI V6 G2 — onglet Utilisation + runner injectable

Onglet Utilisation fonctionnel (couche présentation only) :
- processing_runner: runner testable sans display/moteur lourd, process_fn
  injectable (défaut = process_document en import paresseux), découverte
  fichier/dossier, sorties anonymise/ comme V5 (arbo préservée), progression,
  journal, résumé OK/KO, arrêt coopératif entre documents, anti double-lancement
- tabs/tab_usage: sélection fichier/dossier + nb PDF détectés, dossier sortie
  (défaut anonymise/), Lancer/Arrêter, barre de progression, statut, journal,
  résumé ; worker threadé, file d'événements drainée par after() ; aucun réseau
- app.py: onglet Utilisation câblé (placeholder G2 retiré)
- self-test: couvre processing_runner + tab_usage

Tests: +11 (runner) — discovery, sorties, échec partiel, arrêt, anti-double-run,
callbacks. self-test exit 0, 32 tests gui_v6, 179 tests/unit (0 régression).
Moteur/V5/managers/specs intacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 18:58:10 +02:00
parent a6ee68a8a3
commit 9bc6537233
5 changed files with 534 additions and 7 deletions

View File

@@ -16,15 +16,17 @@ import sys
def _self_test() -> int:
"""Importe les modules du socle GUI V6 sans créer de fenêtre."""
from gui_v6 import app, license_client, license_store, theme # noqa: F401
from gui_v6.tabs import tab_about # noqa: F401
from gui_v6 import app, license_client, license_store, processing_runner, theme # noqa: F401
from gui_v6.tabs import tab_about, tab_usage # noqa: F401
# Sanity check des contrats publics du socle.
assert hasattr(app, "AnonymisationApp")
assert hasattr(license_client, "LicenseClient")
assert hasattr(license_client, "LicenseStatus")
assert hasattr(license_store, "LicenseStore")
assert hasattr(processing_runner, "ProcessingRunner")
assert hasattr(tab_about, "AboutTab")
assert hasattr(tab_usage, "UsageTab")
print("GUI V6 self-test OK")
return 0