Comprendre le traçage Python

Comprendre le traçage Python

Python imprime un traceback lorsqu’une exception est levée dans votre code. La sortie de traçage peut être un peu écrasante si vous la voyez pour la première fois ou si vous ne savez pas ce qu’elle vous dit. Mais le retraçage Python possède une multitude d’informations qui peuvent vous aider à diagnostiquer et à corriger la raison de l’exception levée dans votre code. Comprendre les informations fournies par un traçage Python est essentiel pour devenir un meilleur programmeur Python.

*À la fin de ce didacticiel, vous serez en mesure de:*
  • Donnez un sens à la prochaine trace que vous voyez

  • Reconnaître certains des retraits les plus courants

  • Consigner un traçage avec succès tout en gérant l’exception

    *Bonus gratuit:* lien: [Cliquez ici pour obtenir notre aide-mémoire Python gratuit] qui vous montre les bases de Python 3, comme travailler avec des types de données, des dictionnaires, des listes et des fonctions Python.

Qu’est-ce qu’un Python Traceback?

Un traceback est un rapport contenant les appels de fonction effectués dans votre code à un point spécifique. Les traces sont connues sous de nombreux noms, notamment trace de pile , trace de pile , trace et peut-être d’autres. En Python, le terme utilisé est traceback .

Lorsque votre programme entraîne une exception, Python imprimera le traceback actuel pour vous aider à savoir ce qui s’est passé. Voici un exemple pour illustrer cette situation:

# example.py
def greet(someone):
    print('Hello, ' + someon)

greet('Chad')

Ici, + saluer () + est appelé avec le paramètre + quelqu’un +. Cependant, dans + accueillir () +, ce nom de variable n’est pas utilisé. Au lieu de cela, il a été mal orthographié comme + someon + dans l’appel + print () +.

*Remarque:* Ce didacticiel suppose que vous comprenez les exceptions Python. Si vous n'êtes pas familier ou si vous voulez juste un rafraîchissement, alors vous devriez consulter https://realpython.com/python-exceptions/[Python Exceptions: An Introduction].

Lorsque vous exécutez ce programme, vous obtiendrez le retraçage suivant:

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 4, in <module>
    greet('Chad')
  File "/path/to/example.py", line 2, in greet
    print('Hello, ' + someon)
NameError: name 'someon' is not defined

Cette sortie de traceback contient toutes les informations dont vous aurez besoin pour diagnostiquer le problème. La dernière ligne de la sortie traceback vous indique quel type d’exception a été déclenché ainsi que des informations pertinentes sur cette exception. Les lignes précédentes du traceback indiquent le code qui a entraîné la levée de l’exception.

Dans le traceback ci-dessus, l’exception était un + NameError +, ce qui signifie qu’il existe une référence à un nom (variable, fonction, classe) qui n’a pas été défini. Dans ce cas, le nom référencé est + someon +.

Dans ce cas, la dernière ligne contient suffisamment d’informations pour vous aider à résoudre le problème. La recherche du code pour le nom + someon +, qui est une faute d’orthographe, vous dirigera dans la bonne direction. Souvent, cependant, votre code est beaucoup plus compliqué.

Comment lisez-vous un suivi Python?

Le traçage Python contient de nombreuses informations utiles lorsque vous essayez de déterminer la raison pour laquelle une exception est déclenchée dans votre code. Dans cette section, vous allez parcourir différents retraits afin de comprendre les différents éléments d’information contenus dans un retraçage.

Présentation de Python Traceback

Il existe plusieurs sections importantes pour chaque traceback Python. Le schéma ci-dessous met en évidence les différentes parties:

Un exemple de traçage Python avec appels.

En Python, il est préférable de lire le traçage de bas en haut:

  1. Boîte bleue: La dernière ligne du traçage est la ligne de message d’erreur. Il contient le nom d’exception qui a été déclenché.

  2. Boîte verte: Après le nom de l’exception se trouve le message d’erreur. Ce message contient généralement des informations utiles pour comprendre la raison de la levée de l’exception.

  3. Boîte jaune: Plus haut dans le traçage se trouvent les différents appels de fonction allant de bas en haut, du plus récent au moins récent. Ces appels sont représentés par des entrées de deux lignes pour chaque appel. La première ligne de chaque appel contient des informations telles que le nom de fichier, le numéro de ligne et le nom du module, toutes spécifiant où le code peut être trouvé.

  4. Souligné en rouge: La deuxième ligne de ces appels contient le code réel qui a été exécuté.

