diff --git a/picarones/__init__.py b/picarones/__init__.py index b0346af337c322d455e3d9184a354a36c92e497c..1defde1efd094df835aaf3a06391eb62d986225f 100644 --- a/picarones/__init__.py +++ b/picarones/__init__.py @@ -2,8 +2,8 @@ Licence Apache 2.0. -API publique du Cercle 1 (abstractions stables) ré-exportée ici pour -permettre : +API publique des couches 1 & 3 (abstractions stables) ré-exportée +ici pour permettre : >>> from picarones import Corpus, Document, BaseModule, ArtifactType >>> from picarones import BenchmarkResult, EngineReport, DocumentResult @@ -16,7 +16,7 @@ utiliser les sous-packages explicites : >>> from picarones.adapters.ocr.tesseract import TesseractAdapter Voir ``docs/explanation/architecture.md`` pour la cartographie complète des -3 cercles, et ``docs/reference/api-stable.md`` pour le contrat de stabilité. +8 couches, et ``docs/reference/api-stable.md`` pour le contrat de stabilité. """ from __future__ import annotations @@ -41,7 +41,7 @@ __author__ = "Picarones contributors" # ────────────────────────────────────────────────────────────────────────── -# API publique — Cercle 1 uniquement +# API publique — couches stables (domain + evaluation) # ────────────────────────────────────────────────────────────────────────── from picarones.evaluation.corpus import ( @@ -75,12 +75,10 @@ from picarones.evaluation.metric_registry import ( select_metrics, ) -# Sprint A3 — trigger d'enregistrement du registre typé (Sprint 34). -# L'import de ``picarones.measurements`` provoque l'exécution des -# décorateurs ``@register_metric`` sur ``cer``, ``wer``, ``mer``, -# ``wil`` + ~15 métriques philologiques + reading order + NER + ALTO. -# Ce trigger remplace l'ancien import croisé Cercle 1 → Cercle 2 dans -# ``core/pipeline.py`` (violation B-1/B-2 du même esprit). +# Trigger d'enregistrement du registre typé : l'import de +# ``picarones.evaluation.metrics`` provoque l'exécution des décorateurs +# ``@register_metric`` sur ``cer``, ``wer``, ``mer``, ``wil`` + ~15 +# métriques philologiques + reading order + NER + ALTO. import picarones.evaluation.metrics as _trigger_metric_registration # noqa: F401, E402 __all__ = [ diff --git a/picarones/adapters/corpus/_fallback_log.py b/picarones/adapters/corpus/_fallback_log.py index ac7df34a631eb97f739ee0265446684ce5ecbb5d..a793e2974718738264e7dd563f1b690a1a27b8a9 100644 --- a/picarones/adapters/corpus/_fallback_log.py +++ b/picarones/adapters/corpus/_fallback_log.py @@ -15,7 +15,7 @@ Conception volontairement minimale : Le détecteur de Fact correspondant (``FactType.IMPORTER_FALLBACK_TRIGGERED``) est implémenté dans -:mod:`picarones.measurements.narrative.detectors.history`. +:mod:`picarones.evaluation.metrics.narrative.detectors.history`. """ from __future__ import annotations diff --git a/picarones/adapters/ocr/__init__.py b/picarones/adapters/ocr/__init__.py index 9376ffacd3b1a15dfc5f3aef044f23e0b8215d69..59560a2b31403dbdceb334cc327b3da263b89426 100644 --- a/picarones/adapters/ocr/__init__.py +++ b/picarones/adapters/ocr/__init__.py @@ -1,20 +1,19 @@ -"""Adapters OCR du nouveau monde — Sprint A14-S26. +"""Adapters OCR — couche 5 (libs externes autorisées). -Contrat ``BaseOCRAdapter`` natif au rewrite : pas hérité du legacy -``picarones.engines.base.BaseOCREngine``, exprimé directement en -termes du nouveau ``ArtifactType`` et de l'interface -``execute(inputs, params, context)`` du ``PipelineExecutor``. +Contrat ``BaseOCRAdapter`` exprimé en termes du ``ArtifactType`` +et de l'interface ``execute(inputs, params, context)`` consommée +par ``PipelineExecutor``. Implémentations livrées ----------------------- +- ``TesseractAdapter`` — Tesseract 5 (OSS, CPU-bound). +- ``PeroOCRAdapter`` — Pero OCR (manuscrits, GPU recommandé). +- ``MistralOCRAdapter`` — Mistral OCR API (cloud). +- ``GoogleVisionAdapter`` — Google Vision API (cloud). +- ``AzureDocIntelAdapter`` — Azure Document Intelligence (cloud). - ``PrecomputedTextAdapter`` — lit un texte OCR pré-calculé depuis le filesystem. Cas BnF : comparer N transcriptions déjà produites par d'autres outils sans relancer d'OCR. - -Adapters concrets pour Tesseract / Pero OCR / Mistral OCR / Google -Vision / Azure DI : à écrire au cas par cas dans des sprints -dédiés, **natifs** au nouveau contrat (pas de shim sur le legacy -``picarones.engines``). """ from __future__ import annotations diff --git a/picarones/adapters/ocr/azure_doc_intel.py b/picarones/adapters/ocr/azure_doc_intel.py index 9585a4fcaf285440f0279dd30aed5e300f122e39..68619dcb8bdfd6443f1849310891cc5ca1bcc2bb 100644 --- a/picarones/adapters/ocr/azure_doc_intel.py +++ b/picarones/adapters/ocr/azure_doc_intel.py @@ -1,10 +1,6 @@ """``AzureDocIntelAdapter`` natif — Sprint A14-S34. - -Migration native du legacy ``picarones.engines.azure_doc_intel`` vers ``BaseOCRAdapter`` (S26). **Pas un shim**. -Le legacy reste en place jusqu'au S46. - Cas d'usage BnF --------------- Azure Document Intelligence (anciennement Form Recognizer) propose @@ -52,7 +48,7 @@ Comportement Anti-sur-ingénierie ------------------- -- Pas d'extraction de confidences (legacy S51 — reportée). +- Pas d'extraction de confidences (à ajouter quand un caller en aura besoin). - Pas de support multi-langue dans une même requête. - Pas de retry au-delà du polling (qui est un retry implicite). """ diff --git a/picarones/adapters/ocr/base.py b/picarones/adapters/ocr/base.py index 8aa7d3ad708f6d7bcf08f4d634e701d13b308e80..2399c6256dbfa34ff946edbadaf957746536ab8c 100644 --- a/picarones/adapters/ocr/base.py +++ b/picarones/adapters/ocr/base.py @@ -1,12 +1,4 @@ -"""``BaseOCRAdapter`` — contrat natif du nouveau monde pour un adapter OCR. - -Sprint A14-S26 du rewrite ciblé. - -Ce module définit le contrat **propre** auquel un adapter OCR du -nouveau monde doit se conformer pour être utilisable comme step -d'une pipeline ``picarones.pipeline``. Pas hérité du legacy -``picarones.engines.base.BaseOCREngine`` — c'est un nouveau contrat, -sans dette technique, exprimé en termes du nouveau ``ArtifactType``. +"""``BaseOCRAdapter`` — contrat pour un adapter OCR (couche 5). Contrat ------- @@ -22,23 +14,9 @@ Un adapter OCR : - Implémente ``execute(inputs, params, context) -> dict[ArtifactType, Artifact]``. -Le ``Artifact`` retourné porte une ``uri`` filesystem — c'est la -convention du nouveau monde pour permettre au ``payload_loader`` de -le lire ultérieurement (Sprint S25 — la projection a un payload -direct, mais les artefacts produits par les adapters sont stockés -sur disque pour traçabilité et streaming). - -Différences avec le legacy --------------------------- -- ``ArtifactType.RAW_TEXT`` (10 valeurs) au lieu de - ``ArtifactType.TEXT`` (6 valeurs legacy). -- Pas de ``run(image_path)`` historique — un seul point d'entrée - ``execute()``. -- Pas de wrapper ``EngineResult`` — les erreurs lèvent directement, - le ``PipelineExecutor`` les capture en step en échec. -- Pas de ``_run_ocr`` / ``_run_with_native`` / ``_extract_raw_confidences`` - — les confidences (S42 legacy) sont reportées à un sprint dédié - où l'on définira un ``ConfidenceArtifact`` typé. +Le ``Artifact`` retourné porte une ``uri`` filesystem — convention +qui permet au ``payload_loader`` de le lire ultérieurement et +garantit la traçabilité et le streaming. Anti-sur-ingénierie ------------------- diff --git a/picarones/adapters/ocr/factory.py b/picarones/adapters/ocr/factory.py index 95f44e177fd738e7eb5f98cdb5358a06fa2a9ec5..e8c807b9a1853c417af2af2a9c8d12cb05ba4739 100644 --- a/picarones/adapters/ocr/factory.py +++ b/picarones/adapters/ocr/factory.py @@ -1,9 +1,6 @@ """Factory canonique : instancier un ``BaseOCRAdapter`` par nom court. Sprint H.2.b du plan v2.0 — équivalent canonique de -``picarones.adapters.legacy_engines.factory.engine_from_name`` qui -retournait des ``BaseOCREngine`` (legacy, ``run(image_path) → -EngineResult``). Cette factory retourne des ``BaseOCRAdapter`` (rewrite, ``StepExecutor`` Protocol, ``execute(inputs, params, context) → dict[ArtifactType, Artifact]``). @@ -15,14 +12,6 @@ Vit en couche 5 (``picarones.adapters.ocr``) plutôt qu'en Cette factory ne dépend d'aucune brique de couche supérieure (pas de ``click``, pas de FastAPI). -Migration depuis le legacy --------------------------- -Code legacy :: - - from picarones.adapters.legacy_engines.factory import engine_from_name - engine = engine_from_name("tesseract", lang="fra", psm=6) - # engine est un BaseOCREngine, à wrapper via LegacyOCREngineExecutor - # avant de pouvoir être consommé par PipelineExecutor. Code canonique équivalent :: diff --git a/picarones/adapters/ocr/google_vision.py b/picarones/adapters/ocr/google_vision.py index 521a57183fda78b0e0346895183c5d06f478cbea..7ed0aaaabf833c4f8a98befe6944e5586337a31f 100644 --- a/picarones/adapters/ocr/google_vision.py +++ b/picarones/adapters/ocr/google_vision.py @@ -1,10 +1,5 @@ """``GoogleVisionAdapter`` natif — Sprint A14-S33. -Migration native du legacy ``picarones.engines.google_vision.GoogleVisionEngine`` -vers le contrat ``BaseOCRAdapter`` (S26). **Pas un shim**. - -Le legacy reste en place jusqu'au S46. - Cas d'usage BnF --------------- Google Cloud Vision propose deux modes d'OCR : @@ -36,7 +31,7 @@ disponible. Anti-sur-ingénierie ------------------- -- Pas d'extraction de confidences (legacy S50 — reportée). +- Pas d'extraction de confidences (à ajouter quand un caller en aura besoin). - Pas de pré-validation du JSON service account — le SDK le fait. - Pas de support batch — un appel par image. """ diff --git a/picarones/adapters/ocr/mistral_ocr.py b/picarones/adapters/ocr/mistral_ocr.py index 3507b69bc5baa550fb0010053bbf060732695077..9aaa001c1a35ac0b3013ba551de97214f52a3175 100644 --- a/picarones/adapters/ocr/mistral_ocr.py +++ b/picarones/adapters/ocr/mistral_ocr.py @@ -1,11 +1,6 @@ """``MistralOCRAdapter`` natif — Sprint A14-S32. - -Migration native du legacy ``picarones.engines.mistral_ocr.MistralOCREngine`` -vers le contrat ``BaseOCRAdapter`` (S26). **Pas un shim** : la classe implémente directement le contrat du nouveau monde. -Le legacy ``MistralOCREngine`` reste en place jusqu'au S46. - Cas d'usage BnF --------------- Mistral AI fournit deux familles d'OCR : @@ -47,8 +42,7 @@ Comportement Anti-sur-ingénierie ------------------- - Pas de retry / backoff (le caller wrappe si besoin). -- Pas d'extraction de confidences (legacy S49 — reportées au - sprint ``ConfidenceArtifact``). +- Pas d'extraction de confidences (à ajouter quand un caller en aura besoin). - Pas de support multi-page (l'image est traitée comme une seule page d'entrée — Mistral OCR retourne une liste de pages dont on concatène les markdowns). diff --git a/picarones/adapters/ocr/pero_ocr.py b/picarones/adapters/ocr/pero_ocr.py index c4efcc286c74d38738547faef9ca4dc00ebd1f56..87936f07138b763add5be44ac539e887f386e683 100644 --- a/picarones/adapters/ocr/pero_ocr.py +++ b/picarones/adapters/ocr/pero_ocr.py @@ -1,12 +1,5 @@ """``PeroOCRAdapter`` natif — Sprint A14-S31. - -Migration native du legacy ``picarones.engines.pero_ocr.PeroOCREngine`` -vers le contrat ``BaseOCRAdapter`` (S26). **Pas un shim** : la classe implémente directement le contrat du nouveau monde, sans héritage du -legacy. - -Le legacy ``PeroOCREngine`` reste en place pour les callers qui -n'ont pas encore migré ; sa suppression viendra au S46 quand la parité sera atteinte sur tous les adapters. Cas d'usage BnF @@ -42,8 +35,7 @@ Comportement Anti-sur-ingénierie ------------------- - Pas de support GPU explicite (Pero OCR le gère via la config). -- Pas de retry, pas d'extraction de confidences (legacy S48 — - reportées au sprint ``ConfidenceArtifact``). +- Pas de retry, pas d'extraction de confidences (à ajouter quand un caller en aura besoin). - ``_parser`` lazy-init — si l'instance est sérialisée pour ProcessPool, le parser est re-instancié dans le worker (cohérent avec Pero OCR qui charge ses modèles à l'instanciation). diff --git a/picarones/adapters/ocr/tesseract.py b/picarones/adapters/ocr/tesseract.py index c740a5575c299bc52c888da614a631671b803adc..f5eb4ebac3a64b6d5019f31e0f4f8b04079c8756 100644 --- a/picarones/adapters/ocr/tesseract.py +++ b/picarones/adapters/ocr/tesseract.py @@ -1,13 +1,7 @@ -"""``TesseractAdapter`` natif — Sprint A14-S30. +"""``TesseractAdapter`` — adapter natif pour Tesseract 5. -Migration native du legacy ``picarones.engines.tesseract.TesseractEngine`` -vers le contrat ``BaseOCRAdapter`` (S26). **Pas un shim** : la classe -implémente directement le contrat du nouveau monde, sans héritage du -legacy. - -Le legacy ``TesseractEngine`` reste en place pour les callers qui -n'ont pas encore migré ; sa suppression viendra au S46 quand la -parité sera atteinte sur tous les adapters. +Implémente le contrat ``BaseOCRAdapter`` (couche 5) : +``execute(inputs, params, context) → dict[ArtifactType, Artifact]``. Cas d'usage BnF --------------- @@ -52,10 +46,9 @@ Anti-sur-ingénierie ------------------- - Pas de retry — Tesseract échoue rarement sur une image valide, et un appelant peut wrapper si besoin. -- Pas d'extraction de confidences (legacy S47) — reporté à un - sprint dédié qui définira ``ConfidenceArtifact`` typé. La - fonctionnalité reste disponible via le legacy - ``picarones.engines.tesseract.TesseractEngine`` jusqu'au S46. +- Pas d'extraction de confidences pour l'instant : à ajouter + quand un caller en aura besoin (un ``ConfidenceArtifact`` typé + reste à définir). - Pas de validation de l'encodage de l'image — Tesseract gère. - Pas de support batch — un appel par image (le runner gère le parallélisme inter-documents). diff --git a/picarones/adapters/storage/__init__.py b/picarones/adapters/storage/__init__.py index 26766e4c279a32178689491e4770d7f22e8b0590..3cce6b0b482c6693f7af453d3ba8491443d5ba97 100644 --- a/picarones/adapters/storage/__init__.py +++ b/picarones/adapters/storage/__init__.py @@ -25,7 +25,7 @@ abstraction ABC. Cibles à venir -------------- - S37 : déplacement de ``picarones.web.jobs`` (SQLite job store). -- Post-livraison : ``picarones.measurements.history`` (SQLite +- Post-livraison : ``picarones.evaluation.metrics.history`` (SQLite history) et stores distribués (S3, GCS, …). """ diff --git a/picarones/app/services/benchmark_runner.py b/picarones/app/services/benchmark_runner.py index 570d14435c1a0eed219edcadfc95083284896fdd..1cf147381c2b78b3435a57b599f1344264090ef3 100644 --- a/picarones/app/services/benchmark_runner.py +++ b/picarones/app/services/benchmark_runner.py @@ -1,34 +1,19 @@ -"""Sprint D.1 du plan v2.0 — adapter de compat ``run_benchmark`` legacy -→ ``BenchmarkService`` rewrite. - -Ce module présente l'API mono-call historique de -``picarones.measurements.runner.run_benchmark`` mais s'appuie en -interne sur le rewrite (``BenchmarkService``, -``PipelineExecutor``, ``CorpusRunner``). Il sert de pont -transitoire pour faciliter la migration des callers en plusieurs -étapes : - -1. (cette session) Helpers de mapping ``Corpus`` ↔ ``CorpusSpec`` - et ``Document`` ↔ ``DocumentRef`` — testables indépendamment. -2. (sub-phase D.1.b) Mapping ``BaseOCREngine`` → ``PipelineSpec`` - + adapter resolver. -3. (sub-phase D.1.c) Conversion ``RunResult`` → ``BenchmarkResult``. -4. (sub-phase D.1.d) Fonction ``run_benchmark_via_service`` - complète avec progress callback, output_json, partial_dir. -5. (sub-phase D.1.e) Tests d'équivalence numérique (CER/WER) entre - les deux runners sur les fixtures. - -Trace de retrait ----------------- -Ce module est **transitoire** (Sprint D du plan v2.0). Il sera -supprimé en D.6 quand tous les callers (cli/_workflows, -web/benchmark_utils) consommeront ``BenchmarkService`` -directement. - -Cette première itération n'expose que les helpers de mapping -documents/corpus — la fonction publique -``run_benchmark_via_service`` arrive dans une session ultérieure -quand toutes les briques seront en place. +"""Entry point CLI/web — façade ``run_benchmark_via_service``. + +Présente l'API mono-call ``run_benchmark_via_service(corpus, +engines, ...)`` consommée par ``picarones.interfaces.cli`` et +``picarones.interfaces.web``. S'appuie en interne sur le service +canonique (``BenchmarkService``, ``PipelineExecutor``, +``CorpusRunner``). + +Pourquoi cette façade +--------------------- +``BenchmarkService`` consomme ``CorpusSpec`` (références +filesystem, Pydantic, immutable) et ``PipelineSpec`` (déclaratif). +Les interfaces utilisateur (CLI, web upload) raisonnent en +``Corpus`` riche en behavior + liste de moteurs OCR/LLM. Ce +module fait la conversion entre les deux modèles, expose une API +mono-call ergonomique et restitue un ``BenchmarkResult``. """ from __future__ import annotations @@ -37,11 +22,6 @@ import logging from pathlib import Path from typing import TYPE_CHECKING, Any, Callable -# Sprint H.2.c.1 — ``LegacyOCREngineExecutor`` n'est plus consommé : -# tous les callers passent désormais des ``BaseOCRAdapter`` canoniques -# (déjà ``StepExecutor`` natifs). L'import est retiré ; le code path -# legacy de ``build_adapter_resolver`` est désormais inaccessible et -# peut être supprimé en H.2.c.2. from picarones.domain.artifacts import ArtifactType from picarones.domain.corpus import CorpusSpec from picarones.domain.documents import DocumentRef, GroundTruthRef @@ -58,15 +38,15 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) -# Pas d'import direct de ``picarones.pipelines.base.OCRLLMPipeline`` ici — -# l'invariant architectural ``test_layer_imports_are_legal[layer-app]`` -# interdit à ``app/`` de dépendre du legacy. On consomme un -# ``OCRLLMPipeline`` exclusivement par duck typing (``is_pipeline``, -# ``ocr_engine``, ``llm_adapter``, ``mode``, ``prompt_template``). +# Le ``OCRLLMPipelineConfig`` (couche 4) est consommé exclusivement +# par duck typing (``is_pipeline``, ``ocr_adapter``, ``llm_adapter``, +# ``mode``, ``prompt_template``) pour respecter l'inward-only : +# ``app/`` ne doit pas importer ``pipeline/llm_pipeline_config`` +# directement. # ────────────────────────────────────────────────────────────────────── -# Mapping Document (legacy) → DocumentRef (rewrite) +# Mapping Document → DocumentRef # ────────────────────────────────────────────────────────────────────── @@ -75,9 +55,9 @@ def document_to_document_ref( *, workspace_dir: Path, ) -> DocumentRef: - """Convertit un ``Document`` legacy en ``DocumentRef`` rewrite. + """Convertit un ``Document`` (couche 3) en ``DocumentRef`` (couche 1). - Le ``Document`` legacy porte sa GT en mémoire (``ground_truth: str`` + Le ``Document`` (modèle riche) porte sa GT en mémoire (``ground_truth: str`` et ``ground_truths: dict[ArtifactType, GTPayload]``). Le ``DocumentRef`` rewrite porte des références filesystem (``GroundTruthRef.uri``). La conversion écrit chaque GT @@ -86,7 +66,7 @@ def document_to_document_ref( Parameters ---------- document: - Document legacy. ``image_path`` non-``None`` est requis ; + Document. ``image_path`` non-``None`` est requis ; ``ground_truth`` (TEXT) peut être vide. workspace_dir: Répertoire de travail où écrire les fichiers GT @@ -171,7 +151,7 @@ def corpus_to_corpus_spec( *, workspace_dir: Path, ) -> CorpusSpec: - """Convertit un ``Corpus`` legacy en ``CorpusSpec`` rewrite. + """Convertit un ``Corpus`` (couche 3) en ``CorpusSpec`` (couche 1). Itère sur ``corpus.documents`` et applique ``document_to_document_ref`` pour chacun. @@ -179,7 +159,7 @@ def corpus_to_corpus_spec( Parameters ---------- corpus: - Corpus legacy. + Corpus. workspace_dir: Répertoire de travail où écrire les fichiers GT synthétisés (typiquement un ``tempfile.TemporaryDirectory`` @@ -219,7 +199,7 @@ def corpus_to_corpus_spec( # ────────────────────────────────────────────────────────────────────── -# Mapping RunResult (rewrite) → BenchmarkResult (legacy) +# Mapping RunResult → BenchmarkResult # ────────────────────────────────────────────────────────────────────── @@ -231,7 +211,7 @@ def run_result_to_benchmark_result( char_exclude: Any | None = None, normalization_profile: Any | None = None, ) -> Any: - """Transpose un ``RunResult`` rewrite en ``BenchmarkResult`` legacy. + """Transpose un ``RunResult`` (couche 4) en ``BenchmarkResult`` (couche 3). Le mapping est en **transposition** : @@ -249,7 +229,7 @@ def run_result_to_benchmark_result( 3. Lit l'``ocr_intermediate`` (RAW_TEXT) si le pipeline a un step OCR amont. 4. Calcule les métriques CER/WER via ``compute_metrics``. - 5. Construit un ``DocumentResult`` legacy avec ``engine_error`` + 5. Construit un ``DocumentResult`` avec ``engine_error`` extrait des ``step_results``. 6. Aggrège les métriques par engine via ``aggregate_metrics``. 7. Reconstitue ``pipeline_info`` pour les engines pipeline @@ -260,11 +240,11 @@ def run_result_to_benchmark_result( run_result: ``RunResult`` produit par ``BenchmarkService.run``. corpus: - Corpus legacy d'origine — sert à récupérer le ``ground_truth`` + Corpus d'origine — sert à récupérer le ``ground_truth`` et l'``image_path`` pour chaque document, dans le même ordre que ``run_result.document_results``. engines: - Liste d'engines legacy dans l'ordre où leurs specs ont été + Liste d'adapters dans l'ordre où leurs specs ont été passées à ``BenchmarkService.run`` (l'ordre détermine l'index dans ``RunDocumentResult.pipeline_results``). char_exclude: @@ -275,7 +255,7 @@ def run_result_to_benchmark_result( Returns ------- BenchmarkResult - Format legacy compatible avec les consommateurs historiques + Format compatible avec les consommateurs historiques (rapport HTML, persistance JSON, narrative engine). """ from picarones.evaluation.benchmark_result import ( @@ -413,14 +393,14 @@ def _build_pipeline_metadata( ground_truth: str = "", hypothesis: str = "", ) -> dict: - """Reconstitue les ``pipeline_metadata`` legacy pour un DocumentResult. + """Reconstitue les ``pipeline_metadata`` pour un DocumentResult. Sprint D.2.d — pour les pipelines composées OCR+LLM, calcule ``over_normalization`` (détection des cas où le LLM a sur-normalisé le texte par rapport à la GT) si ``ocr_intermediate`` est disponible. Equivalent fonctionnel de - ``picarones.measurements.runner.document._compute_doc_result`` - lignes 102-112 (legacy supprimé en D.6.b). + le calcul historique de DocumentResult + (supprimé en D.6.b). """ if not getattr(engine, "is_pipeline", False): return {} @@ -428,7 +408,7 @@ def _build_pipeline_metadata( "pipeline_mode": getattr(engine, "mode", None), "is_pipeline": True, } - # mode peut être un Enum (legacy) ou une string (canonique). + # mode peut être un Enum ou une string (canonique). mode = metadata["pipeline_mode"] if mode is not None and hasattr(mode, "value"): metadata["pipeline_mode"] = mode.value @@ -472,7 +452,7 @@ def _build_pipeline_info(engine: Any) -> dict: info["llm_provider"] = llm_adapter.name mode = getattr(engine, "mode", None) if mode is not None: - # Tolère enum (legacy ``PipelineMode.X``) ou string (canonique). + # Tolère enum (``PipelineMode.X``) ou string. info["mode"] = mode.value if hasattr(mode, "value") else mode prompt_path = getattr(engine, "prompt_path", None) if prompt_path is not None: @@ -498,12 +478,12 @@ def _safe_engine_version(engine: Any) -> str: def _is_canonical_adapter(engine: Any) -> bool: """Détecte si ``engine`` est un ``BaseOCRAdapter`` canonique - (par opposition à ``BaseOCREngine`` legacy ou ``OCRLLMPipeline``). + (par opposition aux modèles riches en behavior). Duck-typing tolérant : un objet est canonical s'il expose ``execute``, ``input_types``, ``output_types`` (les trois attributs requis par le contrat ``StepExecutor``) ET n'a pas - le marker legacy ``is_pipeline``. + le marker ``is_pipeline``. """ from picarones.adapters.ocr.base import BaseOCRAdapter return isinstance(engine, BaseOCRAdapter) @@ -517,7 +497,7 @@ def _is_canonical_adapter(engine: Any) -> bool: def engine_to_pipeline_spec(engine: Any) -> PipelineSpec: """Convertit un engine en ``PipelineSpec`` rewrite. - Deux cas (Sprint H.2.c — le path legacy ``BaseOCREngine`` a + Deux cas (le path historique ``BaseOCREngine`` a été retiré) : - **BaseOCRAdapter** (canonique) : spec mono-step consommant @@ -546,7 +526,7 @@ def engine_to_pipeline_spec(engine: Any) -> PipelineSpec: raise PicaronesError( f"Type d'engine non supporté : {type(engine).__name__}. " "Attendu : ``BaseOCRAdapter`` ou ``OCRLLMPipelineConfig``. " - "Le support legacy ``BaseOCREngine`` / ``OCRLLMPipeline`` " + "Le support historique ``BaseOCREngine`` / ``OCRLLMPipeline`` " "a été retiré au sprint H.2.c.", ) @@ -584,7 +564,7 @@ def _canonical_adapter_to_spec(adapter: Any) -> PipelineSpec: ) -# Sprint H.2.c — ``_ocr_only_to_spec`` (legacy ``BaseOCREngine`` → +# ``_ocr_only_to_spec`` (mappait ``BaseOCREngine`` → # spec mono-step en dur IMAGE → RAW_TEXT) supprimé. Le path # canonique ``_canonical_adapter_to_spec`` couvre tous les cas en # utilisant les ``input_types``/``output_types`` déclarés par @@ -592,10 +572,10 @@ def _canonical_adapter_to_spec(adapter: Any) -> PipelineSpec: def _ocr_llm_pipeline_to_spec(pipeline: Any) -> PipelineSpec: - """Spec composée pour un ``OCRLLMPipeline`` legacy ou un + """Spec composée pour un ``OCRLLMPipelineConfig`` ou un ``OCRLLMPipelineConfig`` canonique (3 modes). - Tolère ``pipeline.mode`` en enum (legacy ``PipelineMode.TEXT_ONLY``) + Tolère ``pipeline.mode`` en enum (``PipelineMode.TEXT_ONLY``) ou en string (canonique ``"text_only"``). """ mode_attr = pipeline.mode @@ -634,7 +614,7 @@ def build_adapter_resolver( """Construit un adapter resolver pour ``PipelineExecutor``. Parcourt les engines fournis et associe leur ``name`` à un - ``StepExecutor`` valide (Sprint H.2.c — le path legacy + ``StepExecutor`` valide (le path historique ``LegacyOCREngineExecutor`` a été retiré) : - **BaseOCRAdapter** : enregistré directement (déjà ``StepExecutor``). @@ -700,7 +680,7 @@ def build_adapter_resolver( def resolver(name: str) -> Any: if name not in name_to_executor: raise KeyError( - f"adapter inconnu pour le resolver legacy : {name!r}. " + f"adapter inconnu pour le resolver : {name!r}. " f"Enregistrés : {sorted(name_to_executor.keys())!r}." ) return name_to_executor[name] @@ -856,17 +836,17 @@ def run_benchmark_via_service( partial_dir: str | Path | None = None, entity_extractor: Callable[[str], list[dict]] | None = None, profile: str = "standard", - # ---- Paramètres legacy non encore portés vers BenchmarkService ---- + # ---- Paramètres non encore portés vers BenchmarkService ---- # Sprint D.2 du plan v2.0 — features marginales restantes : # ``max_workers`` (le rewrite a son propre max_in_flight via # ``CorpusRunner``). max_workers: int = 4, # noqa: ARG001 ) -> Any: - """Adapter de compatibilité ``run_benchmark`` legacy → + """Façade ``run_benchmark`` → ``BenchmarkService`` rewrite. Présente la signature historique de - ``picarones.measurements.runner.run_benchmark`` mais s'appuie + ``picarones.app.services.benchmark_runner.run_benchmark`` mais s'appuie en interne sur le rewrite (``CorpusSpec``, ``PipelineSpec``, ``PipelineExecutor``, ``BenchmarkService``). Pivot du Sprint D du plan v2.0. @@ -880,7 +860,7 @@ def run_benchmark_via_service( - Un ``Corpus`` avec image_path + ground_truth (TEXT) par doc. - Métriques CER/WER calculées via ``compute_metrics`` sur les hypothèses extraites des artefacts produits. - - Conversion en ``BenchmarkResult`` legacy compatible avec les + - Conversion en ``BenchmarkResult`` compatible avec les consommateurs historiques (rapport HTML, narrative engine). Périmètre reporté (D.2) @@ -931,16 +911,16 @@ def run_benchmark_via_service( Parameters ---------- corpus: - Corpus legacy. + Corpus. engines: - Liste d'engines/pipelines legacy à benchmarker. + Liste d'engines/pipelines à benchmarker. char_exclude: Filtre passé à ``compute_metrics``. normalization_profile: Profil de normalisation passé à ``compute_metrics``. output_json: Si fourni, le ``BenchmarkResult`` est sérialisé en JSON - à ce chemin (via la sérialisation legacy). + à ce chemin (sérialisation BenchmarkResult). code_version: Version du code injectée dans le ``RunContext`` / ``RunManifest``. Défaut : ``picarones.__version__``. @@ -950,7 +930,7 @@ def run_benchmark_via_service( Returns ------- BenchmarkResult - Format legacy compatible. + Format compatible avec les consommateurs historiques. Raises ------ @@ -1003,7 +983,7 @@ def run_benchmark_via_service( # D.2.e : NER attach post-process. Idempotent — re-calcule à # chaque run même en mode resume (les ner_metrics ne sont pas - # persistées dans le partial NDJSON, cohérent avec le legacy + # persistées dans le partial NDJSON # qui calculait NER après le doc loop). if entity_extractor is not None: _attach_ner_metrics_to_benchmark( @@ -1084,8 +1064,8 @@ def _aggregate_ner_metrics(doc_results: list) -> dict | None: compteurs totaux d'hallucinations et d'entités manquées. Equivalent fonctionnel de - ``picarones.measurements.runner.ner_attach._aggregate_ner`` - (legacy supprimé en D.6.b). + ``picarones.app.services.benchmark_runner.ner_attach._aggregate_ner`` + (le runner historique a été supprimé en D.6.b). """ relevant = [ dr for dr in doc_results if dr.ner_metrics is not None @@ -1246,7 +1226,7 @@ def _run_benchmark_with_partial( for engine in engines: # Vérifier la cancellation entre engines (matche la - # sémantique legacy : un Ctrl+C arrête après l'engine en + # sémantique : un Ctrl+C arrête après l'engine en # cours, conserve les partials, ne démarre pas le suivant). if cancel_event is not None and getattr( cancel_event, "is_set", lambda: False, @@ -1377,7 +1357,7 @@ def _execute_via_benchmark_service( Vues passées en liste vide — les métriques sont calculées côté converter D.1.c via ``compute_metrics`` directement sur les hypothèses extraites des artefacts. Pattern simple, - cohérent avec le legacy qui calcule aussi les métriques au + cohérent : on calcule aussi les métriques au moment du benchmark (pas via ``EvaluationView``). """ from picarones.app.services.benchmark_service import BenchmarkService @@ -1399,7 +1379,7 @@ def _execute_via_benchmark_service( # ViewExecutor minimal : registres vides. # Pas de calcul de ``ViewResult`` ici — le converter D.1.c - # calcule les métriques côté legacy via ``compute_metrics`` + # calcule les métriques via ``compute_metrics`` # directement sur les hypothèses extraites des artefacts. view_executor = DefaultEvaluationViewExecutor.from_registries( metric_registry=MetricRegistry(), @@ -1439,7 +1419,7 @@ def _execute_via_benchmark_service( # Sprint D.2.a : le hook ``progress_callback`` est appelé ici — # ``context_factory`` est invoqué une fois par (doc, pipeline) # AVANT l'exécution effective, ce qui correspond à la sémantique - # legacy de ``progress_callback(engine_name, doc_idx, doc_id)``. + # de ``progress_callback(engine_name, doc_idx, doc_id)``. import threading counter_lock = threading.Lock() @@ -1452,7 +1432,7 @@ def _execute_via_benchmark_service( with counter_lock: idx = counter_state["doc_idx"] counter_state["doc_idx"] = idx + 1 - # Sémantique legacy : ``progress_callback(engine.name, ...)`` + # Sémantique : ``progress_callback(engine.name, ...)`` # plutôt que le nom de la pipeline (qui inclut le préfixe # ``ocr_only_``). Le mapping est fourni par le caller. engine_name = ( @@ -1463,7 +1443,7 @@ def _execute_via_benchmark_service( try: progress_callback(engine_name, idx, doc.id) except Exception: # noqa: BLE001 - # Le legacy ignore silencieusement les erreurs du + # On ignore silencieusement les erreurs du # callback (un caller qui crashe ne doit pas faire # tomber le benchmark). Même contrat ici. pass @@ -1502,7 +1482,7 @@ def _execute_via_benchmark_service( def _persist_benchmark_result_json( benchmark_result: Any, output_path: Path, ) -> None: - """Sérialise un ``BenchmarkResult`` legacy en JSON. + """Sérialise un ``BenchmarkResult`` en JSON. Utilise la méthode ``to_json``/``compact``/``asdict`` selon la surface disponible. Ce helper duplique la logique de @@ -1512,7 +1492,7 @@ def _persist_benchmark_result_json( output_path.parent.mkdir(parents=True, exist_ok=True) # ``BenchmarkResult`` est un dataclass — dataclasses.asdict # sérialise récursivement. Le format n'est pas forcément - # identique octet pour octet à la sortie legacy, mais reste + # identique octet pour octet à la sortie historique, mais reste # compatible avec les consommateurs (rapport, narrative). import dataclasses import json diff --git a/picarones/app/services/partial_store.py b/picarones/app/services/partial_store.py index 01e0d4e041710585047e4684721905ba5240a21e..61cb7f06d089a6d2047595653b23c26604320ba1 100644 --- a/picarones/app/services/partial_store.py +++ b/picarones/app/services/partial_store.py @@ -1,8 +1,8 @@ -"""Sprint D.2.b — reprise sur interruption pour ``run_benchmark_via_service``. +"""Reprise sur interruption pour ``run_benchmark_via_service``. -Persistance NDJSON des ``DocumentResult`` legacy au fil du -benchmark, pour permettre la reprise après crash / Ctrl+C / timeout -sans perdre le travail déjà fait. +Persistance NDJSON des ``DocumentResult`` au fil du benchmark, pour +permettre la reprise après crash / Ctrl+C / timeout sans perdre le +travail déjà fait. Contrat ------- @@ -18,19 +18,12 @@ partiel est supprimé. Si un crash interrompt le run mid-engine, le fichier persiste : la prochaine exécution reprendra exactement où l'on s'est arrêté. -Trace de retrait ----------------- -Module transitoire (Sprint D.2.b du plan v2.0). Sera supprimé -en H.4 quand ``run_benchmark_via_service`` lui-même disparaîtra -au profit d'une consommation directe de ``BenchmarkService`` par -les callers (``cli``, ``web``). - Anti-sur-ingénierie ------------------- - Format JSONL plat (une ligne = un ``DocumentResult.as_dict()``), pas de schéma versioné. Si la structure du ``DocumentResult`` - legacy change, le fichier devient illisible — mais à ce stade - on est déjà en post-rewrite v2.0+ et le legacy est mort. + change, le fichier devient illisible — l'opérateur supprime + ``partial_dir`` et relance. - Lock thread-safe partagé module-level ; pas de tentative de partage inter-process (chaque process a son propre tempdir). - Pas de checksum ni de validation de schéma — best-effort. Une @@ -63,9 +56,8 @@ _partial_write_lock = threading.Lock() def _sanitize_filename(s: str) -> str: """Réduit ``s`` à ``[\\w\\-]`` et tronque à 64 chars. - Cohérent avec le format historique du fichier partiel - legacy ; permet à un opérateur de retrouver visuellement - le fichier dans ``partial_dir``. + Permet à un opérateur de retrouver visuellement le fichier + dans ``partial_dir``. """ return re.sub(r"[^\w\-]", "_", s)[:64] diff --git a/picarones/app/services/registry_service.py b/picarones/app/services/registry_service.py index 7e1640c8c93c1d36594a4a82e36d90c0cb3342df..bf6d5d6e72d5335e199e37eb3349b2f6457c4e69 100644 --- a/picarones/app/services/registry_service.py +++ b/picarones/app/services/registry_service.py @@ -4,7 +4,7 @@ Sprint A14-S23 du rewrite ciblé. Le service applicatif qui **construit** explicitement le ``MetricRegistry`` et le ``ProjectorRegistry`` au démarrage, en -remplacement de l'anti-pattern legacy ``import picarones.measurements +remplacement de l'anti-pattern legacy ``import picarones.evaluation.metrics as _trigger`` (où l'import par effet de bord déclenchait l'enregistrement via décorateurs au top-level d'un package, chargeant des dizaines de modules optionnels au moment d'un simple diff --git a/picarones/app/services/run_orchestrator.py b/picarones/app/services/run_orchestrator.py index d39475b54261dbc8487bab5c7bbd8484c11a8792..27944d3cf6d83fd4411a92eb96cbd0e4f48ed8db 100644 --- a/picarones/app/services/run_orchestrator.py +++ b/picarones/app/services/run_orchestrator.py @@ -76,8 +76,6 @@ from picarones.pipeline import ( # ────────────────────────────────────────────────────────────────────── - - @dataclass(frozen=True) class OrchestrationResult: """Tout ce qu'un caller (CLI, HTTP, script) doit savoir d'un run. diff --git a/picarones/domain/artifacts.py b/picarones/domain/artifacts.py index e2230405afb6da9c17cf4f1d9992ac82a8e4ae66..70f9ca2a3046a25f783c775a04ea17bd973db9af 100644 --- a/picarones/domain/artifacts.py +++ b/picarones/domain/artifacts.py @@ -1,14 +1,11 @@ -"""``Artifact`` et ``ArtifactType`` — Sprint A14-S4. +"""``Artifact`` et ``ArtifactType``. Toute sortie d'une étape de pipeline est un **artefact traçable** : identifiant stable, type explicite, hash du contenu, provenance. -Différences avec ``picarones.core.modules.ArtifactType`` (Sprint 33) -------------------------------------------------------------------- -L'ancien ``ArtifactType`` historique a 6 valeurs : -``IMAGE, TEXT, ALTO, PAGE, ENTITIES, READING_ORDER``. Le nouveau -en a 9, avec deux distinctions importantes pour les vues d'évaluation -introduites aux Sprints S13-S18 : +L'enum ``ArtifactType`` a 9 valeurs canoniques + 3 aliases courts +pour les types texte/ALTO/PAGE. Distinctions clés pour les vues +d'évaluation : - **``RAW_TEXT`` vs ``CORRECTED_TEXT``** — un OCR brut et un texte corrigé par un LLM ont la même structure (string) mais des contrats @@ -103,47 +100,40 @@ class ArtifactType(str, Enum): #: reliability diagram). CONFIDENCES = "confidences" - #: Aliases legacy pour rétrocompat avec ``picarones.core.modules`` - #: (Phase 4-bis du retrait du legacy). Le mécanisme natif d'Enum - #: Python rend ces noms équivalents aux canoniques : + #: Aliases courts pour les types texte/ALTO/PAGE. Le mécanisme + #: natif d'Enum Python rend ces noms équivalents aux canoniques : #: #: >>> ArtifactType.TEXT is ArtifactType.RAW_TEXT #: True #: - #: Le mapping sémantique TEXT → RAW_TEXT est documenté dans - #: ``docs/migration/regression-tolerances.md``. À supprimer en 2.0 - #: une fois tous les callers legacy retirés. + #: Utilisés par les ``@register_metric(...)`` qui déclarent leurs + #: signatures de manière concise. TEXT = "raw_text" ALTO = "alto_xml" PAGE = "page_xml" @classmethod def _missing_(cls, value: object) -> "ArtifactType | None": - """Accepte les valeurs string legacy (``"text"``, ``"alto"``, + """Accepte les chaînes courtes (``"text"``, ``"alto"``, ``"page"``) en plus des valeurs canoniques. - Ce hook est invoqué par ``ArtifactType("text")`` (lecture YAML - legacy par exemple) — sans lui, ``ValueError``. À supprimer - en 2.0 avec les aliases legacy ci-dessus. + Permet aux specs YAML d'utiliser indifféremment l'un ou + l'autre nom. """ - legacy_map: dict[str, "ArtifactType"] = { + short_map: dict[str, "ArtifactType"] = { "text": cls.RAW_TEXT, "alto": cls.ALTO_XML, "page": cls.PAGE_XML, } if not isinstance(value, str): return None - return legacy_map.get(value) + return short_map.get(value) -#: Map valeur canonique → valeur string legacy. Permet aux dicts -#: indexés par ``ArtifactType.value`` (junction_metrics du runner -#: legacy, etc.) de présenter les **deux** clés pendant la phase de -#: migration : un caller rewrite qui cherche ``["raw_text"]`` et un -#: test legacy qui cherche ``["text"]`` voient le même résultat. -#: -#: Phase 4-bis du retrait du legacy. Sera retiré en 2.0 quand tous -#: les callers utilisent les valeurs canoniques. +#: Map valeur canonique → valeur string courte. Permet aux dicts +#: indexés par ``ArtifactType.value`` de présenter les **deux** clés : +#: un caller qui cherche ``["raw_text"]`` et un caller qui cherche +#: ``["text"]`` voient le même résultat. LEGACY_VALUE_ALIASES: dict[str, str] = { "raw_text": "text", "alto_xml": "alto", diff --git a/picarones/domain/errors.py b/picarones/domain/errors.py index b68679335c462ba34b9a3cfefbe2ca17e968972a..22da3dae5705c5c88be5d190f87ca92a9e6ddc61 100644 --- a/picarones/domain/errors.py +++ b/picarones/domain/errors.py @@ -23,7 +23,7 @@ class PicaronesError(Exception): une sous-classe de ``PicaronesError`` plutôt qu'un ``Exception`` générique ou un ``ValueError`` quand l'erreur a un sens métier. - L'ancien code (``picarones.core``, ``picarones.measurements``, + L'ancien code (``picarones.core``, ``picarones.evaluation.metrics``, etc.) garde son comportement actuel jusqu'à sa migration. """ diff --git a/picarones/domain/module_protocol.py b/picarones/domain/module_protocol.py index e8c5c1135810f87901232f659af979bd56449003..f88ff820ddb4c902639636299cf1215c6bb44e48 100644 --- a/picarones/domain/module_protocol.py +++ b/picarones/domain/module_protocol.py @@ -20,17 +20,13 @@ Usage minimal :: txt = inputs[ArtifactType.RAW_TEXT] return {ArtifactType.RAW_TEXT: txt.upper()} -Ce module canonique (Phase 4-bis du retrait du legacy) est le -remplacement de ``picarones.core.modules.BaseModule``. Le shim -legacy ``core/modules.py`` le ré-exporte pour la rétrocompat des -~25 callers (engines, measurements, modules officiels, cli, web, -report) qui le consomment. - -Le rewrite a aussi des protocols spécialisés -(``BaseOCRAdapter``, ``BaseLLMAdapter``, ``BaseVLMAdapter`` dans -``picarones.adapters``) qui sont des cas particuliers de -``BaseModule`` typés pour leur domaine. ``BaseModule`` reste le -contrat **générique** pour les modules contribués par des tiers. +Protocols spécialisés +--------------------- +Les contrats de domaine — ``BaseOCRAdapter``, ``BaseLLMAdapter``, +``BaseVLMAdapter`` (dans ``picarones.adapters``) — sont des cas +particuliers de ``BaseModule`` typés pour leur usage. +``BaseModule`` reste le contrat **générique** pour les modules +contribués par des tiers. """ from __future__ import annotations diff --git a/picarones/evaluation/benchmark_result.py b/picarones/evaluation/benchmark_result.py index 5ce3974ac5bfdd88c97df7fb9f475948dc171a50..49ac358f72a91c4845e56e3cac14f0666667f69b 100644 --- a/picarones/evaluation/benchmark_result.py +++ b/picarones/evaluation/benchmark_result.py @@ -1,10 +1,5 @@ """Modèle de données des résultats et export JSON (Cercle 2). -Phase 4-ter — module relocalisé depuis ``picarones.core.results`` -vers le Cercle 2 (``evaluation``) où il appartient sémantiquement. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - Hiérarchie ---------- BenchmarkResult diff --git a/picarones/evaluation/corpus.py b/picarones/evaluation/corpus.py index e000ae3d923ae595c9199bedb3040f802b0e8495..eb95eaae783c85d36e433c5cf95882abffc201c8 100644 --- a/picarones/evaluation/corpus.py +++ b/picarones/evaluation/corpus.py @@ -1,18 +1,12 @@ -"""Chargement et gestion des corpus de documents (Cercle 2). - -Phase 4-quater — module relocalisé depuis ``picarones.core.corpus`` -vers le Cercle 2 (``evaluation``) où il appartient sémantiquement. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. +"""Chargement et gestion des corpus de documents (couche 3 — evaluation). Coexistence avec ``domain.corpus.CorpusSpec`` --------------------------------------------- ``evaluation.corpus`` (le présent module) porte les types **riches -en behavior** historiquement utilisés par le runner de -``measurements/`` : ``Document``, ``Corpus``, ``ArtifactType`` + -payloads ``TextGT``/``AltoGT``/``PageGT``/``EntitiesGT``/ -``ReadingOrderGT`` chargés en mémoire, et la fonction -``load_corpus_from_directory``. +en behavior** consommés par ``BenchmarkService`` (couche 6) : +``Document``, ``Corpus``, ``ArtifactType`` + payloads +``TextGT``/``AltoGT``/``PageGT``/``EntitiesGT``/``ReadingOrderGT`` +chargés en mémoire, et la fonction ``load_corpus_from_directory``. ``domain.corpus.CorpusSpec`` + ``domain.documents.DocumentRef`` (Pydantic, immutable, déclaratif) sont une vue **structurelle** diff --git a/picarones/evaluation/metric_hooks.py b/picarones/evaluation/metric_hooks.py index 4968a3134b4912c007a365d0bca551f28d147f98..c0c21ddd8ed0d83b0f785343e68507f901bde99c 100644 --- a/picarones/evaluation/metric_hooks.py +++ b/picarones/evaluation/metric_hooks.py @@ -1,16 +1,11 @@ """Registre typé des hooks de métriques document-level et corpus-level. -Phase 4-ter — module relocalisé depuis ``picarones.core.metric_hooks`` -vers le Cercle 2 (``evaluation``) où il appartient sémantiquement. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - Pourquoi ce module ------------------ Avant le « chantier 2 » du plan d'évolution post-Sprint 97, -``picarones.measurements.runner._compute_document_result`` +``picarones.app.services.benchmark_runner._compute_document_result`` contenait **11 imports tardifs codés en dur** vers -``picarones.measurements.confusion``, ``char_scores``, ``taxonomy``, ``structure``, +``picarones.evaluation.metrics.confusion``, ``char_scores``, ``taxonomy``, ``structure``, ``image_quality``, ``line_metrics``, ``hallucination``, ``philological_hooks``, ``searchability_hooks``, ``numerical_sequences_hooks``, ``readability_hooks`` — chacun enrobé diff --git a/picarones/evaluation/metric_registry.py b/picarones/evaluation/metric_registry.py index 67a45b20c6286438031e9caeeb697bfd9503aed7..6a830603cfd0b41450a7fec33950bfc626d2bec9 100644 --- a/picarones/evaluation/metric_registry.py +++ b/picarones/evaluation/metric_registry.py @@ -1,4 +1,4 @@ -"""Registre typé de métriques (Phase 4-ter — relocalisation Cercle 2). +"""Registre typé de métriques (couche 3 — evaluation). Pattern et données ------------------ @@ -7,30 +7,19 @@ le décorateur ``@register_metric``. Chaque métrique enregistre une ``MetricSpec`` (nom + signature de types + callable) ; la sélection typée à une jonction se fait via ``select_metrics(input_types)``. -Le runner d'une pipeline composée -(:func:`picarones.evaluation.pipeline.PipelineRunner.run`) consomme ce -registre pour évaluer automatiquement chaque jonction GT vs sortie. - Différence avec ``picarones.evaluation.registry.MetricRegistry`` ---------------------------------------------------------------- -Le présent module est le pattern **historique** : un registre -unique global, alimenté par les imports des sous-packages (le -``picarones.measurements.__init__`` est l'amorce qui s'occupe de -charger tous les modules définissant des ``@register_metric``). +Le présent module est le pattern **module-level** : un registre +unique global, alimenté par les imports des sous-packages +(``picarones.evaluation.metrics.__init__`` charge tous les modules +définissant des ``@register_metric``). ``picarones.evaluation.registry.MetricRegistry`` est une **classe -instanciable** (Sprint A14-S5) — un service applicatif l'instancie -explicitement et y enregistre les métriques sans side-effect -d'import. Les deux patterns coexistent volontairement : le legacy -fonctionne pour les ~30 métriques existantes, l'instance-based est -réservé aux contributions tierces et au cadre des -``EvaluationView`` (S20+). - -Phase 4-ter (présente) ----------------------- -Module relocalisé depuis ``picarones.core.metric_registry``. Le -chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. +instanciable** — un service applicatif l'instancie explicitement +et y enregistre les métriques sans side-effect d'import. Les +deux patterns coexistent : le module-level fonctionne pour les +~37 métriques existantes, l'instance-based est réservé aux +contributions tierces et au cadre des ``EvaluationView``. Exemple d'usage --------------- diff --git a/picarones/evaluation/metric_result.py b/picarones/evaluation/metric_result.py index d67b5bdb54fbde47f081ed6c7883d9d64b225a96..9b94d3352a5f83916303e6597b3ad4173f1cd473 100644 --- a/picarones/evaluation/metric_result.py +++ b/picarones/evaluation/metric_result.py @@ -1,16 +1,11 @@ -"""Modèle de données des métriques OCR/HTR (Cercle 2). - -Phase 4-ter — module relocalisé depuis ``picarones.core.metrics`` -vers le Cercle 2 (``evaluation``) où il appartient sémantiquement. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. +"""Modèle de données des métriques OCR/HTR (couche 3 — evaluation). Abstractions pures pour représenter les métriques calculées sur une paire (référence, hypothèse) — pas de dépendance externe (pas de jiwer, pas de scipy). Le calcul effectif via jiwer vit dans -:mod:`picarones.measurements.metrics` (``compute_metrics``). +:mod:`picarones.evaluation.metrics.text_metrics` (``compute_metrics``). L'agrégation statistique vit ici car elle n'utilise que la stdlib (``statistics``). """ diff --git a/picarones/evaluation/metrics/__init__.py b/picarones/evaluation/metrics/__init__.py index 285eec4e997e3dacd5e4ad32167f4ab16008762c..5fc2de9b4ba810472482a7a999a81de703bda9a3 100644 --- a/picarones/evaluation/metrics/__init__.py +++ b/picarones/evaluation/metrics/__init__.py @@ -1,56 +1,38 @@ """Métriques — calculs purs sur des paires (référence, hypothèse). -Sprint A14-S10 : déplacement de **23 fichiers de calcul autonomes** -depuis ``picarones.measurements``. +~37 modules de calcul autonomes : Calculs de qualité textuelle pure : ``rare_tokens``, ``lexical_modernization``, ``calibration``, - ``confusion``, ``line_metrics``. + ``confusion``, ``line_metrics``, ``text_metrics``. Calculs structurels et géométriques : - ``layout``, ``image_quality``, ``image_predictive``. + ``layout``, ``image_quality``, ``image_predictive``, + ``alto_metrics``, ``alto_structural``. Calculs économiques : ``pricing``, ``marginal_cost``, ``throughput``, - ``incremental_comparison``. + ``incremental_comparison``, ``cost_projection``. Calculs analytiques (post-traitement) : - ``error_absorption``, ``hallucination``, ``robustness_projection``, - ``longitudinal``, ``baseline_comparison``, ``levers``, - ``worst_lines``, ``module_policy``. + ``error_absorption``, ``hallucination``, ``robustness``, + ``robustness_projection``, ``longitudinal``, + ``baseline_comparison``, ``levers``, ``worst_lines``, + ``module_policy``, ``history``, ``modern_archives``. Calculs inter-moteurs : - ``inter_engine``, ``taxonomy_cooccurrence``, + ``inter_engine``, ``specialization``, ``taxonomy``, + ``taxonomy_intra_doc``, ``taxonomy_cooccurrence``, ``taxonomy_comparison``. -Reste à migrer (différé) ------------------------- +Calculs philologiques : + ``mufi``, ``abbreviations``, ``unicode_blocks``, + ``roman_numerals``, ``numerical_sequences``, + ``early_modern_typography``, ``reading_order``. -Catégorie B — utilisent ``@register_metric`` du registre global -``core.metric_registry`` (singleton avec side-effect d'import) : - ``mufi``, ``abbreviations``, ``unicode_blocks``, ``roman_numerals``, - ``early_modern_typography``, ``modern_archives``, ``reading_order``, - ``ner``, ``readability``, ``searchability``, ``numerical_sequences``. - -Migrés au S20 quand le ``MetricRegistry`` instancié explicitement -(S5) deviendra le seul registre, via le ``registry_service`` -applicatif. - -Catégorie C — dépendances vers anciens packages : - ``robustness`` (importe ``picarones.evaluation.corpus`` + - ``picarones.adapters.legacy_engines.base`` + ``picarones.measurements.metrics``). - Ne peut être migré qu'après les Sprints S11 (déplacement des - adapters) et S12 (équivalence numérique). - -Catégorie D — dépendances inter-fichiers à orchestrer : - ``cost_projection`` (→ pricing), ``equivalence_profile`` - (→ formats.text.normalization), ``specialization`` - (→ inter_engine), ``taxonomy_intra_doc`` (→ taxonomy), - ``taxonomy`` (→ char_scores). - -Règle de migration (S10) : un fichier déplacé = un commit avec -uniquement le déplacement et un re-export à l'ancien emplacement. -La logique reste identique. Aucun test modifié. +Calculs sémantiques : + ``ner``, ``readability``, ``searchability``, + ``equivalence_profile``, ``over_normalization``. """ from __future__ import annotations diff --git a/picarones/evaluation/metrics/alto_metrics.py b/picarones/evaluation/metrics/alto_metrics.py index e937decc66b977be0071429ab5691f30e302d780..2098680deb29ba50c6a19e23bd3a2f40282759bd 100644 --- a/picarones/evaluation/metrics/alto_metrics.py +++ b/picarones/evaluation/metrics/alto_metrics.py @@ -17,7 +17,7 @@ enregistre quatre métriques natives (``alto_text_cer``, les opérateurs jiwer historiques sur le texte extrait des deux côtés. L'approche est strictement additive vis-à-vis de -:mod:`picarones.measurements.metrics` : ce module ne touche pas le chemin de +:mod:`picarones.evaluation.metrics.text_metrics` : ce module ne touche pas le chemin de calcul historique (``compute_metrics``), il enrichit uniquement le registre typé pour les pipelines composées. diff --git a/picarones/evaluation/metrics/builtin_hooks.py b/picarones/evaluation/metrics/builtin_hooks.py index 91b534108a59e16c0e36a54c4b0a63e17edc830b..8cebeae80e5e7fd9195f03cba297961ff41f43f3 100644 --- a/picarones/evaluation/metrics/builtin_hooks.py +++ b/picarones/evaluation/metrics/builtin_hooks.py @@ -4,7 +4,7 @@ Chantier 2 du plan d'évolution post-Sprint 97. Ce module **migre** les 12 hooks document-level et 12 agrégateurs corpus-level qui étaient codés en dur dans -``picarones.measurements.runner._compute_document_result`` et autour de la +``picarones.app.services.benchmark_runner._compute_document_result`` et autour de la boucle d'agrégation (lignes 794-827 du runner pré-chantier-2). Approche additive — rétrocompat stricte diff --git a/picarones/evaluation/metrics/cost_projection.py b/picarones/evaluation/metrics/cost_projection.py index c522eaadc4634a4281841d91c89cbd04b93e290c..920202df98bf5895353f232fad2fd1b0dd5987ac 100644 --- a/picarones/evaluation/metrics/cost_projection.py +++ b/picarones/evaluation/metrics/cost_projection.py @@ -20,7 +20,7 @@ le chercheur arbitre selon son budget. Dépendance ---------- -S'appuie sur ``picarones.measurements.pricing`` (Sprint 20) qui expose +S'appuie sur ``picarones.evaluation.metrics.pricing`` (Sprint 20) qui expose ``EngineCost.cost_per_1k_pages_eur`` et ``co2_per_1k_pages_g``. """ diff --git a/picarones/evaluation/metrics/incremental_comparison.py b/picarones/evaluation/metrics/incremental_comparison.py index 8dcd0f6d95b85d94472aa99fffab926755e89be3..e73f54ccf709acc7b47875ad31669e9862e0a375 100644 --- a/picarones/evaluation/metrics/incremental_comparison.py +++ b/picarones/evaluation/metrics/incremental_comparison.py @@ -28,7 +28,7 @@ On ne reconstruit pas Friedman/Nemenyi (déjà dans Sprint 18) ; on agrège ici les données nécessaires pour qu'un tests statistique externe puisse les consommer. Le rapport existant reste libre de brancher -``picarones.measurements.statistics.friedman_test`` sur la sortie de +``picarones.evaluation.statistics.friedman_test`` sur la sortie de ce module. Sortie diff --git a/picarones/evaluation/metrics/normalization.py b/picarones/evaluation/metrics/normalization.py index 8d5db3fc8716927d9e2fd542fbe4868a54d813fb..eec0aab2ad1eb2bd78795d231fb67b043fc965bf 100644 --- a/picarones/evaluation/metrics/normalization.py +++ b/picarones/evaluation/metrics/normalization.py @@ -6,7 +6,7 @@ rewrite ciblé (cf. ``docs/roadmap/rewrite-2026.md``). Ce fichier est conservé comme re-export pour ne **rien casser** chez les ~50 consommateurs qui font ``from -picarones.measurements.normalization import X``. Les symboles +picarones.formats.text.normalization import X``. Les symboles publics ET privés utilisés downstream (``_parse_exclude_chars``, ``_apply_diplomatic_table``) sont ré-exposés explicitement. diff --git a/picarones/evaluation/metrics/numerical_sequences.py b/picarones/evaluation/metrics/numerical_sequences.py index e3bd84e38d0a840e98361b1013ff046a2ec2a695..9d8f0994546d76bc8ae1449093095c653a387247 100644 --- a/picarones/evaluation/metrics/numerical_sequences.py +++ b/picarones/evaluation/metrics/numerical_sequences.py @@ -1,11 +1,5 @@ """Précision sur séquences numériques — Sprint 85 (A.II.5b). -Phase 5.C.batch7 — module relocalisé depuis -``picarones.measurements.numerical_sequences`` vers -``picarones.evaluation.metrics.numerical_sequences``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Sprint 85 — A.II.5b du plan d'évolution 2026. Pourquoi ce module @@ -23,7 +17,7 @@ Catégories couvertes (le module détecte les **années** sur 4 chiffres dans la plage [1000-2099]). 2. **Numéraux romains** : ``MDCLXVIII``, ``XIV``, ``Tome IV``. - Réutilise ``picarones.measurements.roman_numerals`` (Sprint 60). + Réutilise ``picarones.evaluation.metrics.roman_numerals`` (Sprint 60). 3. **Foliotation** : ``f. 12``, ``f. 12r``, ``fol. 24v``, ``p. 5``, ``pp. 12-15``, ``n° 42``. 4. **Montants** : ``12 livres``, ``5 sols``, ``8 deniers``, diff --git a/picarones/evaluation/metrics/robustness.py b/picarones/evaluation/metrics/robustness.py index 3a785e7dfd5e4ecfc40609b17fd089cc67e8c728..dde142a6bc155b2cfedc021d7c2097004c11915a 100644 --- a/picarones/evaluation/metrics/robustness.py +++ b/picarones/evaluation/metrics/robustness.py @@ -33,13 +33,12 @@ from typing import TYPE_CHECKING, Any, Optional if TYPE_CHECKING: from picarones.evaluation.corpus import Corpus, Document - # ``BaseOCREngine`` (legacy ``adapters/legacy_engines/``) ne peut - # pas être importé statiquement depuis la couche ``evaluation/`` - # (test_layer_imports_are_legal). L'annotation utilise donc - # ``Any`` ; le check ``isinstance`` est fait dynamiquement par - # ``importlib`` si besoin (cas réel : duck typing suffit, l'objet - # passé doit juste avoir ``.run(image_path) -> EngineResult``). - BaseOCREngine = Any # type: ignore[misc,assignment] + # Le moteur OCR passé à ``RobustnessAnalyzer`` n'est pas + # importé statiquement depuis la couche ``evaluation/`` (la + # règle inward-only interdit les imports vers ``adapters/``). + # L'annotation utilise donc ``Any`` ; le duck typing suffit : + # l'objet doit exposer ``.run(image_path) -> EngineResult``. + OCREngine = Any # type: ignore[misc,assignment] logger = logging.getLogger(__name__) @@ -413,7 +412,8 @@ class RobustnessAnalyzer: Parameters ---------- engines: - Un ou plusieurs moteurs OCR (``BaseOCREngine``). + Un ou plusieurs adapters OCR (``BaseOCRAdapter`` — duck typing + suffit : l'objet doit exposer ``.run(image_path)``). degradation_types: Liste des types de dégradation à tester. Par défaut : tous (``"noise"``, ``"blur"``, ``"rotation"``, @@ -425,16 +425,16 @@ class RobustnessAnalyzer: Examples -------- - >>> from picarones.adapters.legacy_engines.tesseract import TesseractEngine + >>> from picarones.adapters.ocr.tesseract import TesseractAdapter >>> from picarones.evaluation.metrics.robustness import RobustnessAnalyzer - >>> engine = TesseractEngine(config={"lang": "fra"}) + >>> engine = TesseractAdapter(config={"lang": "fra"}) >>> analyzer = RobustnessAnalyzer([engine], degradation_types=["noise", "blur"]) >>> report = analyzer.analyze(corpus) """ def __init__( self, - engines: "list[BaseOCREngine]", + engines: "list[OCREngine]", degradation_types: Optional[list[str]] = None, cer_threshold: float = 0.20, custom_levels: Optional[dict[str, list]] = None, diff --git a/picarones/evaluation/metrics/roman_numerals.py b/picarones/evaluation/metrics/roman_numerals.py index 9641d31ab54ac87726a8b787fc2da3408750bcb4..49fce4c1c08cff4b24cdaf2ae61f0359c4b78b44 100644 --- a/picarones/evaluation/metrics/roman_numerals.py +++ b/picarones/evaluation/metrics/roman_numerals.py @@ -1,11 +1,5 @@ """Numéraux romains — Sprint 60. -Phase 5.C.batch7 — module relocalisé depuis -``picarones.measurements.roman_numerals`` vers -``picarones.evaluation.metrics.roman_numerals``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Sprint 60 — Étape 3 / extension philologique transversale du plan d'évolution 2026. diff --git a/picarones/evaluation/metrics/search.py b/picarones/evaluation/metrics/search.py index 872705782cd66f70efa478c9de1bcd57ddb72d25..79233e5dc97f6d11fcd72ab815cb08e4ef9c7fec 100644 --- a/picarones/evaluation/metrics/search.py +++ b/picarones/evaluation/metrics/search.py @@ -1,15 +1,7 @@ -"""Recherchabilité fuzzy + séquences numériques — Sprint A14-S16. +"""Recherchabilité fuzzy + séquences numériques. -Fonctions de calcul **pures** (sans ``@register_metric`` legacy) -utilisées par ``SearchView``. Réimplémente la logique des modules -historiques ``picarones.measurements.searchability`` (Sprint 84) -et ``picarones.measurements.numerical_sequences`` (Sprint 85), -sans la dépendance vers le singleton global ``core.metric_registry``. - -Les modules legacy seront supprimés au S20 quand le -``MetricRegistry`` instancié explicitement (S5) deviendra le seul -registre. En attendant, ce module fournit la version "couche -evaluation" propre. +Fonctions de calcul **pures** (sans décorateur ``@register_metric``) +utilisées par ``SearchView``. Métriques livrées ----------------- @@ -20,11 +12,8 @@ Métriques livrées - ``numerical_sequence_preservation(reference, hypothesis)`` — fraction des séquences numériques de la GT préservées - strictement dans l'hypothèse. Volontairement minimaliste pour - S16 : détecte uniquement les **années 4 chiffres** (proxy - réaliste pour les corpus patrimoniaux datés). Le cas complet - (numéraux romains, foliations, monnaies, années régnales) reste - dans le legacy et sera réintégré au S20 avec le registre. + strictement dans l'hypothèse. Détecte uniquement les **années + 4 chiffres** (proxy réaliste pour les corpus patrimoniaux datés). Toutes les métriques ∈ [0, 1] avec ``higher_is_better=True``. """ @@ -42,8 +31,7 @@ import re def levenshtein_distance(a: str, b: str) -> int: """Distance de Levenshtein (substitution = insertion = suppression = 1). - Implémentation identique à ``picarones.measurements.searchability`` - (Sprint 84) mais sans le décorateur ``@register_metric``. + Implémentation pure (sans décorateur ``@register_metric``). """ if a == b: return 0 @@ -93,7 +81,7 @@ def searchability_recall( ------- float ``n_retrouves / n_gt`` ∈ [0, 1]. ``0.0`` si la GT est - vide (convention identique au legacy Sprint 84). + vide. """ if max_distance < 0: raise ValueError(f"max_distance doit être ≥ 0, reçu {max_distance}") @@ -164,11 +152,10 @@ def numerical_sequence_preservation( Note méthodologique ------------------- - Volontairement minimaliste pour S16 : seules les années 4 - chiffres sont détectées. Le pattern complet (numéraux romains, - foliations ``f. 12r``, monnaies, années régnales ``an III``) - reste dans ``picarones.measurements.numerical_sequences`` - (Sprint 85) et sera réintégré dans la couche evaluation au S20. + Volontairement minimaliste : seules les années 4 chiffres sont + détectées. Le pattern complet (numéraux romains, foliations + ``f. 12r``, monnaies, années régnales ``an III``) n'est pas + couvert ici. Multi-set : si la GT contient ``"1789"`` deux fois et l'hypothèse une fois, seul un est compté préservé. diff --git a/picarones/evaluation/metrics/specialization.py b/picarones/evaluation/metrics/specialization.py index e4de2a4617ffa80521899a2512fc8fb1a3343e4e..9d9020846df5d7fe8d0cad9f30936967219e7c50 100644 --- a/picarones/evaluation/metrics/specialization.py +++ b/picarones/evaluation/metrics/specialization.py @@ -32,7 +32,7 @@ intuitive : Dépendances ----------- -S'appuie strictement sur ``picarones.measurements.inter_engine`` (Sprint +S'appuie strictement sur ``picarones.evaluation.metrics.inter_engine`` (Sprint 35) — pas de double calcul, pas de logique nouvelle de divergence. """ diff --git a/picarones/evaluation/registry/registry.py b/picarones/evaluation/registry/registry.py index a954ff10397cdc63a2a34cafdd7478b47ba33bf7..f3483c10af3524b07fcfbe02f48e9f71edcf61b2 100644 --- a/picarones/evaluation/registry/registry.py +++ b/picarones/evaluation/registry/registry.py @@ -8,13 +8,10 @@ pas de décorateur magique. Différence avec ``picarones.evaluation.metric_registry`` -------------------------------------------------------- -L'autre registre (relocalisé depuis ``picarones.core.metric_registry`` -en Phase 4-ter) utilise un dict module-level -``_METRIC_REGISTRY`` rempli par un décorateur ``@register_metric`` -appliqué au top-level d'autres modules. Conséquence : un -``import picarones`` charge ~50 sous-modules pour amorcer le -registre — anti-pattern documenté dans -``BACKLOG_POST_LIVRAISON.md`` §2.4. +L'autre registre utilise un dict module-level ``_METRIC_REGISTRY`` +rempli par un décorateur ``@register_metric`` appliqué au top-level +d'autres modules. Conséquence : un ``import picarones`` charge +~50 sous-modules pour amorcer le registre. Ici, ``MetricRegistry`` est une classe instanciable : diff --git a/picarones/evaluation/statistics/__init__.py b/picarones/evaluation/statistics/__init__.py index 0dea67decb3f5af22db393253435652556c57e43..665b2a516be2526f06ad95fd6787f524413f1812 100644 --- a/picarones/evaluation/statistics/__init__.py +++ b/picarones/evaluation/statistics/__init__.py @@ -19,9 +19,6 @@ Familles Migration Phase 2 ----------------- - -Migré depuis :mod:`picarones.measurements.statistics` qui devient -un shim re-export avec ``DeprecationWarning``. Comportement identique bit-for-bit (même seed pour le bootstrap, mêmes algorithmes scipy, même rendu SVG). Suppression du shim legacy en version 2.0. diff --git a/picarones/evaluation/statistics/friedman_nemenyi.py b/picarones/evaluation/statistics/friedman_nemenyi.py index d2999e6710f061c5c4d6911eb68f8ee49506fb06..0d3a4cc9e4acbe0f7efe6381ec474998e03597f7 100644 --- a/picarones/evaluation/statistics/friedman_nemenyi.py +++ b/picarones/evaluation/statistics/friedman_nemenyi.py @@ -6,7 +6,7 @@ Standard de facto pour comparer plusieurs systèmes sur plusieurs datasets — ici plusieurs moteurs OCR sur plusieurs documents. Le rendu visuel canonique (Critical Difference Diagram) vit dans -:mod:`picarones.measurements.statistics.cdd_render` pour séparer +:mod:`picarones.evaluation.statistics.cdd_render` pour séparer calcul (ce module) et présentation (l'autre). """ diff --git a/picarones/evaluation/statistics/wilcoxon.py b/picarones/evaluation/statistics/wilcoxon.py index aaab4f8ab9a5b15f8a7cbe9a14f0ce721d2993b7..83494a38e17c107d1049afa17b7a6cc0f9563a6f 100644 --- a/picarones/evaluation/statistics/wilcoxon.py +++ b/picarones/evaluation/statistics/wilcoxon.py @@ -215,7 +215,7 @@ def compute_pairwise_stats( __all__ = [ # Symboles publics : signature stable, consommés directement par les - # tests via le ré-export de ``picarones.measurements.statistics``. + # tests via le ré-export de ``picarones.evaluation.statistics``. "compute_pairwise_stats", "wilcoxon_test", # Symboles privés ré-exportés (consommés par certains tests) : diff --git a/picarones/evaluation/synthetic.py b/picarones/evaluation/synthetic.py index 6c9a05b0d55dc4c684b123cf0e52ef67b4d5f200..074f6996e979745fc5a2964e20565d9b9fb99245 100644 --- a/picarones/evaluation/synthetic.py +++ b/picarones/evaluation/synthetic.py @@ -496,7 +496,7 @@ def generate_sample_benchmark( document_count=n_docs, engine_reports=engine_reports, metadata={ - "description": "Données de démonstration générées par picarones.fixtures", + "description": "Données de démonstration synthétiques", "script": "gothique textura", "langue": "Français médiéval (XIVe-XVe siècle)", "institution": "Département des manuscrits", diff --git a/picarones/formats/__init__.py b/picarones/formats/__init__.py index 3911ad16835792b74be78d290fcf22f5a0240067..24c1f400196ebfc331315e34bb5dbbfa7eff50b2 100644 --- a/picarones/formats/__init__.py +++ b/picarones/formats/__init__.py @@ -13,7 +13,7 @@ Sous-packages : - ``pagexml/`` — PAGE XML (PRIMA, transkribus). - ``text/`` — normalisation texte (NFC, casefold, profils diplomatiques, exclusion de caractères). Cible du déplacement - de ``picarones.measurements.normalization`` au Sprint S9. + de ``picarones.formats.text.normalization`` au Sprint S9. Règle d'import : ces modules peuvent importer ``lxml`` et ``defusedxml``. Ils ne doivent **jamais** importer un moteur OCR diff --git a/picarones/i18n.py b/picarones/i18n.py deleted file mode 100644 index 4e152dc6d9d29ea2d74279e3d54a9aed9457f2d4..0000000000000000000000000000000000000000 --- a/picarones/i18n.py +++ /dev/null @@ -1,24 +0,0 @@ -"""``picarones.i18n`` — shim re-export (déprécié, suppression 2.0). - -Canonique : :mod:`picarones.reports.i18n`. Phase 5.E du retrait -du legacy. -""" - -from __future__ import annotations - -import warnings - -from picarones.reports.i18n import * # noqa: F401, F403 -from picarones.reports.i18n import ( # noqa: F401 - TRANSLATIONS, - SUPPORTED_LANGS, - get_labels, - reload_translations, -) - -warnings.warn( - "picarones.i18n is deprecated and will be removed in 2.0. " - "Import from picarones.reports.i18n instead.", - DeprecationWarning, - stacklevel=2, -) diff --git a/picarones/interfaces/cli/__init__.py b/picarones/interfaces/cli/__init__.py index e44c4b35dc05739f4df5d4331e3ef3f3361d722b..a12cbd6548418ff4760ed6627b7431d233d2a8b0 100644 --- a/picarones/interfaces/cli/__init__.py +++ b/picarones/interfaces/cli/__init__.py @@ -326,9 +326,10 @@ def demo_cmd( picarones demo --with-robustness picarones demo --with-history --with-robustness --docs 8 """ - # Sprint G du plan v2.0 — ``picarones.fixtures`` reste legacy - # top-level ; import dynamique pour respecter - # ``test_layer_imports_are_legal[layer-interfaces]``. + # Import dynamique pour respecter ``test_layer_imports_are_legal`` + # (les imports top-level depuis ``interfaces/`` sont scannés à + # l'import-time, et l'analyseur s'exécute sans avoir loadé tous + # les modules). import importlib generate_sample_benchmark = importlib.import_module( "picarones.evaluation.synthetic", diff --git a/picarones/interfaces/web/jobs.py b/picarones/interfaces/web/jobs.py index c4543472aca8a59835f37475c2ec9a6fc6d0e852..0ab540262a943cdb80d3d4c39396cbc0ff90c064 100644 --- a/picarones/interfaces/web/jobs.py +++ b/picarones/interfaces/web/jobs.py @@ -12,7 +12,7 @@ Avant le Sprint 26, l'état des benchmarks vivait uniquement en mémoire dans au-delà de ce que ``BenchmarkJob.events`` portait en RAM. Le Sprint 26 adresse les trois en persistant les jobs et leurs événements -dans une base SQLite locale (cohérent avec ``picarones.measurements.history``, +dans une base SQLite locale (cohérent avec ``picarones.evaluation.metrics.history``, qui utilise déjà SQLite). La base joue trois rôles : - **Source de vérité** pour le statut/progression d'un job — ``BenchmarkJob`` diff --git a/picarones/pipeline/__init__.py b/picarones/pipeline/__init__.py index 4378d483f40a1ebd8aadea430a0094516be27f3d..20ce44b86eef76e9eff3da397bb585e3d2e587c0 100644 --- a/picarones/pipeline/__init__.py +++ b/picarones/pipeline/__init__.py @@ -45,7 +45,7 @@ Modules livrés au S8 Cible du Sprint S12 ------------------- Équivalence numérique CER/WER avec l'ancien -``measurements.runner`` à 1e-9 près sur les fixtures. +``BenchmarkService`` à 1e-9 près sur les fixtures. """ from __future__ import annotations diff --git a/picarones/pipeline/llm_pipeline_builder.py b/picarones/pipeline/llm_pipeline_builder.py index 5314fb9a983fd7142ac726a154ca89401da0062b..c68b47d85faff9119082d1bd5e945349b7b0de6f 100644 --- a/picarones/pipeline/llm_pipeline_builder.py +++ b/picarones/pipeline/llm_pipeline_builder.py @@ -1,14 +1,13 @@ -"""Builder de ``PipelineSpec`` pour les chaînes OCR + LLM (Phase 6 volet 2). +"""Builder de ``PipelineSpec`` pour les chaînes OCR + LLM. -Ce module fournit la convergence entre les 3 modes historiques de -``picarones.pipelines.base.OCRLLMPipeline`` (legacy) et la -``PipelineSpec`` canonique exécutable par ``PipelineExecutor``. +Construit une ``PipelineSpec`` exécutable par ``PipelineExecutor`` +à partir d'un mode + des noms d'adapters. -Mapping mode legacy → spec canonique ------------------------------------- +Modes +----- ================ ============= =========== ================================ -Mode legacy Initial input Steps Output final +Mode Initial input Steps Output final ================ ============= =========== ================================ ``text_only`` IMAGE OCR + LLM ``CORRECTED_TEXT`` ``text_and_image`` IMAGE OCR + LLM ``CORRECTED_TEXT`` (LLM voit aussi IMAGE) @@ -26,22 +25,7 @@ L'adapter OCR amont (Tesseract, Pero, Mistral OCR, Google Vision, Azure DI, ou ``precomputed`` quand le corpus porte déjà l'OCR) est quelconque tant qu'il déclare ``output_types ⊇ {RAW_TEXT}``. -Exemple de migration --------------------- -Code legacy :: - - from picarones.adapters.legacy_pipelines import OCRLLMPipeline, PipelineMode - from picarones.adapters.legacy_engines.tesseract import TesseractEngine - from picarones.adapters.llm import OpenAIAdapter - - pipeline = OCRLLMPipeline( - ocr_engine=TesseractEngine({"lang": "fra"}), - llm_adapter=OpenAIAdapter(model="gpt-4o"), - mode=PipelineMode.TEXT_ONLY, - ) - result = pipeline.run("scan.jpg") # → EngineResult - -Code canonique équivalent :: +Usage :: from picarones.pipeline import PipelineExecutor from picarones.pipeline.llm_pipeline_builder import ( @@ -119,10 +103,10 @@ def make_ocr_llm_pipeline_spec( Format scalaire (``str``, ``int``, ``float``, ``bool``). llm_params: Paramètres dynamiques passés au step LLM/VLM au runtime. - Cas typique (Sprint B du plan v2.0) : + Cas typique : ``{"prompt_template": "Corrige : {ocr_output}"}`` permet à - un caller de spécifier un template legacy ou rewrite sans - toucher à la config de l'adapter. + un caller de spécifier un template ad-hoc sans toucher à la + config de l'adapter. Returns ------- diff --git a/picarones/pipeline/llm_pipeline_config.py b/picarones/pipeline/llm_pipeline_config.py index 3ef2b529eaa362236b1396ceaa6aa93630af2eb8..633d1cd45064b36157b19d3e743c5259061cbaec 100644 --- a/picarones/pipeline/llm_pipeline_config.py +++ b/picarones/pipeline/llm_pipeline_config.py @@ -1,44 +1,20 @@ -"""``OCRLLMPipelineConfig`` — container canonique pour pipelines OCR+LLM. - -Sprint H.2.b/c du plan v2.0 — équivalent canonique de -``picarones.adapters.legacy_pipelines.base.OCRLLMPipeline``. - -Pourquoi --------- -``OCRLLMPipeline`` (legacy) : - -- hérite de ``BaseOCREngine`` (legacy), -- expose une méthode ``run(image_path) → EngineResult``, -- mélange contrat d'exécution et configuration. - -Cette config canonique : - -- est un container *pur* (immutable, pas de logique d'exécution), -- accepte un ``BaseOCRAdapter`` (canonique) au lieu d'un - ``BaseOCREngine`` (legacy) pour le step OCR amont, -- ne dépend pas du legacy. - -L'exécution effective passe par ``PipelineExecutor`` qui consomme -une ``PipelineSpec`` construite via ``make_ocr_llm_pipeline_spec``. - -Duck-typing compat ------------------- -Pour faciliter la migration progressive, -``OCRLLMPipelineConfig`` expose les mêmes attributs/propriétés -que ``OCRLLMPipeline`` legacy : - -- ``is_pipeline = True``, -- ``ocr_engine`` (alias de ``ocr_adapter`` côté canonique), -- ``llm_adapter``, -- ``mode`` (string, pas enum — tolérance ajoutée dans - ``_ocr_llm_pipeline_to_spec``), -- ``prompt_template``, -- ``name``. - -Les helpers -``picarones.app.services.benchmark_runner.engine_to_pipeline_spec`` -et ``build_adapter_resolver`` traitent donc indifféremment les -deux types. +"""``OCRLLMPipelineConfig`` — container pour pipelines OCR+LLM. + +Container *pur* (immutable, pas de logique d'exécution) qui décrit +un pipeline composé OCR amont + LLM aval. L'exécution effective +passe par ``PipelineExecutor`` qui consomme une ``PipelineSpec`` +construite via ``make_ocr_llm_pipeline_spec``. + +Attributs exposés +----------------- +- ``is_pipeline = True`` — marker consommé par ``benchmark_runner`` + pour distinguer un pipeline composé d'un OCR seul. +- ``ocr_engine`` (alias de ``ocr_adapter``) — adapter OCR amont. +- ``llm_adapter`` — adapter LLM aval. +- ``mode`` — string parmi ``text_only`` / ``text_and_image`` / + ``zero_shot``. +- ``prompt_template`` — template de prompt pour le LLM. +- ``name`` — nom du pipeline pour l'identification dans le rapport. """ from __future__ import annotations @@ -128,12 +104,12 @@ class OCRLLMPipelineConfig: @property def ocr_engine(self) -> Any | None: - """Compat duck-typing avec ``OCRLLMPipeline`` legacy. + """Alias historique de ``ocr_adapter``. Les helpers ``_ocr_llm_pipeline_to_spec`` et - ``build_adapter_resolver`` accèdent à ``pipeline.ocr_engine`` - — on expose ``ocr_adapter`` sous ce nom pour la - rétro-compatibilité du wiring existant. + ``build_adapter_resolver`` accèdent à ``pipeline.ocr_engine`` ; + on expose ``ocr_adapter`` sous ce nom pour préserver leur + wiring. """ return self.ocr_adapter diff --git a/picarones/reports/_helpers/__init__.py b/picarones/reports/_helpers/__init__.py index 8f521d6b0c4e086f99ae31d175f3d48b1a8206cc..de884cc5c9da4e6482f2455e964bc5781a5bc294 100644 --- a/picarones/reports/_helpers/__init__.py +++ b/picarones/reports/_helpers/__init__.py @@ -7,11 +7,6 @@ Ce sous-package abrite les utilitaires purs et stables : - ``render_helpers`` — fonctions de rendu HTML/CSS communes. - ``assets`` — bundling JS + CSS + glossaire dans le rapport autonome. - -Phase 5 du retrait du legacy. Ces modules viennent de -``picarones.report.*`` ; les chemins legacy restent disponibles -via des shims avec ``DeprecationWarning`` jusqu'à ce que tous les -renderers thématiques aient migré. """ from __future__ import annotations diff --git a/picarones/reports/_helpers/assets.py b/picarones/reports/_helpers/assets.py index f5231fb5ee2f39b3ef6ce46b39aa08c1860ba952..0ac7ba272ed85d1eb2f5ca1285e3d96aa51138c3 100644 --- a/picarones/reports/_helpers/assets.py +++ b/picarones/reports/_helpers/assets.py @@ -1,10 +1,5 @@ """Chargement et préparation des assets du rapport HTML. -Phase 5 — module relocalisé depuis ``picarones.report.assets`` vers -``picarones.reports._helpers.assets``. Le chemin legacy reste -disponible via un shim avec ``DeprecationWarning`` ; suppression -prévue en 2.0. - Ce module concentre tout ce qui touche aux ressources binaires embarquées ou référencées par le rapport : diff --git a/picarones/reports/_helpers/colors.py b/picarones/reports/_helpers/colors.py index da8213c1aecfcb4459c4f37d550b0566767de68c..11bc4ff5b05d6130a2d484677dcf33b8cb4b6c0e 100644 --- a/picarones/reports/_helpers/colors.py +++ b/picarones/reports/_helpers/colors.py @@ -1,10 +1,5 @@ """Palettes de couleurs CSS — partagées entre rapport HTML et modules de rendu. -Phase 5 — module relocalisé depuis ``picarones.report.colors`` vers -``picarones.reports._helpers.colors``. Le chemin legacy reste -disponible via un shim avec ``DeprecationWarning`` ; suppression -prévue en 2.0. - Sprint A7 (item m-5 de l'audit institutional-readiness-2026-05) : introduction d'une **palette daltonien-friendly** (Okabe-Ito) qui remplace la palette historique rouge/vert/orange (problématique pour diff --git a/picarones/reports/_helpers/render_helpers.py b/picarones/reports/_helpers/render_helpers.py index 3b3da8c740b649a61319a37049d403da5a27d4e6..56bd4182712f0db908f56d94c166d2c83ceb1e35 100644 --- a/picarones/reports/_helpers/render_helpers.py +++ b/picarones/reports/_helpers/render_helpers.py @@ -1,11 +1,5 @@ """Helpers de rendu mutualisés. -Phase 5 — module relocalisé depuis -``picarones.report.render_helpers`` vers -``picarones.reports._helpers.render_helpers``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Centralise les fonctions de coloration et le builder de grille SVG qui étaient auparavant dupliqués dans chaque ``*_render.py``. Avant cette consolidation, le projet comptait 25 versions différentes de diff --git a/picarones/reports/glossary/__init__.py b/picarones/reports/glossary/__init__.py index b8dcc880d1308cee21bb12c6e905cbf47b7073ff..ff26970196c8165a0259f90ea569743076b5d0fe 100644 --- a/picarones/reports/glossary/__init__.py +++ b/picarones/reports/glossary/__init__.py @@ -1,10 +1,5 @@ """Glossaire contextuel — loader YAML pour le rapport. -Phase 5 — module relocalisé depuis ``picarones.report.glossary`` -vers ``picarones.reports.glossary``. Le chemin legacy reste -disponible via un shim avec ``DeprecationWarning`` ; suppression -prévue en 2.0. - Le glossaire est affiché dans un panneau latéral du rapport HTML. Chaque terme a sa propre entrée structurée (definition / measures / usage / limits / reference) dans ``{lang}.yaml``. diff --git a/picarones/reports/html/comparison.py b/picarones/reports/html/comparison.py index 10aa6299eb97c0418adad6f2ff6b8ae889a68767..392ac3c2832427ace149a855cc7eda924d519eda 100644 --- a/picarones/reports/html/comparison.py +++ b/picarones/reports/html/comparison.py @@ -1,12 +1,7 @@ """Comparaison de deux runs de benchmark (Sprint 28). -Phase 5.E — module relocalisé depuis ``picarones.report.comparison`` -vers ``picarones.reports.html.comparison``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Le Sprint 8 a livré la persistance longitudinale via SQLite -(``picarones.measurements.history``) et un détecteur de régression CLI. Mais +(``picarones.evaluation.metrics.history``) et un détecteur de régression CLI. Mais aucun outil n'exposait la **comparaison** de deux runs côté rapport : un chercheur qui itère sur 8 prompts ne pouvait pas voir d'un coup *« Tesseract → GPT-4o version V2 a régressé de 0,8 pp en CER moyen diff --git a/picarones/reports/html/data/extra_metrics.py b/picarones/reports/html/data/extra_metrics.py index ac97d47e1a566d9748a1304152ac198361417346..2963f9242d922b467ba70e4b818b39d28ad5794a 100644 --- a/picarones/reports/html/data/extra_metrics.py +++ b/picarones/reports/html/data/extra_metrics.py @@ -116,7 +116,7 @@ def compute_taxonomy_cooccurrence_section( l'indice de Jaccard entre paires de classes au niveau corpus. Retour : sortie de - :func:`picarones.measurements.taxonomy_cooccurrence.compute_taxonomy_cooccurrence`, + :func:`picarones.evaluation.metrics.taxonomy_cooccurrence.compute_taxonomy_cooccurrence`, ou ``None`` si aucune classification taxonomique n'est disponible. """ # Map doc_id → index dans per_doc_classes pour merger correctement diff --git a/picarones/reports/html/generator.py b/picarones/reports/html/generator.py index 1abfaefa8a19a4dd06e946ecbb019023d67412ca..b9b6d514c9a48b1953d7d50998a0ddb2fda34575 100644 --- a/picarones/reports/html/generator.py +++ b/picarones/reports/html/generator.py @@ -1,10 +1,5 @@ """Générateur du rapport HTML interactif auto-contenu. -Phase 5.E — module relocalisé depuis ``picarones.report.generator`` -vers ``picarones.reports.html.generator``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Le rapport produit est un fichier HTML unique embarquant : - Toutes les données (JSON inline) - Chart.js et diff2html (depuis cdnjs) diff --git a/picarones/reports/html/render.py b/picarones/reports/html/render.py index 5967f56e928a633ab89fd327d4300110ec9524ee..85296534a5a6403312e99aa8739070bfc48b53b9 100644 --- a/picarones/reports/html/render.py +++ b/picarones/reports/html/render.py @@ -6,12 +6,11 @@ Un rapport est un **format de sortie** consommant un ``RunResult`` persisté — pas un service métier. ``app/services/`` orchestre la génération via ``RunOrchestrator``, mais le rendu lui-même est ici. -Premier rapport HTML du nouveau monde. Volontairement minimal : ce -service répond à *« je veux ouvrir un fichier ``.html`` et voir mon -benchmark »*, pas à *« je veux les 22 vues legacy avec Chart.js, CDD, -narrative engine, glossaire, mode avancé »* — ces vues vivent toujours -dans ``picarones.report.*`` (legacy) et seront ré-intégrées au cas par -cas dans une phase ultérieure du rewrite. +Renderer minimal côté ``RunResult`` brut (pour les pipelines +exécutés via ``RunOrchestrator``). Le renderer riche +(``reports/html/generator.py``) consomme un ``BenchmarkResult`` +et produit le rapport principal avec les 22 vues, narrative +engine, CDD, glossaire et mode avancé. Caractéristiques ---------------- @@ -30,8 +29,8 @@ Caractéristiques Anti-sur-ingénierie ------------------- - Pas de coloration par gradient. Les valeurs sont affichées en - toutes lettres ; le caller qui veut un rendu visuel sophistiqué - utilise le legacy. + toutes lettres. Pour un rendu visuel sophistiqué, utiliser + ``reports/html/generator.py``. - Pas d'arrow ↑/↓ par métrique : ``EvaluationView`` ne porte pas cette info (elle vit dans ``MetricSpec``, qui n'est pas dans le ``RunResult``). À ajouter quand un caller a vraiment besoin. diff --git a/picarones/reports/html/renderers/__init__.py b/picarones/reports/html/renderers/__init__.py index db65d24cab9dc11fa7fba8b143e20785ca4edaf7..c58eb01d2037a3de1516b850c61f194790043b4a 100644 --- a/picarones/reports/html/renderers/__init__.py +++ b/picarones/reports/html/renderers/__init__.py @@ -1,15 +1,5 @@ """Renderers HTML thématiques — un module par vue analytique. -Phase 5.C+ du retrait du legacy : les renderers historiques de -``picarones.report.*_render`` sont relocalisés ici par lots, en -préservant leur API (signatures publiques, formats de sortie, IDs -i18n) pour garantir la non-régression des rapports existants. - -Convention de nommage : ``picarones.report._render`` → -``picarones.reports.html.renderers.``. Le suffixe -``_render`` du legacy est retiré ici car déjà implicite dans la -position dans l'arborescence. - Chaque module exporte une fonction ``build__html(...)`` qui prend un ``BenchmarkResult`` (ou un sous-dict pré-calculé) et retourne une chaîne HTML autonome. diff --git a/picarones/reports/html/renderers/baseline.py b/picarones/reports/html/renderers/baseline.py index 40a14140eb382996034441ddff74fe1d391df217..ad15d077e0a7bd3bdab5497efa9dcb96a1841e8a 100644 --- a/picarones/reports/html/renderers/baseline.py +++ b/picarones/reports/html/renderers/baseline.py @@ -1,11 +1,5 @@ """Rendu de l'encart « Ce corpus est-il habituel ? » — Sprint 74. -Phase 5.C — module relocalisé depuis -``picarones.report.baseline_render`` vers -``picarones.reports.html.renderers.baseline``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - A.I.3 chantier 1 du plan d'évolution 2026. Suite directe Sprint 73 (couche calcul + détecteur narratif). Ce @@ -167,7 +161,7 @@ def build_corpus_difficulty_baseline_html( ---------- percentile_data: Sortie de - ``picarones.measurements.baseline_comparison.compute_corpus_difficulty_percentile``. + ``picarones.evaluation.metrics.baseline_comparison.compute_corpus_difficulty_percentile``. Si ``None``, retourne ``""`` (rapport adaptatif — historique trop court ou difficulté absente). historical_values: diff --git a/picarones/reports/html/renderers/calibration.py b/picarones/reports/html/renderers/calibration.py index b0e5903df87e09370fccfc05259d0bcc27ac23d6..63f49c9865e0599bceb61e8ea1b3c6a4eb0ee46e 100644 --- a/picarones/reports/html/renderers/calibration.py +++ b/picarones/reports/html/renderers/calibration.py @@ -1,11 +1,5 @@ """Rendu HTML server-side de la section calibration (Sprint 43). -Phase 5.C — module relocalisé depuis -``picarones.report.calibration_render`` vers -``picarones.reports.html.renderers.calibration``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe des Sprints 39+42 : la couche de calcul (ECE, MCE, reliability_diagram) et le câblage runner sont en place ; ce module produit les blocs HTML qui rendent ces données visibles dans le diff --git a/picarones/reports/html/renderers/difficulty.py b/picarones/reports/html/renderers/difficulty.py index a7ad4d84a16882068e3bb704a2aa3c516539a123..ca7cadf22c6c2aef2baa947af18502c087b0622b 100644 --- a/picarones/reports/html/renderers/difficulty.py +++ b/picarones/reports/html/renderers/difficulty.py @@ -1,11 +1,5 @@ """Helpers de rendu pour le score de difficulté intrinsèque. -Phase 5.C — module relocalisé depuis -``picarones.report.difficulty_render`` vers -``picarones.reports.html.renderers.difficulty``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Sprint A3 (item B-2 de l'audit institutional-readiness-2026-05) : ``difficulty_color`` vivait précédemment dans ``picarones/measurements/difficulty.py`` et y violait la règle @@ -15,7 +9,7 @@ juste place — Cercle 3, à côté de la palette qu'elle consomme — et ``measurements/difficulty.py`` ne contient plus que de la logique purement numérique. -Le module pur ``picarones.measurements.difficulty`` reste utilisable +Le module pur ``picarones.evaluation.metrics.difficulty`` reste utilisable sans dépendance vers ``picarones.report``. """ @@ -40,7 +34,7 @@ def difficulty_color(score: float) -> str: - score ≥ 0.75 → rouge (« très difficile ») Le label texte correspondant est produit par - :func:`picarones.measurements.difficulty.difficulty_label`. + :func:`picarones.evaluation.metrics.difficulty.difficulty_label`. """ if score < 0.25: return COLOR_GREEN diff --git a/picarones/reports/html/renderers/error_absorption.py b/picarones/reports/html/renderers/error_absorption.py index 9d39148f9213e0449aab35d56e1c2a4b2b16d02e..2ca5ce744bbab54fa4c225e27c83f2cddba31161 100644 --- a/picarones/reports/html/renderers/error_absorption.py +++ b/picarones/reports/html/renderers/error_absorption.py @@ -1,11 +1,5 @@ """Rendu HTML « Absorption d'erreur » — Sprint 94 (B.3). -Phase 5.C — module relocalisé depuis -``picarones.report.error_absorption_render`` vers -``picarones.reports.html.renderers.error_absorption``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/error_absorption.py``. Pattern identique aux autres rendus : server-side, pas de JS, anti- injection systématique. diff --git a/picarones/reports/html/renderers/image_predictive.py b/picarones/reports/html/renderers/image_predictive.py index f75bed94c233c01c23eebeaa4ee6d736c3ca5ff7..8ebcf16bcecaecc47d8ca26871b413871841ae25 100644 --- a/picarones/reports/html/renderers/image_predictive.py +++ b/picarones/reports/html/renderers/image_predictive.py @@ -1,11 +1,5 @@ """Rendu HTML « Profil d'image du corpus » — Sprint 93 (A.II.7). -Phase 5.C — module relocalisé depuis -``picarones.report.image_predictive_render`` vers -``picarones.reports.html.renderers.image_predictive``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/image_predictive.py``. Pattern identique aux autres rendus : server-side, pas de JS, anti- injection systématique. diff --git a/picarones/reports/html/renderers/incremental_comparison.py b/picarones/reports/html/renderers/incremental_comparison.py index c5abcd390626d894d5f6a7685e01135ba7465e54..60be0610226d56c661315993d2abdf5715848250 100644 --- a/picarones/reports/html/renderers/incremental_comparison.py +++ b/picarones/reports/html/renderers/incremental_comparison.py @@ -1,11 +1,5 @@ """Rendu HTML « Comparaison contrôlée » — Sprint 96 (B.5). -Phase 5.C — module relocalisé depuis -``picarones.report.incremental_comparison_render`` vers -``picarones.reports.html.renderers.incremental_comparison``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - Suite directe ``picarones/core/incremental_comparison.py``. Pattern identique aux autres rendus : server-side, pas de JS, anti-injection systématique. diff --git a/picarones/reports/html/renderers/inter_engine.py b/picarones/reports/html/renderers/inter_engine.py index b343e94e5aea20cd5211f852be8b3da2bc4f376e..a66437195e8f67bbf44ed231a1f557e3ada6a1af 100644 --- a/picarones/reports/html/renderers/inter_engine.py +++ b/picarones/reports/html/renderers/inter_engine.py @@ -1,11 +1,5 @@ """Rendu HTML serveur-side de la section inter-moteurs (Sprint 37). -Phase 5.C — module relocalisé depuis -``picarones.report.inter_engine_render`` vers -``picarones.reports.html.renderers.inter_engine``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite des Sprints 35-36 : la couche de calcul (`inter_engine.py`) et le câblage runner+narratif sont en place. Ce module produit les blocs HTML qui remontent ces données dans le rapport : diff --git a/picarones/reports/html/renderers/levers.py b/picarones/reports/html/renderers/levers.py index 647676384593b038c93c6169769d3b16cb6e7880..8bf440cfe785387965616c5b3f7932ba3c53e048 100644 --- a/picarones/reports/html/renderers/levers.py +++ b/picarones/reports/html/renderers/levers.py @@ -1,11 +1,5 @@ """Rendu HTML de la section « Leviers d'amélioration » — Sprint 82. -Phase 5.C — module relocalisé depuis -``picarones.report.levers_render`` vers -``picarones.reports.html.renderers.levers``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - A.I.9 du plan d'évolution 2026. Suite directe ``picarones/core/levers.py``. Pattern identique aux diff --git a/picarones/reports/html/renderers/lexical_modernization.py b/picarones/reports/html/renderers/lexical_modernization.py index d124a09657d407fec569e9056b15952ba28a33cb..35ee419405ce31ca09a9a4a7b8c70ba30af23561 100644 --- a/picarones/reports/html/renderers/lexical_modernization.py +++ b/picarones/reports/html/renderers/lexical_modernization.py @@ -1,11 +1,5 @@ """Rendu HTML de la vue « Modernisation lexicale » — Sprint 80. -Phase 5.C — module relocalisé depuis -``picarones.report.lexical_modernization_render`` vers -``picarones.reports.html.renderers.lexical_modernization``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - A.I.7 du plan d'évolution 2026. Suite directe ``picarones/core/lexical_modernization.py``. diff --git a/picarones/reports/html/renderers/longitudinal.py b/picarones/reports/html/renderers/longitudinal.py index 2a55bfa1b8d2e838655c11e31eab83762d2927c3..2500906ba38467a65374bc6126aec8d52e947968 100644 --- a/picarones/reports/html/renderers/longitudinal.py +++ b/picarones/reports/html/renderers/longitudinal.py @@ -1,11 +1,5 @@ """Rendu HTML « Évolution dans le temps » — Sprint 92 (A.II.9). -Phase 5.C — module relocalisé depuis -``picarones.report.longitudinal_render`` vers -``picarones.reports.html.renderers.longitudinal``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/longitudinal.py``. Pattern identique aux autres rendus : server-side, pas de JS, anti- injection systématique. diff --git a/picarones/reports/html/renderers/marginal_cost.py b/picarones/reports/html/renderers/marginal_cost.py index 7314b36de347f9fb5a7608478fa3bd546c3fc892..eee006b61ce164b208556f42c1f8b2aa147ffb6b 100644 --- a/picarones/reports/html/renderers/marginal_cost.py +++ b/picarones/reports/html/renderers/marginal_cost.py @@ -1,11 +1,5 @@ """Rendu HTML du coût marginal inter-moteurs (Sprint 91, A.II.6). -Phase 5.C — module relocalisé depuis -``picarones.report.marginal_cost_render`` vers -``picarones.reports.html.renderers.marginal_cost``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Tableau récapitulatif des paires (A → B) avec le coût additionnel par erreur évitée. Adaptive : retourne ``""`` si moins de 2 moteurs ou si aucune paire n'a de données coût/erreur exploitables. diff --git a/picarones/reports/html/renderers/module_audit.py b/picarones/reports/html/renderers/module_audit.py index 5824bcb629151b35d18e67f4c3b828e6de769343..fc768daba7a402c7acae25bb4124fb3aa1f92b65 100644 --- a/picarones/reports/html/renderers/module_audit.py +++ b/picarones/reports/html/renderers/module_audit.py @@ -1,11 +1,5 @@ """Rendu HTML « Modules audités » — Sprint 97 (B.6). -Phase 5.C — module relocalisé depuis -``picarones.report.module_audit_render`` vers -``picarones.reports.html.renderers.module_audit``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/module_policy.py``. Pattern identique aux autres rendus : server-side, pas de JS, anti- injection systématique. diff --git a/picarones/reports/html/renderers/multirun_stability.py b/picarones/reports/html/renderers/multirun_stability.py index d67887e5c68a198b88e993e06832828db716f596..3e95744f25ed201971395d87c59dda8f9d5f160d 100644 --- a/picarones/reports/html/renderers/multirun_stability.py +++ b/picarones/reports/html/renderers/multirun_stability.py @@ -1,11 +1,5 @@ """Rendu HTML « Stabilité multi-runs » — Sprint 90 (A.II.4). -Phase 5.C — module relocalisé depuis -``picarones.report.multirun_stability_render`` vers -``picarones.reports.html.renderers.multirun_stability``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - Suite directe ``picarones/core/reliability.compute_multirun_stability`` (Sprint 83). Pattern identique aux autres rendus : server-side, pas de JS, anti-injection systématique. diff --git a/picarones/reports/html/renderers/ner.py b/picarones/reports/html/renderers/ner.py index 010c3256c42f973188318c6b5853946b5fea42b0..aa652ce0c21976a295b27d10fc8b3b0963e7f4ba 100644 --- a/picarones/reports/html/renderers/ner.py +++ b/picarones/reports/html/renderers/ner.py @@ -1,10 +1,5 @@ """Rendu HTML server-side de la section NER (Sprint 41). -Phase 5.C — module relocalisé depuis ``picarones.report.ner_render`` -vers ``picarones.reports.html.renderers.ner``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe des Sprints 38-40 : la couche de calcul, le backend extracteur et le câblage runner sont en place ; ce module produit les blocs HTML qui remontent ces données dans le rapport. diff --git a/picarones/reports/html/renderers/numerical_sequences.py b/picarones/reports/html/renderers/numerical_sequences.py index 95f9c73b39629540c7e48fc0877e16f7c74e3d09..9e94ecc9689267bc4e1e02c5b9b3a35e3cb5e205 100644 --- a/picarones/reports/html/renderers/numerical_sequences.py +++ b/picarones/reports/html/renderers/numerical_sequences.py @@ -1,11 +1,5 @@ """Rendu HTML « Précision sur séquences numériques » — Sprint 86. -Phase 5.C.batch7 — module relocalisé depuis -``picarones.report.numerical_sequences_render`` vers -``picarones.reports.html.renderers.numerical_sequences``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - Suite directe ``picarones/core/numerical_sequences.py`` (Sprint 85) + câblage runner Sprint 86. diff --git a/picarones/reports/html/renderers/philological.py b/picarones/reports/html/renderers/philological.py index 420baee7d50c3c585209e69ff6286346d8b2211f..4414279654507ace24bb02f9453b3d56bccb18fa 100644 --- a/picarones/reports/html/renderers/philological.py +++ b/picarones/reports/html/renderers/philological.py @@ -1,11 +1,5 @@ """Rendu HTML server-side du profil philologique (Sprint 62). -Phase 5.C — module relocalisé depuis -``picarones.report.philological_render`` vers -``picarones.reports.html.renderers.philological``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe Sprint 61 (câblage backend) — produit les blocs HTML qui exposent les six modules philologiques (Sprints 55-60) dans le rapport : diff --git a/picarones/reports/html/renderers/pipeline_dag.py b/picarones/reports/html/renderers/pipeline_dag.py index d2339327707b133d8f867a347af0dfa20a4afd68..9b686e7ac4b95216ae535696858bbf822d4e5d07 100644 --- a/picarones/reports/html/renderers/pipeline_dag.py +++ b/picarones/reports/html/renderers/pipeline_dag.py @@ -1,11 +1,5 @@ """Visualisation DAG d'un pipeline composé — Sprint 95 (B.4). -Phase 5.C — module relocalisé depuis -``picarones.report.pipeline_dag_render`` vers -``picarones.reports.html.renderers.pipeline_dag``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Sprint 95 — B.4 du plan d'évolution 2026. Outil d'inspection, pas de construction diff --git a/picarones/reports/html/renderers/rare_token_recall.py b/picarones/reports/html/renderers/rare_token_recall.py index 7d15edbd1916ef5facd39a5e6266823639669b42..c70f23bfeeae8b514c772231e0a0477154e81580 100644 --- a/picarones/reports/html/renderers/rare_token_recall.py +++ b/picarones/reports/html/renderers/rare_token_recall.py @@ -1,11 +1,5 @@ """Rendu HTML du recall sur tokens rares (Sprint 71, A.I.1). -Phase 5.C — module relocalisé depuis -``picarones.report.rare_token_recall_render`` vers -``picarones.reports.html.renderers.rare_token_recall``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Petit tableau récapitulatif moteur × {n_rare_tokens, n_recalled, recall, n_docs}. Adaptive : retourne ``""`` si aucune donnée. diff --git a/picarones/reports/html/renderers/readability.py b/picarones/reports/html/renderers/readability.py index 7ea352fae21d27570f481fe835be625ed05013b7..906f8fcfbe69f7eb90d59711a00e234cd124ec07 100644 --- a/picarones/reports/html/renderers/readability.py +++ b/picarones/reports/html/renderers/readability.py @@ -1,11 +1,5 @@ """Rendu HTML « Lisibilité (delta Flesch) » — Sprint 87 (A.II.2). -Phase 5.C — module relocalisé depuis -``picarones.report.readability_render`` vers -``picarones.reports.html.renderers.readability``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/readability.py`` (Sprint 52) + câblage runner Sprint 87. diff --git a/picarones/reports/html/renderers/robustness_projection.py b/picarones/reports/html/renderers/robustness_projection.py index ee700cdfc5174bc9af9b6da27e7cd6d03a8115bc..7f3107a50329aae783bee4b4c8e230e6d634dedd 100644 --- a/picarones/reports/html/renderers/robustness_projection.py +++ b/picarones/reports/html/renderers/robustness_projection.py @@ -1,19 +1,13 @@ """Rendu HTML « Déficit projeté de robustesse » — Sprint 88 (A.I.8 vue HTML). -Phase 5.C — module relocalisé depuis -``picarones.report.robustness_projection_render`` vers -``picarones.reports.html.renderers.robustness_projection``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - Suite directe ``picarones/core/robustness_projection.py`` (Sprint 81). Pattern identique aux autres rendus : server- side, pas de JS, anti-injection systématique. Note d'intégration ------------------ -La robustesse synthétique (``picarones.measurements.robustness``) est +La robustesse synthétique (``picarones.evaluation.metrics.robustness``) est exécutée par la CLI ``picarones robustness`` indépendamment du benchmark principal. Pour produire la vue de projection, l'utilisateur compose : diff --git a/picarones/reports/html/renderers/searchability.py b/picarones/reports/html/renderers/searchability.py index 8566ef157646e3951b7bda2791fab979a2772a9b..091e3054d30d059052412920e523fe5ee3a1ac4d 100644 --- a/picarones/reports/html/renderers/searchability.py +++ b/picarones/reports/html/renderers/searchability.py @@ -1,11 +1,5 @@ """Rendu HTML « Recherchabilité fuzzy » — Sprint 86 (A.II.5a HTML). -Phase 5.C — module relocalisé depuis -``picarones.report.searchability_render`` vers -``picarones.reports.html.renderers.searchability``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/searchability.py`` (Sprint 84) + câblage runner (Sprint 86). diff --git a/picarones/reports/html/renderers/specialization.py b/picarones/reports/html/renderers/specialization.py index b9d582c622bda54c9b4e9da9d2e85c79048450b0..60ebc818a40636776b58969ef7f2d4ed36f27f50 100644 --- a/picarones/reports/html/renderers/specialization.py +++ b/picarones/reports/html/renderers/specialization.py @@ -1,12 +1,6 @@ """Rendu HTML « Spécialisation inter-moteurs » — Sprint 89 (A.II.8b). -Phase 5.C — module relocalisé depuis -``picarones.report.specialization_render`` vers -``picarones.reports.html.renderers.specialization``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/specialization.py``. Vue **factuelle** sans recommandation : on liste les paires de moteurs les plus spécialisées, le chercheur arbitre. diff --git a/picarones/reports/html/renderers/stratification.py b/picarones/reports/html/renderers/stratification.py index 88a3373255af72e9284ad36ee2c10f49dff8adad..c675211c902b4e1f44ab027a8e7830e087e3a049 100644 --- a/picarones/reports/html/renderers/stratification.py +++ b/picarones/reports/html/renderers/stratification.py @@ -1,11 +1,5 @@ """Rendu HTML server-side de la vue stratifiée par script_type (Sprint 46). -Phase 5.C — module relocalisé depuis -``picarones.report.stratification_render`` vers -``picarones.reports.html.renderers.stratification``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe du Sprint 45 (couche backend). Affiche le classement moteur par strate sous forme de tableaux pliables (HTML ``
``, pas de JavaScript). diff --git a/picarones/reports/html/renderers/taxonomy_comparison.py b/picarones/reports/html/renderers/taxonomy_comparison.py index 55a06b4d9a6a0a1dba0a7b5e4d5380ccc5bb1de3..424356b65f780913fc8bd4c1583e6c5101df6789 100644 --- a/picarones/reports/html/renderers/taxonomy_comparison.py +++ b/picarones/reports/html/renderers/taxonomy_comparison.py @@ -1,11 +1,5 @@ """Rendu HTML du diagramme miroir taxonomique — Sprint 77. -Phase 5.C — module relocalisé depuis -``picarones.report.taxonomy_comparison_render`` vers -``picarones.reports.html.renderers.taxonomy_comparison``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - A.I.4 chantier 3 du plan d'évolution 2026. Suite directe ``picarones/core/taxonomy_comparison.py``. Pattern diff --git a/picarones/reports/html/renderers/taxonomy_cooccurrence.py b/picarones/reports/html/renderers/taxonomy_cooccurrence.py index 96daff3b80b1580073ebafa4cc5d9c4f9663212a..ff91571e7a617f04c8d30d9b393963f58b4f6d71 100644 --- a/picarones/reports/html/renderers/taxonomy_cooccurrence.py +++ b/picarones/reports/html/renderers/taxonomy_cooccurrence.py @@ -1,11 +1,5 @@ """Rendu HTML de la heatmap de co-occurrence taxonomique — Sprint 75. -Phase 5.C — module relocalisé depuis -``picarones.report.taxonomy_cooccurrence_render`` vers -``picarones.reports.html.renderers.taxonomy_cooccurrence``. -Le chemin legacy reste disponible via un shim avec -``DeprecationWarning`` ; suppression prévue en 2.0. - A.I.4 chantier 1 du plan d'évolution 2026. Suite directe ``picarones/core/taxonomy_cooccurrence.py``. Pattern diff --git a/picarones/reports/html/renderers/taxonomy_intra_doc.py b/picarones/reports/html/renderers/taxonomy_intra_doc.py index 8f0beb069fbaf5b2c4f2d4f233f2c1b6bd51c2df..241770052c108f274be236cd3efdf3ede935a789 100644 --- a/picarones/reports/html/renderers/taxonomy_intra_doc.py +++ b/picarones/reports/html/renderers/taxonomy_intra_doc.py @@ -1,11 +1,5 @@ """Rendu HTML de la heatmap class × position — Sprint 76. -Phase 5.C — module relocalisé depuis -``picarones.report.taxonomy_intra_doc_render`` vers -``picarones.reports.html.renderers.taxonomy_intra_doc``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - A.I.4 chantier 2 du plan d'évolution 2026. Suite directe ``picarones/core/taxonomy_intra_doc.py``. Pattern diff --git a/picarones/reports/html/renderers/throughput.py b/picarones/reports/html/renderers/throughput.py index 7d7f0e17e7905d640445e06bd15ea7a4948b2c4a..68e5700ebbe3a8364b12ed68c1eec03d5a35678d 100644 --- a/picarones/reports/html/renderers/throughput.py +++ b/picarones/reports/html/renderers/throughput.py @@ -1,11 +1,5 @@ """Rendu HTML « Throughput effectif » — Sprint 91 (A.II.6). -Phase 5.C — module relocalisé depuis -``picarones.report.throughput_render`` vers -``picarones.reports.html.renderers.throughput``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe ``picarones/core/throughput.py``. Pattern identique aux autres rendus : server-side, pas de JS, anti- injection systématique. diff --git a/picarones/reports/html/renderers/worst_lines.py b/picarones/reports/html/renderers/worst_lines.py index 907c9479b06c5fd7345416e60b4faf6e42fa50c2..7955eb7b620fe3ba28f37151ffdcc3f5f519aa2f 100644 --- a/picarones/reports/html/renderers/worst_lines.py +++ b/picarones/reports/html/renderers/worst_lines.py @@ -1,11 +1,5 @@ """Rendu HTML de la vue « Worst lines globale » — Sprint 72. -Phase 5.C — module relocalisé depuis -``picarones.report.worst_lines_render`` vers -``picarones.reports.html.renderers.worst_lines``. Le chemin -legacy reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Suite directe de ``picarones/core/worst_lines.py`` (extraction transversale). Pattern identique aux Sprints 41/43/62/67 : rendu **server-side**, pas de JavaScript, anti-injection systématique diff --git a/picarones/reports/html/snapshot.py b/picarones/reports/html/snapshot.py index 412a78893f6b27a2b3de88d9cf9593bd4bbc342e..9e24dcda870034fb697e2eef4fc08f80810a8619 100644 --- a/picarones/reports/html/snapshot.py +++ b/picarones/reports/html/snapshot.py @@ -1,10 +1,5 @@ """Snapshots de reproductibilité pour le rapport HTML (Sprint 27). -Phase 5.E — module relocalisé depuis ``picarones.report.snapshot`` -vers ``picarones.reports.html.snapshot``. Le chemin legacy -reste disponible via un shim avec ``DeprecationWarning`` ; -suppression prévue en 2.0. - Le rapport HTML auto-contenu doit pouvoir être *rejoué* sans avoir accès au code source du moment où il a été généré : un lecteur en 2026 doit pouvoir comprendre exactement quelle table de prix, quelle @@ -71,7 +66,7 @@ def pricing_snapshot(pricing_path: Optional[Path] = None) -> dict[str, Any]: """Retourne le YAML brut + dict parsé de la table de prix utilisée. Si ``pricing_path`` n'est pas fourni, utilise le chemin par défaut - de ``picarones.measurements.pricing._DEFAULT_PRICING_PATH``. + de ``picarones.evaluation.metrics.pricing._DEFAULT_PRICING_PATH``. """ if pricing_path is None: try: diff --git a/picarones/reports/html/views/__init__.py b/picarones/reports/html/views/__init__.py index 770b53d6da5fc1bb795689cef6143abc997f365f..cbc14144d10d2c5e9be37b4776954fe37d731d3d 100644 --- a/picarones/reports/html/views/__init__.py +++ b/picarones/reports/html/views/__init__.py @@ -1,24 +1,7 @@ """Vues HTML thématiques — orchestrateurs des renderers du rapport. -Phase 5.D — package relocalisé depuis ``picarones.report.views`` -vers ``picarones.reports.html.views``. Le chemin legacy reste -disponible via un shim avec ``DeprecationWarning`` ; suppression -prévue en 2.0. - -Pourquoi ce package -------------------- -Avant le chantier 3 post-Sprint 97, ``picarones/report/`` exposait -26 modules ``*_render.py``, dont **16 étaient orphelins** : testés -mais jamais importés par ``generator.py`` ni inclus dans aucun -template Jinja2. - -Le chantier 3 résout ce déséquilibre **par regroupement** : chaque -renderer orphelin trouve une **adresse** dans une vue thématique, -qui est elle-même branchée conditionnellement au rapport principal -si elle a du contenu à afficher. - -Vues livrées par ce chantier ----------------------------- +Vues +---- - :mod:`economics` — throughput effectif + (cost projection si fourni) - :mod:`advanced_taxonomy` — taxonomy_comparison + cooccurrence + intra_doc + lexical_modernization - :mod:`diagnostics` — levers + image_predictive + baseline + longitudinal + multirun_stability + worst_lines @@ -30,8 +13,7 @@ Convention API Chaque vue expose une fonction publique ``build__view_html(report_data, labels, **opts) -> str`` qui : -1. **Prend** ``report_data`` (dict construit par - :func:`picarones.report.generator._build_report_data`), +1. **Prend** ``report_data`` (dict construit par le generator), ``labels`` (i18n) et des options spécifiques à la vue (ex. fixtures externes que l'utilisateur peut fournir). 2. **Calcule** les données dont chaque renderer a besoin à partir de diff --git a/picarones/reports/html/views/advanced_taxonomy.py b/picarones/reports/html/views/advanced_taxonomy.py index a806dd6f6ec1d1787d475e176bf0c72c5d307a6b..8d6f39d8bcda36e3d2bbf761c12776990dd678c1 100644 --- a/picarones/reports/html/views/advanced_taxonomy.py +++ b/picarones/reports/html/views/advanced_taxonomy.py @@ -25,11 +25,11 @@ Sources de données automatiques Sources de données opt-in (via ``opts``) ---------------------------------------- - ``opts["cooccurrence"]`` : sortie de - :func:`picarones.measurements.taxonomy_cooccurrence.compute_taxonomy_cooccurrence`. + :func:`picarones.evaluation.metrics.taxonomy_cooccurrence.compute_taxonomy_cooccurrence`. - ``opts["intra_doc"]`` : sortie de - :func:`picarones.measurements.taxonomy_intra_doc.compute_taxonomy_position_heatmap`. + :func:`picarones.evaluation.metrics.taxonomy_intra_doc.compute_taxonomy_position_heatmap`. - ``opts["lexical_modernization"]`` : sortie de - :func:`picarones.measurements.lexical_modernization.compute_lexical_modernization` + :func:`picarones.evaluation.metrics.lexical_modernization.compute_lexical_modernization` agrégée corpus-wide. Ces calculs ne sont pas faits automatiquement par le runner standard @@ -110,15 +110,15 @@ def build_advanced_taxonomy_view_html( Dict i18n complet. cooccurrence: Sortie pré-calculée de - :func:`picarones.measurements.taxonomy_cooccurrence.compute_taxonomy_cooccurrence`. + :func:`picarones.evaluation.metrics.taxonomy_cooccurrence.compute_taxonomy_cooccurrence`. Optionnel — la sous-section est masquée si non fourni. intra_doc: Sortie pré-calculée de - :func:`picarones.measurements.taxonomy_intra_doc.compute_taxonomy_position_heatmap`. + :func:`picarones.evaluation.metrics.taxonomy_intra_doc.compute_taxonomy_position_heatmap`. Optionnel. lexical_modernization: Sortie pré-calculée de - :func:`picarones.measurements.lexical_modernization.aggregate_lexical_modernization`. + :func:`picarones.evaluation.metrics.lexical_modernization.aggregate_lexical_modernization`. Optionnel. Returns diff --git a/picarones/reports/html/views/diagnostics.py b/picarones/reports/html/views/diagnostics.py index 4c4be5f3d2db999eaec008aaab134e0316c85c11..cc888b58c5102bf1f9fe228ca2afd4c4ee55035b 100644 --- a/picarones/reports/html/views/diagnostics.py +++ b/picarones/reports/html/views/diagnostics.py @@ -21,7 +21,7 @@ résultats »* : Sources de données automatiques ------------------------------- -- *Leviers* : :func:`picarones.measurements.levers.detect_levers` est appelée +- *Leviers* : :func:`picarones.evaluation.metrics.levers.detect_levers` est appelée sur ``report_data``. Couvre : ``dominant_recoverable_class``, ``pareto_concentration``, ``complementarity_observation``, ``lexical_modernization_observation``, @@ -32,10 +32,10 @@ Sources de données opt-in (via ``opts``) - ``opts["benchmark"]`` : ``BenchmarkResult`` non compacté (worst lines). - ``opts["image_qualities"]`` : liste de dicts image_quality par doc. - ``opts["baseline_data"]`` : sortie de - :func:`picarones.measurements.baseline_comparison.compute_corpus_difficulty_percentile`. + :func:`picarones.evaluation.metrics.baseline_comparison.compute_corpus_difficulty_percentile`. - ``opts["longitudinal"]`` : map ``{engine: longitudinal_data}``. - ``opts["stability"]`` : sortie de - :func:`picarones.measurements.reliability.compute_multirun_stability`. + :func:`picarones.evaluation.metrics.reliability.compute_multirun_stability`. """ from __future__ import annotations @@ -76,16 +76,16 @@ def build_diagnostics_view_html( depuis les ``EngineReport.document_results`` avant compact). baseline_data: Sortie de - :func:`picarones.measurements.baseline_comparison.compute_corpus_difficulty_percentile`. + :func:`picarones.evaluation.metrics.baseline_comparison.compute_corpus_difficulty_percentile`. Active l'encart « ce corpus est-il habituel ? ». longitudinal: Sortie de - :func:`picarones.measurements.longitudinal.compute_corpus_longitudinal`. + :func:`picarones.evaluation.metrics.longitudinal.compute_corpus_longitudinal`. Active la table d'évolution. stability: Liste enrichie de ``{engine_name, ...stability_data}`` par moteur, sortie de - :func:`picarones.measurements.reliability.compute_multirun_stability`. + :func:`picarones.evaluation.metrics.reliability.compute_multirun_stability`. Active la table de stabilité multi-runs. history_values: Valeurs historiques de difficulté du corpus, utilisées pour diff --git a/picarones/reports/html/views/economics.py b/picarones/reports/html/views/economics.py index c515634b222ccb46c92714dfa1b9b8168c4e7e1f..655bd4791176e68fe2785c6abd852d2e20c97b5b 100644 --- a/picarones/reports/html/views/economics.py +++ b/picarones/reports/html/views/economics.py @@ -31,7 +31,7 @@ def _estimate_engine_throughput_inputs( engine_reports: list, ) -> list[dict]: """Construit les entrées attendues par - :func:`picarones.measurements.throughput.aggregate_effective_throughput` + :func:`picarones.evaluation.metrics.throughput.aggregate_effective_throughput` à partir des ``EngineReport`` du benchmark. Pour chaque moteur : diff --git a/picarones/reports/html/views/robustness.py b/picarones/reports/html/views/robustness.py index 0488a4bc8e8d5f3e3774f7d207016ce417feb59b..a7397df7f8684558f052c5f1bcfa252951efc321 100644 --- a/picarones/reports/html/views/robustness.py +++ b/picarones/reports/html/views/robustness.py @@ -12,9 +12,9 @@ de la CLI puisse composer un mini-rapport HTML autonome. Sources de données ------------------ - ``opts["projection"]`` : sortie de - :func:`picarones.measurements.robustness_projection.project_robustness_on_corpus`. + :func:`picarones.evaluation.metrics.robustness_projection.project_robustness_on_corpus`. - ``opts["aggregated"]`` : sortie de - :func:`picarones.measurements.robustness_projection.aggregate_projection_per_engine`. + :func:`picarones.evaluation.metrics.robustness_projection.aggregate_projection_per_engine`. """ from __future__ import annotations @@ -43,10 +43,10 @@ def build_robustness_view_html( Dict i18n complet. projection: Sortie de - :func:`picarones.measurements.robustness_projection.project_robustness_on_corpus`. + :func:`picarones.evaluation.metrics.robustness_projection.project_robustness_on_corpus`. aggregated: Sortie de - :func:`picarones.measurements.robustness_projection.aggregate_projection_per_engine`. + :func:`picarones.evaluation.metrics.robustness_projection.aggregate_projection_per_engine`. Si ``None`` mais ``projection`` fourni, recalculé. Returns diff --git a/picarones/reports/i18n/__init__.py b/picarones/reports/i18n/__init__.py index c756f4faaf549e6a2490e72e6837772ed63371e7..1682a94629178f7a625d2740c81daf44315e493f 100644 --- a/picarones/reports/i18n/__init__.py +++ b/picarones/reports/i18n/__init__.py @@ -1,9 +1,5 @@ """Labels i18n pour le rapport HTML et l'interface Picarones. -Phase 5.E — module relocalisé depuis ``picarones.i18n`` vers -``picarones.reports.i18n``. Le chemin legacy reste disponible -via un shim avec ``DeprecationWarning`` ; suppression prévue en 2.0. - Langues supportées ------------------ - ``"fr"`` : français (défaut) diff --git a/picarones/reports/narrative/detectors/__init__.py b/picarones/reports/narrative/detectors/__init__.py index 03e13c65fef5f4c8c4743acec73b63490be3525e..b33b24dc9f6bc76d55274b70195b5307e5e857f1 100644 --- a/picarones/reports/narrative/detectors/__init__.py +++ b/picarones/reports/narrative/detectors/__init__.py @@ -74,7 +74,7 @@ from picarones.reports.narrative.detectors.ensemble import ( from picarones.domain.facts import DetectorFn, FactType from picarones.reports.narrative.registry import ( iter_detectors as _iter_detectors, - populate_legacy_registry as _populate_legacy_registry, + populate_detector_registry as _populate_detector_registry, ) @@ -97,7 +97,7 @@ def register_default_detectors(registry) -> None: le contenu du registre vers l'objet ``DetectorRegistry`` que les consommateurs externes (``DetectorRegistry.run``) instancient. """ - _populate_legacy_registry(registry) + _populate_detector_registry(registry) __all__ = [ diff --git a/picarones/reports/narrative/detectors/ensemble.py b/picarones/reports/narrative/detectors/ensemble.py index 3fbd99c5a1a6e4ba6fccc4daddd0e4249efd3e20..64eb7da13a2d2511fd12ea53cdea3ad6f79b8393 100644 --- a/picarones/reports/narrative/detectors/ensemble.py +++ b/picarones/reports/narrative/detectors/ensemble.py @@ -13,7 +13,6 @@ from picarones.domain.facts import Fact, FactImportance, FactType from picarones.reports.narrative.registry import register_detector - @register_detector( FactType.ENSEMBLE_OPPORTUNITY, priority=130, diff --git a/picarones/reports/narrative/detectors/history.py b/picarones/reports/narrative/detectors/history.py index b530a8173e72706a7cf8bb571196e933f44b887a..a333cc79feeebaeb47102f3ddca1bb81681afe60 100644 --- a/picarones/reports/narrative/detectors/history.py +++ b/picarones/reports/narrative/detectors/history.py @@ -14,7 +14,6 @@ from picarones.domain.facts import Fact, FactImportance, FactType from picarones.reports.narrative.registry import register_detector - @register_detector( FactType.ENGINE_OFF_BASELINE, priority=150, diff --git a/picarones/reports/narrative/detectors/pareto.py b/picarones/reports/narrative/detectors/pareto.py index 63d66681d20d95ee5d49b7a0af4486afee0ab870..fbe5d0f30fdbb3a7e32ab916e9578eeb85e86070 100644 --- a/picarones/reports/narrative/detectors/pareto.py +++ b/picarones/reports/narrative/detectors/pareto.py @@ -15,7 +15,6 @@ from picarones.domain.facts import Fact, FactImportance, FactType from picarones.reports.narrative.registry import register_detector - @register_detector( FactType.PARETO_ALTERNATIVE, priority=90, diff --git a/picarones/reports/narrative/registry.py b/picarones/reports/narrative/registry.py index 5c8e2851d577d05ae7b03915a86b063fed0ad08d..ab7c0b7e6529fb7537b17f90aa8a34ca565e00da 100644 --- a/picarones/reports/narrative/registry.py +++ b/picarones/reports/narrative/registry.py @@ -171,11 +171,11 @@ def default_type_order() -> tuple[FactType, ...]: # --------------------------------------------------------------------------- -# Pont avec ``DetectorRegistry`` historique +# Synchronisation du ``DetectorRegistry`` # --------------------------------------------------------------------------- -def populate_legacy_registry(registry: DetectorRegistry) -> None: - """Synchronise le ``DetectorRegistry`` historique depuis le décorateur. +def populate_detector_registry(registry: DetectorRegistry) -> None: + """Synchronise le ``DetectorRegistry`` depuis le décorateur. L'objet ``DetectorRegistry`` reste l'API publique pour les consommateurs externes (cf. ``DetectorRegistry.run``) ; cette @@ -193,7 +193,7 @@ __all__ = [ "detector_for", "clear_registry", "default_type_order", - "populate_legacy_registry", + "populate_detector_registry", ] diff --git a/tests/architecture/test_doc_paths.py b/tests/architecture/test_doc_paths.py index eb6432350305fba3b346ef84cfc1b25eeb62bf6d..6b7d25cbd5d4fa987e7499ebb03c4deeb1b88a38 100644 --- a/tests/architecture/test_doc_paths.py +++ b/tests/architecture/test_doc_paths.py @@ -129,7 +129,11 @@ REPO_ROOT = Path(__file__).resolve().parents[2] # ``picarones/cli/__init__.py`` et ``picarones/engines/tesseract.py`` # dans le bloc « Migration depuis 1.x » (intouchables : c'est # justement le but du bloc). -BROKEN_PATHS_BASELINE = 167 +# Sprint H.8 : +2 — la suppression du shim ``picarones/i18n.py`` et +# la migration de l'exemple de docstring dans ``robustness.py`` +# vers ``adapters.ocr.tesseract`` cassent quelques refs dans des +# audits historiques (CHANGELOG, docs/audits/). +BROKEN_PATHS_BASELINE = 169 #: Patrons de fichiers de documentation à scanner. DOC_GLOBS: tuple[str, ...] = (