Introduction
En programmation informatique, le débogage (debugging) est le processus essentiel de recherche et de résolution des défauts ou « bugs » qui empêchent un programme de fonctionner correctement. Bien que les bugs soient une partie inévitable du développement logiciel, Python fournit un ensemble d'outils puissants pour vous aider à les diagnostiquer et à les corriger efficacement.
Dans ce laboratoire, vous apprendrez plusieurs techniques fondamentales de débogage en Python. Nous aborderons comment :
- Lever et gérer manuellement les exceptions pour contrôler le flux du programme lors d'erreurs.
- Capturer des traces d'erreurs (tracebacks) détaillées sous forme de chaînes de caractères à des fins de journalisation (logging).
- Utiliser des assertions comme vérifications de cohérence (sanity checks) pour détecter les erreurs logiques précocement.
- Implémenter un système de journalisation flexible pour tracer l'exécution de votre programme et diagnostiquer les problèmes sans interrompre son flux.
Déclenchement des Exceptions
Dans cette étape, vous apprendrez à déclencher manuellement des exceptions à l'aide de l'instruction raise. Les exceptions sont un moyen de signaler qu'une erreur s'est produite. Une instruction raise se compose du mot-clé raise, d'un appel à la fonction Exception(), et d'un message d'erreur utile passé à Exception().
Il est courant de lever des exceptions dans une fonction lorsque ses préconditions ne sont pas satisfaites, puis de gérer ces exceptions dans le code qui appelle la fonction en utilisant des blocs try et except.
Note: Si vous n'êtes pas familier avec l'utilisation de WebIDE (similaire à VS Code), veuillez vous familiariser avec celui-ci via ce laboratoire.
Essayons avec un exemple.
- Ouvrez le fichier
raise_exception.pydans l'explorateur de fichiers à gauche. - Ajoutez le code suivant au fichier. Ce code définit une fonction
box_printqui lève des exceptions pour les arguments invalides, puis appelle cette fonction avec des entrées valides et invalides, capturant les exceptions.
def box_print(symbol, width, height):
if len(symbol) != 1:
raise Exception('Symbol must be a single character string.')
if width <= 2:
raise Exception('Width must be greater than 2.')
if height <= 2:
raise Exception('Height must be greater than 2.')
print(symbol * width)
for i in range(height - 2):
print(symbol + (' ' * (width - 2)) + symbol)
print(symbol * width)
## Handle exceptions when calling the function
for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):
try:
box_print(sym, w, h)
except Exception as err: ## Catch exception and print error message
print('An exception happened: ' + str(err))
- Maintenant, exécutez le script depuis le terminal pour voir comment les exceptions sont levées et gérées.
python3 raise_exception.py
Vous verrez la sortie suivante. Les deux premiers appels à box_print réussissent, tandis que les deux derniers échouent, déclenchant le bloc except pour afficher les messages d'erreur personnalisés.
****
* *
* *
****
OOOOOOOOOOOOOOOOOOOO
O O
O O
O O
OOOOOOOOOOOOOOOOOOOO
An exception happened: Width must be greater than 2.
An exception happened: Symbol must be a single character string.
Obtenir le Traceback sous forme de Chaîne de Caractères
Lorsqu'une exception non gérée se produit, Python affiche une trace d'erreur (traceback), qui est un rapport détaillé des appels de fonctions ayant conduit à l'erreur. Parfois, vous souhaitez gérer une exception de manière élégante tout en enregistrant la trace d'erreur complète pour un débogage ultérieur. Le module traceback vous permet de le faire.
Dans cette étape, vous apprendrez à utiliser traceback.format_exc() pour capturer la trace d'erreur sous forme de chaîne de caractères et l'enregistrer dans un fichier.
- Ouvrez le fichier
get_traceback.pydepuis l'explorateur de fichiers. - Ajoutez le code suivant. Ce script importe le module
traceback, puis utilise un bloctry...exceptpour capturer une exception. À l'intérieur du blocexcept, il écrit la trace d'erreur complète dans un fichier nomméerrorInfo.txt.
import traceback
try:
raise Exception('This is the error message.')
except:
with open('errorInfo.txt', 'w') as error_file:
error_file.write(traceback.format_exc()) ## Write traceback to file
print('The traceback info was written to errorInfo.txt.')
- Exécutez le script dans le terminal.
python3 get_traceback.py
Le script affichera un message de confirmation :
The traceback info was written to errorInfo.txt.
- Maintenant, vérifiez le contenu du fichier nouvellement créé
errorInfo.txt. Vous pouvez l'ouvrir depuis l'explorateur de fichiers ou utiliser la commandecatdans le terminal.
cat errorInfo.txt
Le fichier contiendra la trace d'erreur complète, similaire à ceci :
Traceback (most recent call last):
File "/home/labex/project/get_traceback.py", line 4, in <module>
raise Exception('This is the error message.')
Exception: This is the error message.
Cette technique est extrêmement utile pour journaliser les erreurs dans les applications de production sans faire planter le programme.
Utilisation des Assertions
Les assertions sont des vérifications de cohérence (sanity checks) visant à s'assurer que votre code ne fait rien de manifestement erroné. Une instruction assert vérifie si une condition est vraie. Si la condition est fausse, elle lève une AssertionError, ce qui devrait idéalement faire planter votre programme. Cette approche "fail-fast" (échouer rapidement) vous aide à identifier plus rapidement la cause première d'un bug.
Une instruction assert se compose du mot-clé assert, d'une condition à vérifier, et d'un message d'erreur optionnel.
Dans cette étape, vous utiliserez une assertion pour valider l'état d'un programme.
- Ouvrez le fichier
use_assertions.pydepuis l'explorateur de fichiers. - Ajoutez le code suivant. Il vérifie l'état de
pod_bay_door_status. La première assertion passe silencieusement, mais la seconde échouera et lèvera uneAssertionError.
## assert statement: check condition, raise AssertionError if False
pod_bay_door_status = 'open'
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' ## Passes
pod_bay_door_status = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.'
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' ## Raises AssertionError
- Exécutez le script depuis le terminal.
python3 use_assertions.py
Comme la deuxième assertion échoue, le programme plantera et vous verrez une AssertionError avec votre message personnalisé.
Traceback (most recent call last):
File "/home/labex/project/use_assertions.py", line 6, in <module>
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".'
AssertionError: The pod bay doors need to be "open".
Contrairement aux exceptions, vous ne devez pas gérer les assertions avec try...except. Une AssertionError signale un bug dans le programme qui doit être corrigé. Il est également à noter que les assertions peuvent être désactivées globalement en exécutant Python avec l'option -O (optimize), elles ne doivent donc pas être utilisées pour la validation des entrées qui doit toujours être appliquée.
Implémentation de la journalisation (Logging)
Bien que les instructions print() puissent être utilisées pour le débogage, une approche plus puissante et flexible consiste à utiliser le module logging intégré à Python. La journalisation vous permet de suivre les événements pendant l'exécution de votre programme et de catégoriser les messages par sévérité.
Dans cette étape, vous ajouterez la journalisation à un programme pour aider à diagnostiquer un bug.
- Tout d'abord, ouvrez le fichier
factorial_log.pydepuis l'explorateur de fichiers. - Ajoutez le code suivant. Ce programme tente de calculer la factorielle d'un nombre mais contient un bug. Nous avons ajouté des appels
logging.debug()pour tracer les valeurs des variables à chaque étape. La fonctionlogging.basicConfig()configure le système de journalisation pour afficher les messages de niveauDEBUGet supérieurs.
import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program')
def factorial(n):
logging.debug('Start of factorial(%s)' % (n))
total = 1
for i in range(1, n + 1):
total *= i
logging.debug('i is ' + str(i) + ', total is ' + str(total))
logging.debug('End of factorial(%s)' % (n))
return total
print(factorial(5))
logging.debug('End of program')
- Exécutez le script depuis le terminal.
python3 factorial_log.py
Vous verrez une sortie de journal détaillée entremêlée avec la sortie normale du programme.
%(asctime)s - DEBUG - Start of program
%(asctime)s - DEBUG - Start of factorial(5)
%(asctime)s - DEBUG - i is 1, total is 1
%(asctime)s - DEBUG - i is 2, total is 2
%(asctime)s - DEBUG - i is 3, total is 6
%(asctime)s - DEBUG - i is 4, total is 24
%(asctime)s - DEBUG - i is 5, total is 120
%(asctime)s - DEBUG - End of factorial(5)
120
%(asctime)s - DEBUG - End of program
(Note : Le markdown original contenait un bug dans le code d'exemple. Le code corrigé est fourni ici pour une meilleure expérience d'apprentissage. Le bug original était range(n + 1) qui commence à 0, rendant le total toujours 0. La correction est range(1, n + 1).)
En examinant les messages de journal, vous pouvez clairement voir la valeur de i et total à chaque itération de la boucle, ce qui est un moyen puissant de comprendre le flux du programme et de trouver des bugs.
Configuration du comportement de la journalisation
Le module logging est hautement configurable. Vous pouvez contrôler le niveau de sévérité des messages à afficher, désactiver complètement la journalisation, ou rediriger les messages de journal vers un fichier au lieu de l'écran.
Niveaux de Journalisation
Il existe cinq niveaux de journalisation standard, chacun avec une fonction correspondante :
| Niveau | Fonction de Journalisation | Description |
|---|---|---|
DEBUG |
logging.debug() |
Pour les petits détails, utiles uniquement lors du diagnostic de problèmes. |
INFO |
logging.info() |
Pour enregistrer des événements généraux ou confirmer que les choses fonctionnent comme prévu. |
WARNING |
logging.warning() |
Pour indiquer un problème potentiel qui n'arrête pas le programme. |
ERROR |
logging.error() |
Pour enregistrer une erreur qui a provoqué l'échec d'une opération spécifique. |
CRITICAL |
logging.critical() |
Pour une erreur fatale sur le point de provoquer l'arrêt du programme. |
Lorsque vous définissez un niveau de journalisation dans basicConfig, Python affichera les messages à ce niveau et à tous les niveaux supérieurs. Par exemple, définir level=logging.INFO affichera les messages INFO, WARNING, ERROR et CRITICAL, mais pas DEBUG.
Désactivation de la Journalisation
Après le débogage, vous voudrez peut-être désactiver tous les messages de journal sans supprimer les appels logging de votre code. Vous pouvez le faire avec logging.disable(). Il prend un niveau comme argument et désactive tous les messages de journal à ce niveau et en dessous. Par exemple, logging.disable(logging.CRITICAL) supprimera tous les messages de journal.
Journalisation vers un Fichier
Au lieu d'afficher les journaux dans la console, vous pouvez les enregistrer dans un fichier en passant l'argument mot-clé filename à logging.basicConfig().
Mettons cela en pratique.
- Ouvrez le fichier
configure_logging.py. - Ajoutez le code suivant. Il configure la journalisation pour écrire tous les messages de niveau
DEBUGet supérieur dans un fichier nommémyProgramLog.txt.
import logging
## Configure logging to write to a file
logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a debug message.')
logging.info('This is an info message.')
logging.warning('This is a warning message.')
- Exécutez le script depuis le terminal.
python3 configure_logging.py
Cette fois, vous ne verrez aucune sortie dans le terminal.
- Vérifiez le contenu du fichier
myProgramLog.txt.
cat myProgramLog.txt
Vous verrez que tous les messages de journal ont été écrits dans le fichier, avec horodatages et niveaux de sévérité complets.
2023-10-27 10:30:00,123 - DEBUG - This is a debug message.
2023-10-27 10:30:00,123 - INFO - This is an info message.
2023-10-27 10:30:00,123 - WARNING - This is a warning message.
Ceci conclut notre tour d'horizon des techniques de débogage Python de base.
Résumé
Dans ce laboratoire, vous avez appris et pratiqué plusieurs techniques essentielles de débogage en Python. Vous avez commencé par utiliser l'instruction raise pour créer et déclencher des exceptions personnalisées, et les gérer avec des blocs try...except. Vous avez ensuite appris à capturer un traceback d'exception complet sous forme de chaîne de caractères en utilisant traceback.format_exc() à des fins de journalisation.
Ensuite, vous avez exploré les instructions assert comme moyen d'effectuer des vérifications de cohérence (sanity checks) et de "échouer rapidement" (fail fast) lorsque votre programme entre dans un état inattendu. Enfin, vous vous êtes penché sur le module logging, apprenant comment le configurer pour afficher des messages, contrôler la sortie avec différents niveaux de journalisation et écrire les journaux dans un fichier pour un enregistrement persistant.
Ces compétences sont fondamentales pour écrire des applications Python robustes, maintenables et plus faciles à déboguer.