Il existe quelques différences entre la sortie de traceback lorsque vous exécutez votre code dans la ligne de commande et exécutez le code dans le REPL. Ci-dessous se trouve le même code de la section précédente exécuté dans un REPL et la sortie de traceback résultante:

>>>

>>> def greet(someone):
...   print('Hello, ' + someon)
...
>>> greet('Chad')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greet
NameError: name 'someon' is not defined

Notez qu’à la place des noms de fichiers, vous obtenez " <stdin> ". Cela a du sens puisque vous avez tapé le code via une entrée standard. En outre, les lignes de code exécutées ne sont pas affichées dans le suivi.

*Remarque* : Si vous avez l'habitude de voir les traces de pile dans d'autres langages de programmation, vous remarquerez une différence majeure dans la façon dont un traceback Python ressemble en comparaison. La plupart des autres langues affichent l'exception en haut, puis passent de haut en bas, des appels les plus récents aux moins récents.

Cela a déjà été dit, mais pour réitérer, un retraçage Python doit être lu de bas en haut. Ceci est très utile car le traçage est imprimé et votre terminal (ou partout où vous lisez le traçage) se retrouve généralement au bas de la sortie, vous donnant l’endroit idéal pour commencer à lire le traçage.

Procédure pas à pas de traçage spécifique

Le fait de passer par une sortie de traçage spécifique vous aidera à mieux comprendre et à voir quelles informations le traçage vous donnera.

Le code ci-dessous est utilisé dans les exemples suivants pour illustrer les informations que vous fournit un traçage Python:

# greetings.py
def who_to_greet(person):
    return person if person else input('Greet who? ')

def greet(someone, greeting='Hello'):
    print(greeting + ', ' + who_to_greet(someone))

def greet_many(people):
    for person in people:
        try:
            greet(person)
        except Exception:
            print('hi, ' + person)

Ici, + who_to_greet () + prend une valeur, + person +, et la renvoie ou invite une valeur à retourner à la place.

Ensuite, + saluer () + prend un nom à saluer, + quelqu’un +, et une valeur facultative + salutation + et appelle + print () +. + who_to_greet () + est également appelé avec la valeur + quelqu’un + transmise.

Enfin, + saluer_many () + va parcourir la liste des + personnes + et appeler + saluer () +. S’il y a une exception levée en appelant + saluer () +, alors un simple message d’accueil de sauvegarde est imprimé.

Ce code ne contient aucun bogue qui entraînerait la levée d’une exception tant que la bonne entrée est fournie.

Si vous ajoutez un appel à + ​​Message de bienvenue () + au bas de + Message de bienvenue.py + et spécifiez un argument de mot clé auquel il ne s’attend pas (par exemple `+ Message de bienvenue ('Chad', greting = 'Yo' ) + `), vous obtiendrez le traceback suivant:

$ python example.py
Traceback (most recent call last):
  File "/path/to/greetings.py", line 19, in <module>
    greet('Chad', greting='Yo')
TypeError: greet() got an unexpected keyword argument 'greting'

Encore une fois, avec une traceback Python, il est préférable de travailler en arrière, en remontant la sortie. À partir de la dernière ligne du traceback, vous pouvez voir que l’exception était un + TypeError +. Les messages qui suivent le type d’exception, tout ce qui se trouve après les deux-points, vous donnent d’excellentes informations. Il vous indique que + salutation () + a été appelé avec un argument de mot clé auquel il ne s’attendait pas. Le nom d’argument inconnu vous est également donné: + greting +.

En remontant, vous pouvez voir la ligne qui a entraîné l’exception. Dans ce cas, il s’agit de l’appel + salutation () + que nous avons ajouté au bas de + salutations.py +.

