Lever une exception pour une donnée invalide
Objectif : Lever une exception explicite lorsqu’un montant de dépense ne respecte pas les règles définies.
Un montant invalide peut fausser le total des dépenses sans provoquer immédiatement d’erreur visible. Pour éviter qu’une donnée incohérente entre dans le calcul, vous allez définir les règles attendues et faire échouer clairement la fonction qui reçoit une valeur incorrecte.
Dans la leçon précédente, vous avez appris à lire un traceback pour retrouver l’origine d’une erreur. Ici, vous provoquez volontairement un échec explicite lorsque le montant ne respecte pas les règles du projet : il doit être numérique et strictement positif.
Définir les préconditions du calcul
Une précondition est une règle que les arguments doivent respecter avant qu’une fonction puisse effectuer son travail. Pour total_depenses, chaque transaction doit fournir un montant numérique strictement supérieur à zéro. Fixer cette règle à l’entrée du calcul évite de produire un total à partir d’une valeur absente, textuelle ou négative.
Python fournit des exceptions intégrées qui décrivent différentes catégories de problèmes. TypeError convient lorsque la valeur n’a pas le type attendu ; ValueError convient lorsque son type est correct, mais que sa valeur ne respecte pas la règle métier. L’instruction raise lève l’exception choisie et interrompt le calcul en cours.
Faire respecter la règle dans le module métier
Modifiez depenses/transactions.py pour contrôler chaque montant avant de l’ajouter au total. Le contrôle distingue une valeur non numérique d’un montant numérique nul ou négatif. Le fichier ci-dessous est complet et conserve le nom de fonction utilisé par depenses/main.py.
def total_depenses(transactions):
total = 0.0
for index, transaction in enumerate(transactions, start=1):
montant = transaction["montant"]
if isinstance(montant, bool) or not isinstance(montant, (int, float)):
raise TypeError(
f"Le montant de la transaction {index} doit être numérique."
)
if montant <= 0:
raise ValueError(
f"Le montant de la transaction {index} doit être strictement positif."
)
total += montant
return totalLe test sur bool est nécessaire parce qu’en Python les booléens sont aussi considérés comme des nombres entiers : sans ce test, True serait accepté comme un montant de 1. L’index commence à 1 pour que le message désigne une transaction dans un ordre naturel pour la personne qui utilise le programme. Une liste vide reste acceptable et produit un total de zéro, puisqu’aucun montant invalide n’est présent.
Vérifier les cas valides et invalides
Vous pouvez vérifier les règles sans modifier le point d’entrée de l’application, en exécutant un court programme depuis la racine du projet. Le premier appel doit afficher le total existant ; les deux suivants doivent s’arrêter sur des exceptions différentes, car ils enfreignent deux règles différentes.
from depenses.transactions import total_depenses
transactions_valides = [
{"montant": 42.80},
{"montant": 18.50},
]
print(f"Total des dépenses : {total_depenses(transactions_valides):.2f} EUR")
print(total_depenses([{"montant": "18.50"}]))
print(total_depenses([{"montant": -2.00}]))Total des dépenses : 61.30 EUR
Traceback (most recent call last):
...
TypeError: Le montant de la transaction 1 doit être numérique.
La troisième instruction n’est pas exécutée : la deuxième a levé une exception.Pour observer aussi le cas négatif, exécutez séparément l’appel correspondant : total_depenses([{"montant": -2.00}]). Il lève une ValueError avec le message indiquant que le montant doit être strictement positif. Une chaîne numérique telle que "18.50" reste refusée : la conversion des champs provenant de fichiers sera traitée dans la leçon consacrée à la lecture CSV, et ne doit pas être supposée ici.
Cette leçon laisse volontairement l’exception remonter jusqu’à l’appelant. La prochaine leçon montrera où placer les blocs try et except pour intercepter un échec et présenter un message utile, sans mélanger cette responsabilité avec le calcul du total.
À retenir
- Définissez les préconditions d’une fonction à partir des règles métier qu’elle doit garantir.
- Levez une exception avec
raisedès qu’une donnée invalide est détectée. - Utilisez
TypeErrorpour un type inadapté etValueErrorpour une valeur interdite. - Ne transformez pas une donnée invalide en résultat plausible : signalez le problème à l’appelant.