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:
+14
-3
@@ -1,3 +1,4 @@
|
|||||||
|
import sqlite3
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Callable
|
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}")
|
raise ValueError(f"Table inconnue : {table}")
|
||||||
cfg = TABLES[table]
|
cfg = TABLES[table]
|
||||||
coerced = _coerce_value(table, column, value)
|
coerced = _coerce_value(table, column, value)
|
||||||
get_conn().execute(
|
try:
|
||||||
f"UPDATE {table} SET {column} = ? WHERE {cfg.pk} = ?", (coerced, pk_value)
|
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(
|
def find_changed_cell(
|
||||||
|
|||||||
@@ -68,6 +68,28 @@ def test_set_cell_writes_valid_value(users_db_path):
|
|||||||
assert rows[0]["siret"] == "12345678900011"
|
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):
|
def test_set_cell_coerces_numeric_type(users_db_path):
|
||||||
from src.auth import db as auth_db
|
from src.auth import db as auth_db
|
||||||
from src.subscriptions import db as sub_db
|
from src.subscriptions import db as sub_db
|
||||||
|
|||||||
Reference in New Issue
Block a user