feat(server): assainissement PII couche regex+structurelle (tokens typés cohérents)
pii_sanitizer.anonymize_text() remplace la PII par des tokens typés et cohérents ([IPP_1], [AGE_1], [NOM_1]) : protège la donnée ET garde la structure (type de champ) utile à l'apprentissage des variables. Sans modèle, déployable partout. Filet regex (IPP/NIR/TEL/EMAIL/AGE, repris de anonymisation) + règles structurelles cliniques (NOM (NAISSANCE) Prénom ; [Nom Prénom] PACS) + blacklist logiciels anti-FP. 5 tests verts. Couche NER (noms libres) en complément ensuite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
81
tests/unit/test_pii_sanitizer.py
Normal file
81
tests/unit/test_pii_sanitizer.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""Tests de l'assainissement PII des données capturées (titres, texte, OCR).
|
||||
|
||||
Couche 1 (sans modèle) : filet regex sur la PII structurée (IPP, NIR, TEL,
|
||||
EMAIL, AGE) + règles structurelles cliniques (NOM (NAISSANCE) Prénom ;
|
||||
[Nom Prénom] des fenêtres PACS), avec tokens TYPÉS et COHÉRENTS ([IPP_1]…).
|
||||
|
||||
Réutilise l'approche du projet `anonymisation` (placeholders + regex). La
|
||||
couche NER (noms libres) viendra en complément. Cas réels remontés en clinique
|
||||
le 28/06 (anonymisés ici par construction). Branche feat/push-log-dgx.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_ROOT = str(Path(__file__).resolve().parents[2])
|
||||
if _ROOT not in sys.path:
|
||||
sys.path.insert(0, _ROOT)
|
||||
|
||||
|
||||
def test_ipp_et_age_tokenises():
|
||||
from agent_v0.server_v1.pii_sanitizer import anonymize_text
|
||||
|
||||
titre = "VIOLA (VIOLA) Liliane 90 ans - IPP: 168246 - Expert Sante - Mozilla Firefox"
|
||||
out, ents = anonymize_text(titre)
|
||||
|
||||
assert "168246" not in out, out # IPP retiré
|
||||
assert "[IPP_1]" in out
|
||||
assert "90 ans" not in out # âge retiré
|
||||
assert "[AGE_1]" in out
|
||||
# le nom format clinique « NOM (NAISSANCE) Prénom » est tokenisé
|
||||
assert "VIOLA" not in out and "Liliane" not in out, out
|
||||
assert "[NOM_1]" in out
|
||||
# le logiciel n'est pas pris pour de la PII
|
||||
assert "Firefox" in out and "Expert Sante" in out
|
||||
types = {e["type"] for e in ents}
|
||||
assert {"IPP", "AGE", "NOM"} <= types
|
||||
|
||||
|
||||
def test_nom_entre_crochets_pacs():
|
||||
"""Le PACS met le patient entre crochets : `[DATTIN Alix]`."""
|
||||
from agent_v0.server_v1.pii_sanitizer import anonymize_text
|
||||
|
||||
titre = "GXD5 Pacs 4.0.4.307 CIM ARES - [DATTIN Alix] - Mozilla Firefox"
|
||||
out, _ = anonymize_text(titre)
|
||||
|
||||
assert "DATTIN" not in out and "Alix" not in out, out
|
||||
assert "[NOM_1]" in out
|
||||
assert "Pacs" in out and "Firefox" in out # contexte logiciel préservé
|
||||
|
||||
|
||||
def test_coherence_meme_ipp_meme_token():
|
||||
"""Même valeur PII -> même token (sur un mapping partagé de session)."""
|
||||
from agent_v0.server_v1.pii_sanitizer import anonymize_text
|
||||
|
||||
mapping: dict = {}
|
||||
o1, _ = anonymize_text("IPP: 168246 ouvert", mapping=mapping)
|
||||
o2, _ = anonymize_text("dossier IPP: 168246 fermé", mapping=mapping)
|
||||
o3, _ = anonymize_text("IPP: 270020 autre", mapping=mapping)
|
||||
|
||||
assert "[IPP_1]" in o1 and "[IPP_1]" in o2 # même patient -> même token
|
||||
assert "[IPP_2]" in o3 # patient différent -> token différent
|
||||
assert "270020" not in o3
|
||||
|
||||
|
||||
def test_email_et_telephone():
|
||||
from agent_v0.server_v1.pii_sanitizer import anonymize_text
|
||||
|
||||
out, _ = anonymize_text("contact j.dupont@chu.fr / 06 12 34 56 78")
|
||||
assert "@chu.fr" not in out and "[EMAIL_1]" in out
|
||||
assert "06 12 34 56 78" not in out and "[TEL_1]" in out
|
||||
|
||||
|
||||
def test_texte_sans_pii_inchange():
|
||||
from agent_v0.server_v1.pii_sanitizer import anonymize_text
|
||||
|
||||
t = "Expert Sante - Consultation - Mozilla Firefox"
|
||||
out, ents = anonymize_text(t)
|
||||
assert out == t
|
||||
assert ents == []
|
||||
Reference in New Issue
Block a user