La ligne suivante vous donne le chemin d’accès au fichier où le code existe, le numéro de ligne de ce fichier où le code peut être trouvé et dans quel module il se trouve. Dans ce cas, parce que notre code n’utilise aucun autre module Python, nous voyons juste + <module> + ici, ce qui signifie que c’est le fichier qui est en cours d’exécution.

Avec un fichier différent et une entrée différente, vous pouvez voir que le traceback vous pointe vraiment dans la bonne direction pour trouver le problème. Si vous suivez, supprimez l’appel buggy +reet () + du bas de +reetings.py + et ajoutez le fichier suivant à votre répertoire:

# example.py
from greetings import greet

greet(1)

Ici, vous avez configuré un autre fichier Python qui importe votre module précédent, + salutations.py +, et en utilisant + accueillir () + à partir de celui-ci. Voici ce qui se passe si vous exécutez maintenant + example.py +:

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 3, in <module>
    greet(1)
  File "/path/to/greetings.py", line 5, in greet
    print(greeting + ', ' + who_to_greet(someone))
TypeError: must be str, not int

L’exception levée dans ce cas est à nouveau un + TypeError +, mais cette fois le message est un peu moins utile. Il vous indique que quelque part dans le code, il s’attendait à travailler avec une chaîne, mais un entier a été donné.

En remontant, vous voyez la ligne de code qui a été exécutée. Ensuite, le fichier et le numéro de ligne du code. Cette fois, cependant, au lieu de + <module> +, nous obtenons le nom de la fonction qui était en cours d’exécution, + saluer () +.

En passant à la prochaine ligne de code exécutée, nous voyons notre appel problématique + accueillir () + passer dans un entier.

Parfois, après qu’une exception est levée, un autre morceau de code intercepte cette exception et entraîne également une exception. Dans ces situations, Python affichera tous les retraits d’exception dans l’ordre dans lequel ils ont été reçus, se terminant une fois de plus par le dernier retour de l’exception.

Comme cela peut être un peu déroutant, voici un exemple. Ajoutez un appel à +reet_many () + au bas de + salutations.py +:

# greetings.py
...
greet_many(['Chad', 'Dan', 1])

Cela devrait entraîner l’impression de salutations pour les trois personnes. Cependant, si vous exécutez ce code, vous verrez un exemple des multiples retraits en cours de sortie:

$ python greetings.py
Hello, Chad
Hello, Dan
Traceback (most recent call last):
  File "greetings.py", line 10, in greet_many
    greet(person)
  File "greetings.py", line 5, in greet
    print(greeting + ', ' + who_to_greet(someone))
TypeError: must be str, not int

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "greetings.py", line 14, in <module>
    greet_many(['Chad', 'Dan', 1])
  File "greetings.py", line 12, in greet_many
    print('hi, ' + person)
TypeError: must be str, not int

Remarquez la ligne en surbrillance commençant par «+ pendant la manipulation +» dans la sortie ci-dessus. Entre tous les retraits, vous verrez cette ligne. Son message est très clair, alors que votre code essayait de gérer l’exception précédente, une autre exception a été déclenchée.

*Remarque* : La fonction Python d'afficher les traces d'exceptions précédentes a été ajoutée dans Python 3. Dans Python 2, vous n'obtiendrez que le traceback de la dernière exception.

Vous avez déjà vu l’exception précédente, lorsque vous avez appelé + saluer () + avec un entier. Puisque nous avons ajouté un + 1 + à la liste des personnes à saluer, nous pouvons nous attendre au même résultat. Cependant, la fonction + greet_many () + encapsule l’appel + greet () + dans un bloc + try + et + except + +. Juste au cas où + Message de bienvenue () + entraînerait une exception, + Message de bienvenue () + souhaite imprimer un message d’accueil par défaut.

La partie pertinente de + salutations.py + est répétée ici:

def greet_many(people):
    for person in people:
        try:
            greet(person)
        except Exception:
            print('hi, ' + person)

