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:
from cStringIO import StringIO
stack = inspect.stack()
# get rid of logPoint's part of the stack:
stack = stack[1:]
output = StringIO()
output.write(str(msg) + '\n')
for stackLine in stack:
frame, filename, line, funcname, lines, unknown = stackLine
# unittest.py code is a boring part of the traceback
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:
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
It looks like there's an extra parenthesis on the line, "if (filename.endswith".
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.
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)
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.
Wouldn't trace.py (the sys.settrace wrapper) be as clean a way to have solved the original problem?