Normaliser les échecs d'écriture set_cell en ValueError

- IntegrityError (ex: email déjà utilisé) est désormais capturée et
  reconvertie en ValueError, pour rester dans le funnel d'alerte
  existant du callback admin au lieu de faire planter le callback Dash.
- Une UPDATE qui touche 0 ligne (ligne supprimée entre le chargement du
  tableau et la soumission de l'édition) lève désormais une ValueError
  au lieu d'être silencieusement traitée comme un succès (ce qui aurait
  créé un log d'audit trompeur).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Colin Maudry
2026-07-03 23:10:32 +02:00
parent eb8f54dbf2
commit 1551faaf0c
2 changed files with 36 additions and 3 deletions
+12 -1
View File
@@ -1,3 +1,4 @@
import sqlite3
from dataclasses import dataclass
from typing import Callable
@@ -134,9 +135,19 @@ def set_cell(table: str, pk_value, column: str, value) -> None:
raise ValueError(f"Table inconnue : {table}")
cfg = TABLES[table]
coerced = _coerce_value(table, column, value)
get_conn().execute(
try:
cursor = get_conn().execute(
f"UPDATE {table} SET {column} = ? WHERE {cfg.pk} = ?", (coerced, pk_value)
)
except sqlite3.IntegrityError as exc:
raise ValueError(
f"Écriture refusée pour {column} (contrainte violée) : {value!r}"
) from exc
if cursor.rowcount == 0:
raise ValueError(
f"Ligne introuvable (table={table}, {cfg.pk}={pk_value!r}) — "
"probablement supprimée entre-temps."
)
def find_changed_cell(
+22
View File
@@ -68,6 +68,28 @@ def test_set_cell_writes_valid_value(users_db_path):
assert rows[0]["siret"] == "12345678900011"
def test_set_cell_raises_valueerror_on_unique_constraint_violation(users_db_path):
from src.auth import db as auth_db
auth_db.init_schema()
auth_db.create_user("first@ex.fr", "hash")
second_uid = auth_db.create_user("second@ex.fr", "hash")
with pytest.raises(ValueError):
tables.set_cell("users", second_uid, "email", "first@ex.fr")
def test_set_cell_raises_valueerror_when_row_missing(users_db_path):
from src.auth import db as auth_db
auth_db.init_schema()
uid = auth_db.create_user("a@ex.fr", "hash")
auth_db.delete_user(uid)
with pytest.raises(ValueError):
tables.set_cell("users", uid, "email", "new@ex.fr")
def test_set_cell_coerces_numeric_type(users_db_path):
from src.auth import db as auth_db
from src.subscriptions import db as sub_db