Pregunta

He visto muchas publicaciones sobre Stack Trace y excepciones en Python. Pero no he encontrado lo que necesito.

Tengo una parte del código Python 2.7 que puede plantear una excepción. Me gustaría atraparlo y asignar a un cuerda Su descripción completa y la traza de pila que causó el error (simplemente todo lo que usamos para ver en la consola). Necesito esta cadena para imprimirla en un cuadro de texto en la GUI.

Algo como esto:

try:
    method_that_can_raise_an_exception(params)
except Exception as e:
    print_to_textbox(complete_exception_description(e))

El problema es: Cuál es la función complete_exception_description?

¿Fue útil?

Solución

Ver el traceback módulo, específicamente el format_exc() función. Aquí.

import traceback

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

Otros consejos

Creemos una StackTrace decentemente complicada, para demostrar que obtenemos el StackTrace completo:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Registro de la Stacktrace completa

Una mejor práctica es tener un registrador configurado para su módulo. Conocerá el nombre del módulo y podrá cambiar los niveles (entre otros atributos, como los manejadores)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

Y podemos usar este registrador para obtener el error:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

Qué registros:

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!

Y entonces obtenemos la misma salida que cuando tenemos un error:

>>> 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!

Conseguir solo la cadena

Si realmente solo quieres la cadena, usa la traceback.format_exc Funciona en su lugar, demostrando registrar la cadena aquí:

import traceback
try:
    do_something_that_might_error()
except Exception as error:
    just_the_string = traceback.format_exc()
    logger.debug(just_the_string)

Qué registros:

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

Tu usas sys.exc_info () para recopilar la información y las funciones en el traceback módulo para formatearlo.Aquí son algunos ejemplos para formatearlo.

Toda la cadena de excepción está en:

>>> 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']

Con Python 3, el siguiente código formateará un Exception objeto exactamente como se obtendría usando 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__)))

La ventaja es que solo el Exception se necesita objeto (gracias a los grabados __traceback__ atributo) y, por lo tanto, se puede pasar más fácilmente como argumento a otra función para el procesamiento posterior.

Para aquellos que usan Python-3

Usando traceback módulo y exception.__traceback__ Uno puede extraer el ritmo de pila de la siguiente manera:

  • toma el Actual pilotear traceback.extract_stack()
  • Elimine los últimos tres elementos (ya que esas son entradas en la pila que me llevaron a mi función de depuración)
  • Agregar el __traceback__ Desde el objeto de excepción usando traceback.extract_tb()
  • formatear todo usando 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)

Una simple demostración:

def foo():
    try:
        something_invalid()
    except Exception as e:
        print(exception_to_string(e))

def bar():
    return foo()

Obtenemos la siguiente salida cuando llamamos 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

También puede considerar usar el módulo Python incorporado, CGITB, para obtener información de excepción realmente buena y bien formateada que incluye valores variables locales, contexto del código fuente, parámetros de función, etc.

Por ejemplo, para este código ...

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)

obtenemos esta salida de excepción ...

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 desea obtener la misma información dada cuando no se maneja una excepción, puede hacer algo como esto. Hacer import traceback y entonces:

try:
    ...
except Exception as e:
    print(traceback.print_tb(e.__traceback__))

Estoy usando Python 3.7.

mis 2 centavos:

import sys, traceback
try: 
  ...
except Exception, e:
  T, V, TB = sys.exc_info()
  print ''.join(traceback.format_exception(T,V,TB))

Definí la siguiente clase de ayudante:

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

Que luego puedo usar así:

with TracedExeptions():
  #some-code-which-might-throw-any-exception

Y luego puede consumirlo así:

def log_err(ex):
  if hasattr(ex, 'traceString'):
    print("ERROR:{}".format(ex.traceString));
  else:
    print("ERROR:{}".format(ex));

(Antecedentes: estaba frustrado por usar Promises junto con ExceptionS, que desafortunadamente pasa excepciones planteadas en un lugar a un controlador de On_rejected en otro lugar, y por lo tanto es difícil obtener el rastreo de la ubicación original)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top