Ainsi, lorsque + Message de bienvenue () + produit + Erreur de type + en raison d’une entrée de nombre entier incorrecte, + Message de bienvenue () + gère cette exception et tente d’imprimer un message de bienvenue simple. Ici, le code aboutit à une autre exception similaire. Il essaie toujours d’ajouter une chaîne et un entier.

La visualisation de toutes les sorties de traceback peut vous aider à voir quelle pourrait être la véritable cause d’une exception. Parfois, lorsque vous voyez l’exception finale déclenchée et son traçage résultant, vous ne pouvez toujours pas voir ce qui ne va pas. Dans ces cas, passer aux exceptions précédentes vous donne généralement une meilleure idée de la cause première.

Quelles sont les traces courantes en Python?

Savoir lire un traceback Python lorsque votre programme lève une exception peut être très utile lorsque vous programmez, mais connaître certains des retraits les plus courants peut également accélérer votre processus.

Voici quelques exceptions courantes que vous pourriez rencontrer, les raisons pour lesquelles elles sont soulevées et ce qu’elles signifient, ainsi que les informations que vous pouvez trouver dans leurs retraits.

+ AttributeError +

Le + AttributeError + est déclenché lorsque vous essayez d’accéder à un attribut sur un objet qui n’a pas cet attribut défini. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsqu’une référence d’attribut ou une affectation échoue. (Source) _

Voici un exemple de + AttributeError + levée:

>>>

>>> an_int = 1
>>> an_int.an_attribute
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'an_attribute'

La ligne de message d’erreur pour un + AttributeError + vous indique que le type d’objet spécifique, + int + dans ce cas, n’a pas accès à l’attribut, + an_attribute + dans ce cas. Voir + AttributeError + dans la ligne de message d’erreur peut vous aider à identifier rapidement l’attribut auquel vous avez tenté d’accéder et où aller pour le réparer.

La plupart du temps, l’obtention de cette exception indique que vous travaillez probablement avec un objet qui n’est pas du type que vous attendiez:

>>>

