When I catch an exception, how do I get the type, file, and line number?

312,891

Solution 1

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)

Solution 2

Simplest form that worked for me.

import traceback

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

Output

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

Solution 3

Source (Py v2.7.3) for traceback.format_exception() and called/related functions helps greatly. Embarrassingly, I always forget to Read the Source. I only did so for this after searching for similar details in vain. A simple question, "How to recreate the same output as Python for an exception, with all the same details?" This would get anybody 90+% to whatever they're looking for. Frustrated, I came up with this example. I hope it helps others. (It sure helped me! ;-)

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

In specific answer to this query:

sys.exc_info()[0].__name__, os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename), sys.exc_info()[2].tb_lineno

Solution 4

Here is an example of showing the line number of where exception takes place.

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

Solution 5

Without any imports, but also incompatible with imported modules:

try:
    raise TypeError("Hello, World!")  # line 2
except Exception as e:
    print(
        type(e).__name__,          # TypeError
        __file__,                  # /tmp/example.py
        e.__traceback__.tb_lineno  # 2
    )

$ python3 /tmp/example.py
TypeError /tmp/example.py 2

To reiterate, this does not work across imports or modules, so if you do import X; try: X.example(); then the filename and line number will point to the line containing X.example() instead of the line where it went wrong within X.example(). If anyone knows how to easily get the file name and line number from the last stack trace line (I expected something like e[-1].filename, but no such luck), please improve this answer.

Share:
312,891
Claudiu
Author by

Claudiu

Graduated from Brown University. E-mail: [email protected]

Updated on July 16, 2022

Comments

  • Claudiu
    Claudiu almost 2 years

    Catching an exception that would print like this:

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

    I want to format it into:

    ZeroDivisonError, tmp.py, 1
    
  • Daniel Pryden
    Daniel Pryden almost 15 years
    You should be careful about unpacking sys.exc_info() into local variables, since if you get an exception in the except handler, the local vars could get kept in a circular reference and not GC'd. Best practice is to always just use slices off of sys.exc_info() instead. Or use other modules like traceback, as other posters have suggested.
  • Reut
    Reut over 14 years
    is tb just exc_tb? and os.path.split(blabla)[1] is os.path.basename(balbal)
  • Basj
    Basj about 10 years
    With this code, I get (when try: 1/0) : <type 'exceptions.ZeroDivisionError'> integer division or modulo by zero. How to have ZeroDivisionError: integer division or modulo by zero instead ?
  • Johannes Overmann
    Johannes Overmann about 10 years
    @Basj: With sys.exc_info()[0].__name__ you get the plain name of the type.
  • user
    user almost 10 years
    @DanielPryden Python docs are also using the same unpacking method docs.python.org/2/library/traceback.html#traceback-examples
  • Ivan Bilan
    Ivan Bilan about 8 years
    I am importing a Class from a different file, when I use this solution the error points to the line in the current file on which the function from the class is called. The actual error occurs in a class file but this solution only shows the error in a current file. Any way to dig deeper?
  • user2357112
    user2357112 about 8 years
    @RobM: Yes, it's thread-safe. sys.exc_info() was introduced to deal with thread-safety problems in the previous API. Its output is specific to both the current thread and the current stack frame.
  • cs_alumnus
    cs_alumnus almost 6 years
    while not exactly the format the op wanted, this is the simplest and most robust solution
  • saurabh
    saurabh over 5 years
    use logging.exception(e) if using logging lib
  • jouell
    jouell over 5 years
    what is robust about it?
  • user2682863
    user2682863 about 5 years
    change 'message' : exc_value.message to 'message' : str(exc_value) for py3
  • Adam Lenda
    Adam Lenda about 5 years
    an excellent demonstration of why everything simple is harder in python....
  • Rishav
    Rishav over 4 years
    @jouell Hey, I like to use fancy words too sometimes :)
  • Himanshu Gautam
    Himanshu Gautam almost 4 years
    Clean & effective. Thanks for sharing :)
  • YNX
    YNX over 3 years
    It just more robust. High rate answer can't print the deepest stack in my program.
  • pschanely
    pschanely almost 3 years
    I think possibly e.__traceback__.tb_frame.f_code.co_filename would do the trick for the filename.
  • Cees Timmerman
    Cees Timmerman over 2 years
    What's unsafe about letting Python handle those variables like any other variables?
  • Luc
    Luc over 2 years
    FYI, copying the text instead of making a pixely (jpeg-y) screenshot of text is more searchable and useful.
  • starriet
    starriet over 2 years
    you can also use traceback.print_exc(), without print(). save some typing :)