Ian Bicking: the old part of his blog

Still Pretty Cheap Debugging Trick

After reading Uche Ogbuji's cheap debugging trick, I looked a bit more at inspect.stack(). It wasn't very hard to make a sort of ad hoc traceback, but without actually causing an exception. My particular motivation was a case where some code was being cause twice where it should only be called once. I sometimes just put assert 0 in someplace to find when it is called, but then it would catch the first correct usage and never get to the second. So I put a function call in the overly-called code, logPoint(), and I got a list of tracebacks. The code:
import inspect
from cStringIO import StringIO

def logPoint(msg=''):
    stack = inspect.stack()
    # get rid of logPoint's part of the stack:
    stack = stack[1:]
    stack.reverse()
    output = StringIO()
    if msg:
        output.write(str(msg) + '\n')
    for stackLine in stack:
        frame, filename, line, funcname, lines, unknown = stackLine
        if filename.endswith('/unittest.py'):
            # unittest.py code is a boring part of the traceback
            continue
        if filename.startswith('./'):
            filename = filename[2:]
        output.write('%s:%s in %s:\n' % (filename, line, funcname))
        output.write('  %s\n' % ''.join(lines)[:-1])
    s = output.getvalue()
    # I actually logged the result, but you could also print it:
    print s
Update: Maybe print_stack() in the traceback is an easier way to do this? The only real advantage to this way is that you can hide parts of the stack that are boring -- usually the framework, be it unittest, a web framework, the interactive interface, etc.
Created 05 Aug '04
Modified 14 Dec '04

Comments:

It looks like there's an extra parenthesis on the line, "if (filename.endswith".
# Mathieu Fenniak

Indeed; fixed.
# Ian Bicking

I wonder whether your code would be acceptable as a replacement for traceback.print_stack() - for people who don't want it to use the exception hack. Not that I've ever had a problem with that.
# Richard Jones

iRichard, If that's a really problem, why not just change traceback.print_stack() to use sys._getframe()?

(traceback.print_stack() and traceback.print_stack(sys._getframe()) gives the same output)
# Fredrik

See also http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52215 which shows how to dump the local variables from each frame as well. That makes the debugging really easy.
# Roger Binns

Wouldn't trace.py (the sys.settrace wrapper) be as clean a way to have solved the original problem?
# Mark Eichin