>>> a_list = (1, 2)
>>> a_list.append(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'

Dans l’exemple ci-dessus, vous pouvez vous attendre à ce que + a_list + soit de type + list +, qui a une méthode appelée + .append () + ". Lorsque vous recevez l’exception `+ AttributeError + et voyez qu’elle a été déclenchée lorsque vous essayez d’appeler + .append () +, cela vous indique que vous ne traitez probablement pas avec le type d’objet que vous attendiez.

Souvent, cela se produit lorsque vous attendez qu’un objet soit renvoyé à partir d’un appel de fonction ou de méthode pour être d’un type spécifique et que vous vous retrouvez avec un objet de type + None +. Dans ce cas, la ligne de message d’erreur indiquera `+ AttributeError: l’objet 'NoneType' n’a pas d’attribut 'append' + '.

+ ImportError +

Le + ImportError + est levé quand quelque chose ne va pas avec une instruction d’importation. Vous obtiendrez cette exception, ou sa sous-classe + ModuleNotFoundError +, si le module que vous essayez d’importer est introuvable ou si vous essayez d’importer quelque chose d’un module qui n’existe pas dans le module. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsque l’instruction d’importation rencontre des problèmes lors de la tentative de chargement d’un module. Également levé lorsque le «de la liste» dans «+ de …​ import + `a un nom introuvable. (Source) _

Voici un exemple de levée de + ImportError + et + ModuleNotFoundError +:

>>>

>>> import asdf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'asdf'
>>> from collections import asdf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'asdf'

Dans l’exemple ci-dessus, vous pouvez voir que la tentative d’importation d’un module qui n’existe pas, + asdf +, entraîne ` + ModuleNotFoundError + `. Lorsque vous essayez d’importer quelque chose qui n’existe pas, `+ asdf +, à partir d’un module qui existe, + collections +, cela se traduit par un + ImportError +. Les lignes de message d’erreur au bas des traces vous indiquent quelle chose n’a pas pu être importée, + asdf + dans les deux cas.

+ IndexError +

Le + IndexError + est levé lorsque vous essayez de récupérer un index d’une séquence, comme un + list + ou un + tuple +, et l’index ne se trouve pas dans la séquence. La documentation Python définit le moment où cette exception est déclenchée:

_ Augmenté lorsqu’un indice de séquence est hors de portée. (Source) _

Voici un exemple qui déclenche le + IndexError +:

>>>

>>> a_list = ['a', 'b']
>>> a_list[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

La ligne de message d’erreur pour un + IndexError + ne vous donne pas d’excellentes informations. Vous pouvez voir que vous avez une référence de séquence qui est «+ hors plage » et quel est le type de la séquence, une « liste +» dans ce cas. Ces informations, combinées avec le reste du traçage, sont généralement suffisantes pour vous aider à identifier rapidement comment résoudre le problème.

+ KeyError +

Semblable au + IndexError +, le + KeyError + est levé lorsque vous essayez d’accéder à une clé qui n’est pas dans le mappage, généralement un + dict + '. Considérez cela comme le `+ IndexError + mais pour dictionaries. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsqu’une clé de mappage (dictionnaire) n’est pas trouvée dans l’ensemble de clés existantes. (Source) _

Voici un exemple de la levée de + KeyError +:

>>>

>>> a_dict['b']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'b'

La ligne de message d’erreur pour un + KeyError + vous donne la clé qui n’a pas pu être trouvée. Ce n’est pas grand-chose, mais, combiné avec le reste de la trace, c’est généralement suffisant pour résoudre le problème.

Pour un examen approfondi de + KeyError +, jetez un œil à Python KeyError Exceptions et comment les gérer.

+ NameError +

Le + NameError + est déclenché lorsque vous avez référencé une variable, un module, une classe, une fonction ou un autre nom qui n’a pas été défini dans votre code. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsqu’un nom local ou global est introuvable. (Source) _

Dans le code ci-dessous, + accueillir () + prend un paramètre + personne +. Mais dans la fonction elle-même, ce paramètre a été mal orthographié en + persn +:

>>>

>>> def greet(person):
...     print(f'Hello, {persn}')
>>> greet('World')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greet
NameError: name 'persn' is not defined

La ligne de message d’erreur de la trace + NameError + vous donne le nom qui manque. Dans l’exemple ci-dessus, il s’agit d’une variable ou d’un paramètre mal orthographié de la fonction transmise.

Un + NameError + sera également levé si c’est le paramètre que vous avez mal orthographié:

>>>

>>> def greet(persn):
...     print(f'Hello, {person}')
>>> greet('World')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greet
NameError: name 'person' is not defined

Ici, il peut sembler que vous n’ayez rien fait de mal. La dernière ligne qui a été exécutée et référencée dans le retraçage semble bonne. Si vous vous trouvez dans cette situation, alors la chose à faire est de chercher dans votre code où la variable + personne + est utilisée et définie. Ici, vous pouvez rapidement voir que le nom du paramètre a été mal orthographié.

+ SyntaxError +

Le + SyntaxError + est levé lorsque vous avez une syntaxe Python incorrecte dans votre code. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsque l’analyseur rencontre une erreur de syntaxe. (Source) _

Ci-dessous, le problème est un deux-points manquant qui devrait se trouver à la fin de la ligne de définition de fonction. Dans le Python REPL, cette erreur de syntaxe est déclenchée immédiatement après avoir appuyé sur Entrée:

>>>

>>> def greet(person)
  File "<stdin>", line 1
    def greet(person)
                    ^
SyntaxError: invalid syntax

La ligne de message d’erreur du + SyntaxError + vous indique seulement qu’il y a eu un problème avec la syntaxe de votre code. En regardant dans les lignes ci-dessus, vous obtenez la ligne avec le problème et généralement un + ^ + (caret) pointant vers le problème. Ici, les deux points sont absents de l’instruction + def + de la fonction.

De plus, avec + SyntaxError + tracebacks, la première ligne régulière + Traceback (dernier appel le plus récent): + est manquante. C’est parce que le + SyntaxError + est levé lorsque Python tente d’analyser votre code, et les lignes ne sont pas réellement exécutées.

+ TypeError +

Le + TypeError + est levé lorsque votre code tente de faire quelque chose avec un objet qui ne peut pas faire cette chose, comme essayer d’ajouter une chaîne à un entier ou appeler + len () + sur un objet où sa longueur n’est pas défini. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsqu’une opération ou une fonction est appliquée à un objet de type inapproprié. (Source) _

Voici quelques exemples de + TypeError + levées:

>>>

>>> 1 + '1'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> '1' + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must be str, not int
>>> len(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()

Tous les exemples ci-dessus de génération d’un + TypeError + entraînent une ligne de message d’erreur avec différents messages. Chacun d’eux fait un très bon travail pour vous informer de ce qui ne va pas.

Les deux premiers exemples tentent d’ajouter des chaînes et des entiers ensemble. Cependant, ils sont subtilement différents:

  • Le premier essaie d’ajouter un + str + à un + int +. *Le second essaie d’ajouter un + int + à un + str +.

Les lignes de message d’erreur reflètent ces différences.

Le dernier exemple tente d’appeler + len () + sur un + int +. La ligne de message d’erreur vous indique que vous ne pouvez pas faire cela avec un + int +.

+ ValueError +

Le + ValueError + est levé lorsque la valeur de l’objet n’est pas correcte. Vous pouvez penser à cela comme un + IndexError + qui est élevé parce que la valeur de l’index n’est pas dans la plage de la séquence, seul le + ValueError + est pour un cas plus générique. La documentation Python définit le moment où cette exception est déclenchée:

_ Déclenché lorsqu’une opération ou une fonction reçoit un argument qui a le bon type mais une valeur inappropriée, et la situation n’est pas décrite par une exception plus précise telle que + IndexError +. (Source) _

Voici deux exemples de + ValueError + levées:

>>>

>>> a, b, c = [1, 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)
>>> a, b = [1, 2, 3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

La ligne de message d’erreur + ValueError + dans ces exemples vous indique exactement quel est le problème avec les valeurs:

  1. Dans le premier exemple, vous essayez de décompresser trop de valeurs. La ligne de message d’erreur vous indique même que vous vous attendiez à décompresser 3 valeurs mais que vous avez obtenu 2 valeurs.

  2. Dans le deuxième exemple, le problème est que vous obtenez trop de valeurs et pas assez de variables pour les décompresser.

Comment enregistrer un traçage?

L’obtention d’une exception et son traçage Python résultant signifie que vous devez décider quoi faire à ce sujet. La réparation de votre code est généralement la première étape, mais parfois le problème vient d’une entrée inattendue ou incorrecte. Bien qu’il soit bon de prévoir ces situations dans votre code, il est parfois également judicieux de désactiver ou de masquer l’exception en enregistrant la trace et en faisant autre chose.

Voici un exemple de code plus réel qui doit faire taire certains retraits Python. Cet exemple utilise la + demandes + bibliothèque. Vous pouvez en savoir plus à ce sujet dans Python’s Requests Library (Guide):

# urlcaller.py
import sys
import requests

response = requests.get(sys.argv[1])

print(response.status_code, response.content)

Ce code fonctionne bien. Lorsque vous exécutez ce script, en lui donnant une URL comme argument de ligne de commande, il appelle l’URL, puis imprime le code d’état HTTP et le contenu de la réponse. Cela fonctionne même si la réponse était un état d’erreur HTTP:

$ python urlcaller.py https://httpbin.org/status/200
200 b''
$ python urlcaller.py https://httpbin.org/status/500
500 b''

Cependant, parfois l’URL que votre script est donné à récupérer n’existe pas ou le serveur hôte est en panne. Dans ces cas, ce script lèvera désormais une exception + ConnectionError + non capturée et affichera une trace:

$ python urlcaller.py http://thisurlprobablydoesntexist.com
...
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "urlcaller.py", line 5, in <module>
    response = requests.get(sys.argv[1])
  File "/path/to/requests/api.py", line 75, in get
    return request('get', url, params=params,* *kwargs)
  File "/path/to/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/path/to/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/path/to/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/path/to/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url:/(Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known',))

Le traceback Python ici peut être très long avec de nombreuses autres exceptions levées et finalement entraînant le + ConnectionError + levé par + requêtes + lui-même. Si vous remontez la trace des exceptions finales, vous pouvez voir que le problème a commencé dans notre code avec la ligne 5 de + urlcaller.py +.

Si vous encapsulez la ligne incriminée dans un https://realpython.com/python-exceptions/#the-try-and-except-block-handling-exceptions [+ try + et `+ except + 'block], attraper le code approprié exception permettra à votre script de continuer à fonctionner avec plus d’entrées:

# urlcaller.py
...
try:
    response = requests.get(sys.argv[1])
except requests.exceptions.ConnectionError:
    print(-1, 'Connection Error')
else:
    print(response.status_code, response.content)

Le code ci-dessus utilise une clause + else + avec les blocs + try + et + except + + '. Si vous n’êtes pas familier avec cette fonctionnalité de Python, consultez la section sur la clause `+ else + dans Python Exceptions: An Introduction.

Maintenant, lorsque vous exécutez le script avec une URL qui entraînera une augmentation de + ConnectionError +, vous obtiendrez un + -1 + pour le code d’état et le contenu `+ Erreur de connexion + ':

$ python urlcaller.py http://thisurlprobablydoesntexist.com
-1 Connection Error

Cela fonctionne très bien. Cependant, dans la plupart des systèmes réels, vous ne voulez pas simplement faire taire l’exception et le traçage résultant, mais vous voulez enregistrer le traçage. La journalisation des traces vous permet d’avoir une meilleure compréhension de ce qui ne va pas dans vos programmes.

*Remarque:* Pour en savoir plus sur le système de journalisation de Python, consultez https://realpython.com/python-logging/[Logging en Python].

Vous pouvez enregistrer le traceback dans le script en important le package + logging +, en obtenant un enregistreur et en appelant + .exception () + sur cet enregistreur dans la partie + except + 'du + try + et + sauf + `bloc. Votre script final devrait ressembler au code suivant:

# urlcaller.py
import logging
import sys
import requests

logger = logging.getLogger(__name__)

try:
    response = requests.get(sys.argv[1])
except requests.exceptions.ConnectionError as e:
    logger.exception()
    print(-1, 'Connection Error')
else:
    print(response.status_code, response.content)

Maintenant, lorsque vous exécutez le script pour une URL problématique, il affichera les attendus + -1 + et + Erreur de connexion +, mais il enregistrera également le traceback:

$ python urlcaller.py http://thisurlprobablydoesntexist.com
...
  File "/path/to/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url:/(Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known',))
-1 Connection Error

Par défaut, Python enverra des messages de journal à l’erreur standard (+ stderr +). Il semble que nous n’ayons pas du tout supprimé la sortie de traçage. Cependant, si vous l’appelez à nouveau lors de la redirection du + stderr +, vous pouvez voir que le système de journalisation fonctionne et nous pouvons enregistrer nos journaux pour plus tard:

$ python urlcaller.py http://thisurlprobablydoesntexist.com 2> my-logs.log
-1 Connection Error

Conclusion

La traceback Python contient d’excellentes informations qui peuvent vous aider à trouver ce qui ne va pas dans votre code Python. Ces traces peuvent sembler un peu intimidantes, mais une fois que vous les décomposez pour voir ce qu’elles essaient de vous montrer, elles peuvent être très utiles. En parcourant quelques retraits ligne par ligne, vous comprendrez mieux les informations qu’ils contiennent et vous en tirerez le meilleur parti.

Obtenir une sortie de traceback Python lorsque vous exécutez votre code est une opportunité d’améliorer votre code. C’est une façon pour Python de vous aider.

Maintenant que vous savez lire un traceback Python, vous pouvez en apprendre davantage sur certains outils et techniques pour diagnostiquer les problèmes dont votre sortie de traceback vous parle. Le https://docs.python.org/3.7/library/traceback.html [module + traceback + ] intégré de Python peut être utilisé pour travailler avec et inspecter les traces. Le module `+ traceback + peut être utile lorsque vous avez besoin de tirer le meilleur parti de la sortie traceback. Il serait également utile d’en savoir plus sur certaines techniques pour le débogage de votre code Python.