Obtenez une description d'exception et trace de la pile qui a provoqué une exception, tout comme une chaîne

StackOverflow https://stackoverflow.com/questions/4564559

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

Était-ce utile?

La solution

Voir le module traceback, en particulier la fonction format_exc(). .

import traceback

try:
    raise ValueError
except ValueError:
    tb = traceback.format_exc()
else:
    tb = "No error"
finally:
    print tb

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 utilisant traceback.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 Promises avec Exceptions, 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)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top