Picarones / tests /architecture /test_s7_no_silent_excepts.py
Claude
chore(sprint-S7)!: nettoyage qualité — shims supprimés, silent excepts éliminés
f8a5c40 unverified
Raw
History Blame
2.35 kB
"""Sprint S7.4 — invariant CLAUDE.md : pas de ``except Exception: pass``.
CLAUDE.md déclare comme règle stricte :
**Ne jamais mettre `except Exception: pass`** : remplacer par
`logger.warning("[module] fonctionnalité dégradée : %s", e)`.
Ce test scanne la base et échoue si un nouveau silent-except est
introduit. Trois patterns silencieux interdits :
1. ``except Exception: pass`` (le plus visible).
2. ``except Exception: ...`` (Ellipsis comme no-op).
3. ``except Exception as e: pass`` (typo qui ressemble à du log).
Best-effort accepté avec ``logger.debug(...)`` minimum (signal
opérationnel pour ops).
"""
from __future__ import annotations
import re
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
PRODUCTION = REPO_ROOT / "picarones"
# Patterns interdits
_SILENT_EXCEPT_RE = re.compile(
r"except\s+(?:\([^)]*Exception[^)]*\)|Exception)\s*"
r"(?:as\s+\w+)?\s*:\s*(?:#[^\n]*)?\s*\n"
r"(\s+)(pass|\.\.\.)\s*$",
re.MULTILINE,
)
def _scan_silent_excepts() -> list[tuple[str, int, str]]:
issues: list[tuple[str, int, str]] = []
for f in PRODUCTION.rglob("*.py"):
if "__pycache__" in str(f):
continue
text = f.read_text(encoding="utf-8")
for m in _SILENT_EXCEPT_RE.finditer(text):
line_no = text[: m.start()].count("\n") + 1
relpath = str(f.relative_to(REPO_ROOT))
issues.append((relpath, line_no, m.group(2)))
return issues
def test_no_silent_except_exception_in_production() -> None:
"""Aucun ``except Exception: pass`` dans le code production.
Le test échoue si un mainteneur introduit un silent except.
Pour fixer : remplacer ``pass`` par ``logger.warning(...)``
ou ``logger.debug(...)`` selon la criticité.
"""
issues = _scan_silent_excepts()
if issues:
formatted = "\n".join(
f" - {f}:{line} ({kind})" for f, line, kind in issues
)
raise AssertionError(
f"Violations CLAUDE.md règle « pas de "
f"``except Exception: pass`` » détectées dans "
f"{len(issues)} emplacement(s) :\n{formatted}\n\n"
f"Remplacer ``pass`` par "
f"``logger.warning('[module] feature dégradée : %s', e)`` "
f"ou ``logger.debug(...)`` pour les best-effort."
)