Les parseurs géométriques (par cellules de tableau) traitent les 5 PDF du corpus sans jamais déclencher le repli : les parseurs texte étaient 586 lignes de regex fragiles, non testées, à maintenir à chaque évolution du format de sortie. Les références golden sont inchangées après leur suppression — l'extraction produit exactement la même chose. Le parseur géométrique devient donc le seul chemin : ce qu'il ne lit pas est perdu. L'orchestrateur distingue maintenant les deux cas : - aucun lot lu -> ExtractionError (422 côté API). Un compte rendu sans lot n'existe pas : c'est le tableau qui n'a pas été reconnu, et mieux vaut échouer que d'enregistrer un document vide découvert bien plus tard, au moment de relire les chiffres ; - aucune opération -> accepté. Un mois sans dépense reste plausible. _extract_lot_code_from_description était la seule fonction encore utilisée : elle rejoint utils.lots sous le nom extract_lot_numero_from_description, à côté de normalize_lot_numero. extract_text_from_pdf, sans appelant, disparaît au passage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
64 lines
2.2 KiB
Python
64 lines
2.2 KiB
Python
"""Tests de l'orchestrateur d'extraction.
|
|
|
|
Depuis la suppression des parseurs texte de repli, le parseur geometrique est le
|
|
seul chemin : ce qu'il ne lit pas est definitivement perdu. L'orchestrateur doit
|
|
donc distinguer un PDF illisible d'un mois calme.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from plesna_gerance import extractor
|
|
from plesna_gerance.extractor import ExtractionError, extract_compte_rendu
|
|
from plesna_gerance.parsers.pdf import PdfContent
|
|
|
|
_UN_LOT = [{"lot": {"numero": "01", "type": "Appartement T2"}, "lignes": []}]
|
|
|
|
|
|
@pytest.fixture
|
|
def parseurs(monkeypatch):
|
|
"""Neutralise la lecture PDF et pilote ce que renvoie chaque parseur."""
|
|
|
|
def configurer(situation, operations):
|
|
monkeypatch.setattr(
|
|
extractor, "read_pdf", lambda _: PdfContent(text="", words=[])
|
|
)
|
|
monkeypatch.setattr(extractor, "extract_metadata", lambda *_: {})
|
|
monkeypatch.setattr(
|
|
extractor, "extract_situation_locataires_from_pdf", lambda _: situation
|
|
)
|
|
monkeypatch.setattr(
|
|
extractor, "extract_recapitulatif_operations_from_pdf", lambda _: operations
|
|
)
|
|
|
|
return configurer
|
|
|
|
|
|
def test_sans_aucun_lot_l_extraction_echoue(parseurs):
|
|
"""Un PDF dont le tableau des locataires est illisible doit lever."""
|
|
parseurs(situation=[], operations=[{"categorie": "DIVERS"}])
|
|
|
|
with pytest.raises(ExtractionError, match="Aucun lot"):
|
|
extract_compte_rendu("document.pdf")
|
|
|
|
|
|
def test_sans_operation_l_extraction_reussit(parseurs):
|
|
"""Un mois sans depense est plausible : la liste vide est acceptee."""
|
|
parseurs(situation=_UN_LOT, operations=[])
|
|
|
|
resultat = extract_compte_rendu("document.pdf")
|
|
|
|
assert resultat["situation_locataires"] == _UN_LOT
|
|
assert resultat["recapitulatif_operations"] == []
|
|
|
|
|
|
def test_extraction_complete(parseurs):
|
|
"""Cas nominal : les deux sections sont remontees telles quelles."""
|
|
operations = [{"categorie": "DEPENSES_LOCATIVES"}]
|
|
parseurs(situation=_UN_LOT, operations=operations)
|
|
|
|
resultat = extract_compte_rendu("document.pdf")
|
|
|
|
assert resultat["situation_locataires"] == _UN_LOT
|
|
assert resultat["recapitulatif_operations"] == operations
|
|
assert "metadata" in resultat
|