Lorsque j'attrape une exception, comment obtenir le type, le fichier et le numéro de ligne?

252

Attraper une exception qui s'imprimerait comme ceci:

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

Je veux le formater en:

ZeroDivisonError, tmp.py, 1
Claudiu
la source
5
Utilisez le module de traçage intégré.
Ned Deily
Il peut également être utile d'imprimer une ligne de code, où une exception s'est produite: voir stackoverflow.com/questions/14519177/…
Apogentus

Réponses:

381
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)
Fourmis Aasma
la source
51
Vous devez faire attention à ne pas décompresser sys.exc_info () dans des variables locales, car si vous obtenez une exception dans le gestionnaire except, les variables locales peuvent être conservées dans une référence circulaire et non GC'd. La meilleure pratique consiste à toujours utiliser uniquement des tranches hors de sys.exc_info (). Ou utilisez d'autres modules comme traceback, comme l'ont suggéré d'autres affiches.
Daniel Pryden
1
est tb juste exc_tb? et os.path.split (blabla) [1] est os.path.basename (balbal)
sunqiang
4
@Basj: Avec sys.exc_info () [0] .__ nom__ vous obtenez le nom simple du type.
Johannes Overmann
5
@DanielPryden Les documents Python utilisent également la même méthode de décompression docs.python.org/2/library/traceback.html#traceback-examples
utilisateur
3
@RobM: Oui, c'est thread-safe. sys.exc_info()a été introduit pour traiter les problèmes de sécurité des threads dans l'API précédente. Sa sortie est spécifique à la fois au thread actuel et au cadre de pile actuel.
user2357112 prend en charge Monica
126

Forme la plus simple qui a fonctionné pour moi.

import traceback

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

Production

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
la source
7
bien que ce ne soit pas exactement le format souhaité par l'op, c'est la solution la plus simple et la plus robuste
cs_alumnus
5
qu'est-ce qui est robuste?
jouell
1
@jouell Hé, j'aime aussi utiliser des mots fantaisistes parfois :)
Rishav
Propre et efficace. Merci pour le partage :)
Himanshu Gautam
49

La source (Py v2.7.3) pour traceback.format_exception () et les fonctions appelées / associées aide grandement. Gênant, j'oublie toujours de lire la source . Je ne l'ai fait pour cela qu'après avoir cherché en vain des détails similaires. Une question simple, "Comment recréer la même sortie que Python pour une exception, avec tous les mêmes détails?" Cela permettrait à quiconque de 90% + à tout ce qu'ils recherchent. Frustré, j'ai trouvé cet exemple. J'espère que cela aide les autres. (Cela m'a bien sûr aidé! ;-)

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 réponse spécifique à cette requête:

sys.exc_info()[0].__name__, os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename), sys.exc_info()[2].tb_lineno
pythonlarry
la source
1
le changement 'message' : exc_value.messageà 'message' : str(exc_value)des PY3
user2682863
34

Voici un exemple montrant le numéro de ligne où l'exception a lieu.

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
la source