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

Each Answer to this Q is separated by one/two green lines.

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

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)

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

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

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

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.

You could achieve this without having to import traceback:

try:
    func1()
except Exception as ex:
    trace = []
    tb = ex.__traceback__
    while tb is not None:
        trace.append({
            "filename": tb.tb_frame.f_code.co_filename,
            "name": tb.tb_frame.f_code.co_name,
            "lineno": tb.tb_lineno
        })
        tb = tb.tb_next
    print(str({
        'type': type(ex).__name__,
        'message': str(ex),
        'trace': trace
    }))

Output:

{

  'type': 'ZeroDivisionError',
  'message': 'division by zero',
  'trace': [
    {
      'filename': '/var/playground/main.py',
      'name': '<module>',
      'lineno': 16
    },
    {
      'filename': '/var/playground/main.py',
      'name': 'func1',
      'lineno': 11
    },
    {
      'filename': '/var/playground/main.py',
      'name': 'func2',
      'lineno': 7
    },
    {
      'filename': '/var/playground/my.py',
      'name': 'test',
      'lineno': 2
    }
  ]
}

This is what I used to get the file name.

__file__.__str__

To sum it, I created a page to show errors. Return this on exception.

context={
                'details':'Type of error:{}:Function name:{}:Line number:{}'.format(exc_type, fname, exc_tb.tb_lineno),
                'error_details':str(e),
                'filename':__file__.__str__,
            })

How it looks in case an exception occurs:

enter image description here


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.