Une autre réponse a déjà souligné le module traceback .
Veuillez noter qu'avec print_exc
, dans certains cas, vous n'obtiendrez pas ce que vous attendez. En Python 2.x:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
... affichera la trace de la dernière exception:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
Si vous avez vraiment besoin d'accéder à la trace d' origine, une solution consiste à mettre en cache les informations d' exception renvoyées exc_info
dans une variable locale et à l'afficher en utilisant print_exception
:
import traceback
import sys
try:
raise TypeError("Oups!")
except Exception, err:
try:
exc_info = sys.exc_info()
# do you usefull stuff here
# (potentially raising an exception)
try:
raise TypeError("Again !?!")
except:
pass
# end of useful stuff
finally:
# Display the *original* exception
traceback.print_exception(*exc_info)
del exc_info
Produire:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
Quelques pièges à cela cependant:
Du doc de sys_info
:
L'affectation de la valeur de retour traceback à une variable locale dans une fonction qui gère une exception provoquera une référence circulaire . Cela empêchera tout ce qui est référencé par une variable locale dans la même fonction ou par le traçage d'être récupéré. [...] Si vous avez besoin du traceback, assurez-vous de le supprimer après utilisation (mieux vaut avec une instruction try ... finally)
mais, du même doc:
À partir de Python 2.2, ces cycles sont automatiquement récupérés lorsque la récupération de place est activée et deviennent inaccessibles, mais cela reste plus efficace pour éviter de créer des cycles.
En revanche, en vous permettant d'accéder au traceback associé à une exception, Python 3 produit un résultat moins surprenant:
import traceback
try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_tb(err.__traceback__)
... Affichera:
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
print(sys.exc_info()[0]
impressions<class 'Exception'>
.Si vous déboguez et souhaitez simplement voir la trace de la pile actuelle, vous pouvez simplement appeler:
traceback.print_stack()
Il n'est pas nécessaire de lever manuellement une exception juste pour la rattraper.
la source
Lorsque vous ne voulez pas arrêter votre programme en cas d'erreur, vous devez gérer cette erreur avec un essai / sauf:
Pour extraire la trace complète, nous utiliserons le
traceback
module de la bibliothèque standard:Et pour créer un stacktrace décemment compliqué pour démontrer que nous obtenons le stacktrace complet:
Impression
Pour imprimer la trace complète, utilisez la
traceback.print_exc
méthode:Qui imprime:
Mieux que l'impression, la journalisation:
Cependant, une meilleure pratique consiste à configurer un enregistreur pour votre module. Il connaîtra le nom du module et pourra changer de niveau (entre autres attributs, comme les gestionnaires)
Dans ce cas, vous voudrez
logger.exception
plutôt la fonction:Quels journaux:
Ou peut-être que vous voulez juste la chaîne, auquel cas, vous voudrez
traceback.format_exc
plutôt la fonction:Quels journaux:
Conclusion
Et pour les trois options, nous voyons que nous obtenons la même sortie que lorsque nous avons une erreur:
la source
traceback.print_exc()
ne renvoie que le dernier appel: comment réussissez-vous à renvoyer plusieurs niveaux de la pile (et éventuellement tous les niveaux?)raise
chaînage nu ou d'exception, ou cachez-vous le traçage d'origine? voir stackoverflow.com/questions/2052390/…Tout d' abord, ne pas utiliser
print
s pour l' exploitation forestière, il est astable, éprouvée et bien pensé module stdlib de le faire:logging
. Vous devriez certainement l' utiliser à la place.Deuxièmement, ne soyez pas tenté de gâcher des outils sans rapport avec une approche native et simple. C'est ici:
C'est ça. Vous avez terminé maintenant.
Explication pour quiconque s'intéresse à la façon dont les choses fonctionnent sous le capot
Ce qui
log.exception
se passe réellement est juste un appel àlog.error
(c'est-à-dire, un événement de journal avec niveauERROR
) et une trace de retour d'impression ensuite.Pourquoi est-ce mieux?
Eh bien, voici quelques considérations:
Pourquoi personne ne devrait utiliser
traceback
ou appeler l'enregistreurexc_info=True
ou se salir les mainssys.exc_info
?Eh bien, juste parce que! Ils existent tous à des fins différentes. Par exemple,
traceback.print_exc
la sortie de 'est un peu différente des traces produites par l'interpréteur lui-même. Si vous l'utilisez, vous confondrez tous ceux qui liront vos journaux, ils se cogneront la tête contre eux.Passer
exc_info=True
pour consigner les appels est tout simplement inapproprié. Mais , il est utile lors de la capture d'erreurs récupérables et vous souhaitez également les enregistrer (en utilisant, par exemple, leINFO
niveau) avec des traces, car illog.exception
produit des journaux d'un seul niveau -ERROR
.Et vous devez absolument éviter de jouer avec
sys.exc_info
autant que vous le pouvez. Ce n'est tout simplement pas une interface publique, c'est une interface interne - vous pouvez l' utiliser si vous savez vraiment ce que vous faites. Il n'est pas destiné à imprimer uniquement des exceptions.la source
logging.exception()
. Pas besoin de créer d'instance de journal, sauf si vous avez des exigences particulières.En plus de la réponse de @Aaron Hall, si vous vous connectez, mais que vous ne souhaitez pas l'utiliser
logging.exception()
(car il se connecte au niveau ERREUR), vous pouvez utiliser un niveau inférieur et passerexc_info=True
. par exemplela source
Pour obtenir la trace précise de la pile, sous forme de chaîne, qui aurait été déclenchée si aucun essai / except n'était là pour la franchir, placez-le simplement dans le bloc except qui attrape l'exception incriminée.
Voici comment l'utiliser (en supposant qu'il
flaky_func
soit défini etlog
appelle votre système de journalisation préféré):C'est une bonne idée d'attraper et de relancer
KeyboardInterrupt
s, afin que vous puissiez toujours tuer le programme en utilisant Ctrl-C. La journalisation sort du cadre de la question, mais une bonne option est la journalisation . Documentation pour les modules sys et traceback .la source
desired_trace = traceback.format_exc()
. Passersys.exc_info()
l'argument n'a jamais été la bonne chose à faire, mais est silencieusement ignoré en Python 2, mais pas en Python 3 (3.6.4 de toute façon).KeyboardInterrupt
n'est pas dérivé (directement ou indirectement) deException
. (Les deux dérivent deBaseException
.) Ce moyenexcept Exception:
n'attrapera jamais unKeyboardInterrupt
, et doncexcept KeyboardInterrupt: raise
est complètement inutile.traceback.format_exc(sys.exc_info())
ne fonctionne pas pour moi avec python 3.6.10Vous devrez placer le try / except dans la boucle la plus interne où l'erreur peut se produire, c'est-à-dire
... etc
En d'autres termes, vous devrez encapsuler les instructions qui peuvent échouer dans try / sauf aussi spécifiques que possible, dans la boucle la plus interne possible.
la source
Une remarque sur les commentaires de cette réponse :
print(traceback.format_exc())
fait un meilleur travail pour moi quetraceback.print_exc()
. Avec ce dernier, lehello
est parfois étrangement "mélangé" avec le texte de traceback, comme si les deux veulent écrire en même temps sur stdout ou stderr, produisant une sortie étrange (au moins lors de la construction depuis l'intérieur d'un éditeur de texte et de la visualisation dans le Panneau "Générer les résultats").J'utilise donc:
la source
Je ne vois cela mentionné dans aucune des autres réponses. Si vous passez un objet Exception pour une raison quelconque ...
Dans Python 3.5+, vous pouvez obtenir une trace à partir d'un objet Exception à l'aide de traceback.TracebackException.from_exception () . Par exemple:
Cependant, le code ci-dessus entraîne:
Il ne s'agit que de deux niveaux de la pile, contrairement à ce qui aurait été imprimé à l'écran si l'exception avait été levée
stack_lvl_2()
et non interceptée (décommentez la# raise
ligne).Si je comprends bien, c'est parce qu'une exception enregistre uniquement le niveau actuel de la pile lorsqu'elle est augmentée,
stack_lvl_3()
dans ce cas. Au fur et à mesure qu'il est remonté dans la pile, plus de niveaux sont ajoutés à son__traceback__
. Mais nous l'avons interceptéstack_lvl_2()
, ce qui signifie que tout ce qu'il a pu enregistrer était les niveaux 3 et 2. Pour obtenir la trace complète telle qu'imprimée sur stdout, nous devons l'attraper au niveau le plus élevé (le plus bas?):Ce qui se traduit par:
Notez que l'impression de la pile est différente, les première et dernière lignes sont manquantes. Parce que c'est différent
format()
.Intercepter l'exception le plus loin possible du point où elle a été levée rend le code plus simple tout en donnant plus d'informations.
la source
Obtenez le traceback complet sous forme de chaîne à partir de l'objet d'exception avec
traceback.format_exception
Si vous n'avez que l'objet d'exception, vous pouvez obtenir le traceback sous forme de chaîne à partir de n'importe quel point du code en Python 3 avec:
Exemple complet:
Production:
Documentation: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
Voir aussi: Extraire les informations de traceback d'un objet d'exception
Testé en Python 3.7.3.
la source
Vous voulez le module traceback . Il vous permettra d'imprimer des vidages de pile comme Python le fait normalement. En particulier, la fonction print_last affichera la dernière exception et une trace de pile.
la source
Si vous avez déjà un objet Error et que vous souhaitez imprimer le tout, vous devez effectuer cet appel légèrement maladroit:
C'est vrai,
print_exception
prend trois arguments positionnels: le type de l'exception, l'objet d'exception réel et la propre propriété de traceback interne de l'exception.En python 3.5 ou version ultérieure, le
type(err)
est facultatif ... mais c'est un argument positionnel, vous devez donc toujours explicitement passer None à sa place.Je ne sais pas pourquoi tout cela n'est pas juste
traceback.print_exception(err)
. Pourquoi vous voudriez jamais imprimer une erreur, avec un retraçage autre que celui qui appartient à cette erreur, me dépasse.la source