try print exceptions example error catch and all python exception exception-handling try-catch traceback

print - traceback python 3



El rastreo de excepciones se oculta si no se vuelve a generar de inmediato (5)

Tengo un fragmento de código similar a esto:

import sys def func1(): func2() def func2(): raise Exception(''test error'') def main(): err = None try: func1() except: err = sys.exc_info()[1] pass # some extra processing, involving checking err details (if err is not None) # need to re-raise err so caller can do its own handling if err: raise err if __name__ == ''__main__'': main()

Cuando func2 genera una excepción, recibo el siguiente rastreo:

Traceback (most recent call last): File "err_test.py", line 25, in <module> main() File "err_test.py", line 22, in main raise err Exception: test error

Desde aquí no veo de dónde viene la excepción. El rastreo original se pierde.

¿Cómo puedo conservar el rastreo original y volver a subirlo? Quiero ver algo similar a esto:

Traceback (most recent call last): File "err_test.py", line 26, in <module> main() File "err_test.py", line 13, in main func1() File "err_test.py", line 4, in func1 func2() File "err_test.py", line 7, in func2 raise Exception(''test error'') Exception: test error


Es posible modificar y volver a lanzar una excepción:

Si no hay expresiones presentes, raise vuelve a subir la última excepción que estaba activa en el ámbito actual. Si no hay excepciones activas en el ámbito actual, se TypeError una excepción TypeError que indica que se trata de un error (si se ejecuta en IDLE, se Queue.Empty una excepción Queue.Empty su lugar).

De lo contrario, raise evalúa las expresiones para obtener tres objetos, utilizando None como el valor de las expresiones omitidas. Los primeros dos objetos se utilizan para determinar el tipo y el valor de la excepción.

Si hay un tercer objeto presente y no None , debe ser un objeto de seguimiento (consulte la sección Jerarquía de tipo estándar) y se sustituye en lugar de la ubicación actual como el lugar donde se produjo la excepción. Si el tercer objeto está presente y no un objeto de rastreo o None , se TypeError una excepción TypeError .

La forma de raise de tres expresiones es útil para volver a plantear una excepción de forma transparente en una cláusula de except , pero raise sin expresiones debe ser preferible si la excepción que se volvió a raise fue la excepción activa más reciente en el ámbito actual.

Entonces, si quiere modificar la excepción y volver a lanzarla, puede hacer esto:

try: buggy_code_which_throws_exception() except Exception as e: raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]


Puede obtener mucha información acerca de la excepción a través de sys.exc_info() junto con el módulo de traceback

prueba la siguiente extensión a tu código.

import sys import traceback def func1(): func2() def func2(): raise Exception(''test error'') def main(): try: func1() except: exc_type, exc_value, exc_traceback = sys.exc_info() # Do your verification using exc_value and exc_traceback print "*** print_exception:" traceback.print_exception(exc_type, exc_value, exc_traceback, limit=3, file=sys.stdout) if __name__ == ''__main__'': main()

Esto se imprimiría, similar a lo que quería.

*** print_exception: Traceback (most recent call last): File "err_test.py", line 14, in main func1() File "err_test.py", line 5, in func1 func2() File "err_test.py", line 8, in func2 raise Exception(''test error'') Exception: test error


Si bien la respuesta de @Jochen funciona bien en el caso simple, no es capaz de manejar casos más complejos, en los que no se está capturando y volviendo a lanzar directamente, pero por alguna razón se les da la excepción como objeto y se desea volver a tirar completamente. nuevo contexto (es decir, si necesita manejarlo en un proceso diferente).

En este caso, propongo lo siguiente:

  1. obtener el original exc_info
  2. formatee el mensaje de error original, con el seguimiento de la pila
  3. lanzar una nueva excepción con ese mensaje de error completo (incluido el seguimiento de la pila) incrustado

Antes de hacer esto, defina un nuevo tipo de excepción que volverá a lanzar más tarde ...

class ChildTaskException(Exception): pass

En el código ofensivo ...

import sys import traceback try: # do something dangerous except: error_type, error, tb = sys.exc_info() error_lines = traceback.format_exception(error_type, error, tb) error_msg = ''''.join(error_lines) # for example, if you are doing multiprocessing, you might want to send this to another process via a pipe connection.send(error_msg)

Retirarse ...

# again, a multiprocessing example of receiving that message through a pipe error_msg = pcon.recv() raise ChildTaskException(error_msg)



Un raise blanco plantea la última excepción.

# need to re-raise err so caller can do its own handling if err: raise

Si usa raise something Python no tiene forma de saber si something fue una excepción que acaba de ser capturada, o una nueva excepción con un nuevo seguimiento de pila. Es por eso que hay un raise blanco que conserva el seguimiento de la pila.

Referencia aquí