Renforce les contrats : types complets et docstrings de methode protegees

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Ralph Mayola 2026-08-23 17:53:12 +02:00
parent 54479d9af9
commit 434944def6
2 changed files with 17 additions and 3 deletions

View File

@ -5,7 +5,13 @@ le noyau parle au monde extérieur. Tout ce qui dépend d'un système d'exploita
d'une bibliothèque d'affichage ou d'un moteur de transcription vit DERRIÈRE l'un d'une bibliothèque d'affichage ou d'un moteur de transcription vit DERRIÈRE l'un
d'eux — jamais dans `core.py`, `controller.py` ni `audio_level.py`. d'eux — jamais dans `core.py`, `controller.py` ni `audio_level.py`.
""" """
from typing import Protocol from typing import IO, Protocol
# numpy entre dans ce fichier volontairement minuscule car c'est déjà une
# dépendance dure du projet, et le type du signal audio fait partie du
# contrat : un `Any` implicite laisserait passer un mauvais type sans que
# rien ne bronche.
import numpy as np
class Transcripteur(Protocol): class Transcripteur(Protocol):
@ -14,7 +20,7 @@ class Transcripteur(Protocol):
def warmup(self) -> None: def warmup(self) -> None:
"""Charge le modèle une fois, pour que la première dictée ne traîne pas.""" """Charge le modèle une fois, pour que la première dictée ne traîne pas."""
def transcrire(self, audio) -> str: def transcrire(self, audio: np.ndarray) -> str:
"""Rend le texte d'un tableau numpy float32 mono.""" """Rend le texte d'un tableau numpy float32 mono."""
@ -55,5 +61,5 @@ class Systeme(Protocol):
def dossier_donnees(self) -> str: def dossier_donnees(self) -> str:
"""Dossier des données de l'application (verrou d'instance, réglages).""" """Dossier des données de l'application (verrou d'instance, réglages)."""
def acquerir_verrou_instance(self, chemin: str): def acquerir_verrou_instance(self, chemin: str) -> IO | None:
"""Verrou exclusif non bloquant ; rend le fichier, ou None s'il est pris.""" """Verrou exclusif non bloquant ; rend le fichier, ou None s'il est pris."""

View File

@ -21,6 +21,14 @@ def test_le_contrat_declare_exactement_ses_methodes(contrat, methodes):
if not n.startswith("_")] if not n.startswith("_")]
assert sorted(declarees) == sorted(methodes) assert sorted(declarees) == sorted(methodes)
# Ce sont les docstrings de MÉTHODE qui portent l'essentiel du contrat
# (la plage [0, 1] de set_level, l'affinité thread, la sémantique de
# retour) : une docstring vidée ici doit rougir, pas seulement celle
# de la classe.
for nom in methodes:
methode = getattr(contrat, nom)
assert methode.__doc__, f"{contrat.__name__}.{nom} doit dire à quoi il sert"
def test_les_contrats_sont_documentes(): def test_les_contrats_sont_documentes():
for contrat in (Transcripteur, Overlay, Systeme): for contrat in (Transcripteur, Overlay, Systeme):