Python – traceback.print_exc() shows an incomplete stack trace

traceback.print_exc() shows an incomplete stack trace… here is a solution to the problem.

traceback.print_exc() shows an incomplete stack trace

The traceback module is great for catching and handling exceptions, but in the following example, it seems to catch an incomplete stack from the most recent exception.

Consider two files, one is “mymod.py”:

import sys, traceback

def func():
    try:
        otherfunc()
    except:
        raise
        #traceback.print_exc()

def otherfunc():
    raise Exception( 'fake' )

Another says “myfile.py”:

from mymod import *
func()

Run myfile.py to get:

Traceback (most recent call last):
  File "myfile.py", line 2, in <module>
    func()
  File "/Users/rrdrake/temp/mymod.py", line 5, in func
    otherfunc()
  File "/Users/rrdrake/temp/mymod.py", line 11, in otherfunc
    raise Exception( 'fake' )

Now change mymod.py to comment out “raise” and uncomment line print_exc. And then we got

Traceback (most recent call last):
  File "/Users/rrdrake/temp/mymod.py", line 5, in func
    otherfunc()
  File "/Users/rrdrake/temp/mymod.py", line 11, in otherfunc
    raise Exception( 'fake' )
Exception: fake

Note that print_exc() does not contain the myfile.py framework, while re-raising does. How do I get print_exc() to include the original call frame?

Note that if I add traceback.print_stack() in except block, it does contain the myfile.py framework, so the information seems available.

Solution

In your first case, the exception of your raise call bubbles up on top of the script. Python calls sys.excepthook(), which shows the full traceback.

In your second case, the exception is

caught and print_exc() is used to print the exception, which stops at your calling function (otherfunc() case) so you don’t get the full traceback.

You can change it using your own traceback/anomaly printing feature,
Something along these directions:

def print_full_stack(tb=None):
    if tb is None:
        tb = sys.exc_info()[2]

print 'Traceback (most recent call last):'
    for item in reversed(inspect.getouterframes(tb.tb_frame)[1:]):
        print ' File "{1}", line {2}, in {3}\n'.format(*item),
        for line in item[4]:
            print ' ' + line.lstrip(),
    for item in inspect.getinnerframes(tb):
        print ' File "{1}", line {2}, in {3}\n'.format(*item),
        for line in item[4]:
            print ' ' + line.lstrip(),

Just replace traceback.print_exc() with print_full_stack(). This function involves the Inspect module to fetch the code frame.

You can read this blog for more information: http://blog.dscpl.com.au/2015/03/generating-full-stack-traces-for.html

Note that the code in the article above has some indentation errors….

Related Problems and Solutions