Cuando encuentro una excepción, ¿cómo obtengo el tipo, el archivo y el número de línea?

251

Capturando una excepción que se imprimiría así:

Traceback (most recent call last):
  File "c:/tmp.py", line 1, in <module>
    4 / 0
ZeroDivisionError: integer division or modulo by zero

Quiero formatearlo en:

ZeroDivisonError, tmp.py, 1
Claudiu
fuente
55
Use el módulo de rastreo integrado .
Ned Deily
También puede ser útil imprimir una línea de código, donde ocurrió una excepción: consulte stackoverflow.com/questions/14519177/…
Apogentus el

Respuestas:

380
import sys, os

try:
    raise NotImplementedError("No error")
except Exception as e:
    exc_type, exc_obj, exc_tb = sys.exc_info()
    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
    print(exc_type, fname, exc_tb.tb_lineno)
Hormigas Aasma
fuente
51
Debe tener cuidado al desempaquetar sys.exc_info () en variables locales, ya que si obtiene una excepción en el controlador excepto, los vars locales podrían mantenerse en una referencia circular y no GC'd. La mejor práctica es usar siempre cortes de sys.exc_info () en su lugar. O utilice otros módulos como el rastreo, como han sugerido otros carteles.
Daniel Pryden
1
es tb solo exc_tb? y os.path.split (blabla) [1] es os.path.basename (balbal)
sunqiang el
44
@Basj: Con sys.exc_info () [0] .__ name__ obtienes el nombre simple del tipo.
Johannes Overmann
55
Los documentos de @DanielPryden Python también están utilizando el mismo método de desempaquetado docs.python.org/2/library/traceback.html#traceback-examples
usuario del
3
@RobM: Sí, es seguro para subprocesos. sys.exc_info()se introdujo para tratar problemas de seguridad de subprocesos en la API anterior. Su salida es específica tanto para el subproceso actual como para el marco de pila actual.
user2357112 es compatible con Monica el
125

La forma más simple que funcionó para mí.

import traceback

try:
    print(4/0)
except ZeroDivisionError:
    print(traceback.format_exc())

Salida

Traceback (most recent call last):
  File "/path/to/file.py", line 51, in <module>
    print(4/0)
ZeroDivisionError: division by zero

Process finished with exit code 0
nu everest
fuente
77
Aunque no es exactamente el formato que el operador quería, esta es la solución más simple y robusta
cs_alumnus
55
¿Qué tiene de robusto?
jouell
1
@jouell Hola, a veces también me gusta usar palabras elegantes :)
Rishav
Limpio y efectivo. Gracias por compartir :)
Himanshu Gautam
49

Source (Py v2.7.3) para traceback.format_exception () y llamadas / funciones relacionadas ayuda mucho. Vergonzosamente, siempre me olvido de leer la fuente . Solo lo hice para esto después de buscar detalles similares en vano. Una pregunta simple, "¿Cómo recrear la misma salida que Python para una excepción, con todos los mismos detalles?" Esto llevaría a cualquiera más del 90% a lo que sea que estén buscando. Frustrado, se me ocurrió este ejemplo. Espero que ayude a los demás. (¡Seguro que me ayudó! ;-)

import sys, traceback

traceback_template = '''Traceback (most recent call last):
  File "%(filename)s", line %(lineno)s, in %(name)s
%(type)s: %(message)s\n''' # Skipping the "actual line" item

# Also note: we don't walk all the way through the frame stack in this example
# see hg.python.org/cpython/file/8dffb76faacc/Lib/traceback.py#l280
# (Imagine if the 1/0, below, were replaced by a call to test() which did 1/0.)

try:
    1/0
except:
    # http://docs.python.org/2/library/sys.html#sys.exc_info
    exc_type, exc_value, exc_traceback = sys.exc_info() # most recent (if any) by default

    '''
    Reason this _can_ be bad: If an (unhandled) exception happens AFTER this,
    or if we do not delete the labels on (not much) older versions of Py, the
    reference we created can linger.

    traceback.format_exc/print_exc do this very thing, BUT note this creates a
    temp scope within the function.
    '''

    traceback_details = {
                         'filename': exc_traceback.tb_frame.f_code.co_filename,
                         'lineno'  : exc_traceback.tb_lineno,
                         'name'    : exc_traceback.tb_frame.f_code.co_name,
                         'type'    : exc_type.__name__,
                         'message' : exc_value.message, # or see traceback._some_str()
                        }

    del(exc_type, exc_value, exc_traceback) # So we don't leave our local labels/objects dangling
    # This still isn't "completely safe", though!
    # "Best (recommended) practice: replace all exc_type, exc_value, exc_traceback
    # with sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

    print
    print traceback.format_exc()
    print
    print traceback_template % traceback_details
    print

En respuesta específica a esta consulta:

sys.exc_info()[0].__name__, os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename), sys.exc_info()[2].tb_lineno
pitonaria
fuente
1
cambiar 'message' : exc_value.messagea 'message' : str(exc_value)para py3
user2682863
34

Aquí hay un ejemplo de mostrar el número de línea de dónde tiene lugar la excepción.

import sys
try:
    print(5/0)
except Exception as e:
    print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)

print('And the rest of program continues')
Stryker
fuente