86 lines
3.4 KiB
Python
86 lines
3.4 KiB
Python
"""Couche 'capabilities moteurs' : vérité testable sur les moteurs disponibles.
|
|
|
|
Un moteur n'est *disponible* que si ses dépendances (et son modèle, pour
|
|
CamemBERT) chargent réellement dans l'environnement courant. Cette couche est
|
|
consommée par la GUI (afficher/désactiver) et le CLI (`--engines`) pour que
|
|
l'application ne promette jamais un moteur qu'elle n'embarque pas.
|
|
|
|
Sondes injectables → aucun modèle, aucun réseau dans les tests.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import engine_capabilities as ec
|
|
|
|
|
|
def _probes(camembert=True, eds=False, gliner=False):
|
|
return {
|
|
"camembert": lambda: (camembert, "ok" if camembert else "modèle absent"),
|
|
"eds": lambda: (eds, "ok" if eds else "edsnlp non embarqué"),
|
|
"gliner": lambda: (gliner, "ok" if gliner else "gliner non embarqué"),
|
|
}
|
|
|
|
|
|
def test_capabilities_map_reads_injected_probes():
|
|
caps = ec.capabilities_map(probes=_probes(camembert=True, eds=False, gliner=False))
|
|
assert set(caps) == {"camembert", "eds", "gliner"}
|
|
assert caps["camembert"].available is True
|
|
assert caps["eds"].available is False
|
|
assert caps["gliner"].available is False
|
|
|
|
|
|
def test_camembert_required_others_optional():
|
|
caps = ec.capabilities_map(probes=_probes())
|
|
assert caps["camembert"].required is True
|
|
assert caps["eds"].required is False
|
|
assert caps["gliner"].required is False
|
|
|
|
|
|
def test_reason_surfaced_when_unavailable():
|
|
caps = ec.capabilities_map(probes=_probes(eds=False))
|
|
assert "edsnlp" in caps["eds"].reason # explication présentable à l'utilisateur
|
|
# un moteur disponible expose aussi une raison non vide
|
|
assert caps["camembert"].reason
|
|
|
|
|
|
def test_available_engines_filters_unavailable():
|
|
avail = ec.available_engines(probes=_probes(camembert=True, eds=True, gliner=False))
|
|
keys = {c.key for c in avail}
|
|
assert keys == {"camembert", "eds"}
|
|
|
|
|
|
def test_labels_are_human_readable():
|
|
caps = ec.capabilities_map(probes=_probes())
|
|
assert "CamemBERT" in caps["camembert"].label
|
|
assert "EDS" in caps["eds"].label
|
|
assert "GLiNER" in caps["gliner"].label
|
|
|
|
|
|
def test_default_probes_run_without_crash_and_are_consistent():
|
|
"""Les sondes par défaut (find_spec + fichier modèle) ne crashent pas et
|
|
renvoient un booléen + une raison non vide pour chaque moteur."""
|
|
caps = ec.capabilities_map() # sondes réelles de l'environnement
|
|
assert set(caps) == {"camembert", "eds", "gliner"}
|
|
for cap in caps.values():
|
|
assert isinstance(cap.available, bool)
|
|
assert isinstance(cap.reason, str) and cap.reason
|
|
|
|
|
|
def test_optional_engines_require_bundled_models(monkeypatch, tmp_path):
|
|
monkeypatch.setattr(ec, "_has_module", lambda name: name in {"onnxruntime", "edsnlp", "spacy", "gliner"})
|
|
monkeypatch.setattr(ec, "_app_dir", lambda: tmp_path)
|
|
(tmp_path / "models" / "camembert-bio-deid" / "onnx").mkdir(parents=True)
|
|
(tmp_path / "models" / "camembert-bio-deid" / "onnx" / "model.onnx").write_bytes(b"fake")
|
|
|
|
caps = ec.capabilities_map()
|
|
assert caps["eds"].available is False
|
|
assert "modèle" in caps["eds"].reason
|
|
assert caps["gliner"].available is False
|
|
assert "modèle" in caps["gliner"].reason
|
|
|
|
(tmp_path / "models" / "eds-pseudo-public").mkdir()
|
|
(tmp_path / "models" / "gliner_multi_pii-v1").mkdir()
|
|
caps = ec.capabilities_map()
|
|
assert caps["eds"].available is True
|
|
assert caps["gliner"].available is True
|