Obtenez une description d'exception et trace de la pile qui a provoqué une exception, tout comme une chaîne
-
14-10-2019 - |
Question
J'ai vu beaucoup de messages sur la trace de la pile et les exceptions en Python. Mais ne l'ont pas trouvé ce que j'ai besoin.
J'ai un morceau de code Python 2.7 qui peut soulever une exception. Je voudrais attraper et lui attribuer un string sa description complète et la trace de la pile qui a causé l'erreur (simplement tout ce que nous utilisons pour voir sur la console). J'ai besoin cette chaîne pour l'imprimer sur une zone de texte dans l'interface graphique.
Quelque chose comme ceci:
try:
method_that_can_raise_an_exception(params)
except Exception as e:
print_to_textbox(complete_exception_description(e))
Le problème est: quelle est la fonction complete_exception_description
Autres conseils
Créons un stacktrace décemment compliqué, afin de démontrer que nous obtenons la pleine stacktrace:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
Connexion plein stacktrace
Une meilleure pratique est d'avoir un enregistreur mis en place pour votre module. Il saura le nom du module et être en mesure de modifier les niveaux (entre autres attributs, tels que les gestionnaires)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
Et nous pouvons utiliser cet enregistreur pour obtenir l'erreur:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
Quels sont les journaux:
ERROR:__main__:something bad happened!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Et nous obtenons la même sortie que lorsque nous avons une erreur:
>>> do_something_that_might_error()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
Obtenir juste la chaîne
Si vous voulez vraiment que la chaîne, utilisez la fonction traceback.format_exc
à la place, ce qui démontre la connexion de la chaîne ici:
import traceback
try:
do_something_that_might_error()
except Exception as error:
just_the_string = traceback.format_exc()
logger.debug(just_the_string)
Quels sont les journaux:
DEBUG:__main__:Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
>>> import sys
>>> import traceback
>>> try:
... 5 / 0
... except ZeroDivisionError as e:
... type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
[' File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
Vous utilisez sys.exc_info () pour collecter les informations et les fonctions du module traceback
pour le formater.
quelques exemples pour le formater.
La chaîne d'exception tout est à:
>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', ' File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']
Avec Python 3, le code suivant formate un objet Exception
exactement comme on obtiendrait en utilisant traceback.format_exc()
:
import traceback
try:
method_that_can_raise_an_exception(params)
except Exception as ex:
print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))
L'avantage étant que seul l'objet Exception
est nécessaire (grâce à l'attribut __traceback__
enregistré), et peut donc être plus facilement passé comme argument à une autre fonction de traitement ultérieur.
Pour ceux qui utilisent Python-3
Utilisation de module de traceback
et une exception.__traceback__
peut extraire de la pile trace comme suit:
- saisir le courant stack-trace en utilisant
traceback.extract_stack()
- enlever les trois derniers éléments (comme ceux qui sont entrées dans la pile qui m'a à ma fonction de débogage)
- append le
__traceback__
de l'objet d'exception en utilisanttraceback.extract_tb()
- formater la chose en utilisant
traceback.format_list()
import traceback
def exception_to_string(excp):
stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__) # add limit=??
pretty = traceback.format_list(stack)
return ''.join(pretty) + '\n {} {}'.format(excp.__class__,excp)
Une démonstration simple:
def foo():
try:
something_invalid()
except Exception as e:
print(exception_to_string(e))
def bar():
return foo()
Nous obtenons la sortie suivante lorsque nous appelons bar()
:
File "./test.py", line 57, in <module>
bar()
File "./test.py", line 55, in bar
return foo()
File "./test.py", line 50, in foo
something_invalid()
<class 'NameError'> name 'something_invalid' is not defined
Vous pourriez également envisager d'utiliser le module Python intégré, cgitb , pour obtenir certains vraiment bon, les informations d'exception bien formaté, y compris les valeurs des variables locales, le contexte de code source, les paramètres de la fonction etc ..
Par exemple, pour ce code ...
import cgitb
cgitb.enable(format='text')
def func2(a, divisor):
return a / divisor
def func1(a, b):
c = b - 5
return func2(a, c)
func1(1, 5)
nous obtenons cette sortie d'exception ...
ZeroDivisionError
Python 3.4.2: C:\tools\python\python.exe
Tue Sep 22 15:29:33 2015
A problem occurred in a Python script. Here is the sequence of
function calls leading up to the error, in the order they occurred.
c:\TEMP\cgittest2.py in <module>()
7 def func1(a, b):
8 c = b - 5
9 return func2(a, c)
10
11 func1(1, 5)
func1 = <function func1>
c:\TEMP\cgittest2.py in func1(a=1, b=5)
7 def func1(a, b):
8 c = b - 5
9 return func2(a, c)
10
11 func1(1, 5)
global func2 = <function func2>
a = 1
c = 0
c:\TEMP\cgittest2.py in func2(a=1, divisor=0)
3
4 def func2(a, divisor):
5 return a / divisor
6
7 def func1(a, b):
a = 1
divisor = 0
ZeroDivisionError: division by zero
__cause__ = None
__class__ = <class 'ZeroDivisionError'>
__context__ = None
__delattr__ = <method-wrapper '__delattr__' of ZeroDivisionError object>
__dict__ = {}
__dir__ = <built-in method __dir__ of ZeroDivisionError object>
__doc__ = 'Second argument to a division or modulo operation was zero.'
__eq__ = <method-wrapper '__eq__' of ZeroDivisionError object>
__format__ = <built-in method __format__ of ZeroDivisionError object>
__ge__ = <method-wrapper '__ge__' of ZeroDivisionError object>
__getattribute__ = <method-wrapper '__getattribute__' of ZeroDivisionError object>
__gt__ = <method-wrapper '__gt__' of ZeroDivisionError object>
__hash__ = <method-wrapper '__hash__' of ZeroDivisionError object>
__init__ = <method-wrapper '__init__' of ZeroDivisionError object>
__le__ = <method-wrapper '__le__' of ZeroDivisionError object>
__lt__ = <method-wrapper '__lt__' of ZeroDivisionError object>
__ne__ = <method-wrapper '__ne__' of ZeroDivisionError object>
__new__ = <built-in method __new__ of type object>
__reduce__ = <built-in method __reduce__ of ZeroDivisionError object>
__reduce_ex__ = <built-in method __reduce_ex__ of ZeroDivisionError object>
__repr__ = <method-wrapper '__repr__' of ZeroDivisionError object>
__setattr__ = <method-wrapper '__setattr__' of ZeroDivisionError object>
__setstate__ = <built-in method __setstate__ of ZeroDivisionError object>
__sizeof__ = <built-in method __sizeof__ of ZeroDivisionError object>
__str__ = <method-wrapper '__str__' of ZeroDivisionError object>
__subclasshook__ = <built-in method __subclasshook__ of type object>
__suppress_context__ = False
__traceback__ = <traceback object>
args = ('division by zero',)
with_traceback = <built-in method with_traceback of ZeroDivisionError object>
The above is a description of an error in a Python program. Here is
the original traceback:
Traceback (most recent call last):
File "cgittest2.py", line 11, in <module>
func1(1, 5)
File "cgittest2.py", line 9, in func1
return func2(a, c)
File "cgittest2.py", line 5, in func2
return a / divisor
ZeroDivisionError: division by zero
Si vous souhaitez obtenir les mêmes informations données lorsqu'une exception est pas gérée que vous pouvez faire quelque chose comme ça. Faites import traceback
puis:
try:
...
except Exception as e:
print(traceback.print_tb(e.__traceback__))
J'utilise Python 3.7.
mes 2 cents:
import sys, traceback
try:
...
except Exception, e:
T, V, TB = sys.exc_info()
print ''.join(traceback.format_exception(T,V,TB))
Je défini ci-dessous classe d'aide:
import traceback
class TracedExeptions(object):
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, etype, value, tb):
if value :
if not hasattr(value, 'traceString'):
value.traceString = "\n".join(traceback.format_exception(etype, value, tb))
return False
return True
Ce que je peux ensuite utiliser comme ceci:
with TracedExeptions():
#some-code-which-might-throw-any-exception
Et plus tard peut consommer comme ceci:
def log_err(ex):
if hasattr(ex, 'traceString'):
print("ERROR:{}".format(ex.traceString));
else:
print("ERROR:{}".format(ex));
(Contexte: Je frustraded à cause de l'utilisation Promise
s avec Exception
s, qui passe malheureusement des exceptions soulevées dans un endroit à un gestionnaire on_rejected dans un autre endroit, et il est donc difficile d'obtenir le retraçage de l'emplacement d'origine)