Arbitrary Stack Trace in Python

by Mahmoud on February 11, 2011

I had a need to trace a function’s call stack to identify call chain paths in some difficult-to-follow Python code that was laced with lots of magic and abstractions.

I tried stepping through ipdb, but it took forever. So, I thought to myself, why can’t I just take a stack trace and I’ll be able to get the call stack. It didn’t help that this function was apparently called multiple times from different places so when I tried raising an unhandled exception, it only helped display the stack trace for the first call to the function, not the successive ones. I also tried throwing and catching the exception, assuming that a stack trace can share some information about its call chain. That didn’t work too well because the exception masked the stack[1].

So I wrote some simple code that will do exactly that, take a stack trace and format it as if it looked like an exception traceback. Without further ado, here is, as far as I know, the only way to get an arbitrary stack trace in Python from any line of code.

    import inspect
    import traceback

    # get the currently frames' stack
    # this returns the frameobject, the filename,
    # the line number of the current line, the
    # function name, a list of lines of context from
    # the source code, and the index of the current
    # line within that list.
    stack = inspect.stack()
    # reverse the stack trace so the most recent is at the bottom of the stack
    stack.reverse()
    try:
        stack_list = []
        for s in stack:
            _, filename, line_no, func_name, code_list, index_in_code_list = s
            stack_list.append(
                (filename, line_no, func_name, code_list[index_in_code_list]))
        print ''.join(traceback.format_list(stack_list))
    finally:
        # avoid memory leak issues
        del stack

Hope this helps in your debugging adventures.

I’d love to hear if there are any other ways of doing the same thing.

[1] I should probably revisit this later to see why it didn’t work. In theory it should do what the stack trace snippet above does.

EDIT:

My original assumption was right. Using a stack trace to get the call chain is one way of doing it.

Turns out Python already does this in the traceback.print_stack function.

Thanks to @teepark for the comment!

  • http://topsy.com/blog.mahmoudimus.com/2011/02/arbitrary-stack-trace-in-python/?utm_source=pingback&utm_campaign=L2 Tweets that mention Arbitrary Stack Trace in Python — Topsy.com

    [...] This post was mentioned on Twitter by Y Combinator Newest! and HN Firehose, mahmoud abdelkader. mahmoud abdelkader said: http://bit.ly/fOpm9c #python Getting an arbitrary stack trace in python [...]

    [WORDPRESS HASHCASH] The comment’s server IP (208.74.66.43) doesn’t match the comment’s URL host IP (74.112.128.10) and so is spam.

  • http://twitter.com/teepark teepark

    kinda looks like a re-implementation of traceback.print_stack()

  • http://mahmoudimus.com/ Mahmoud Abdelkader

    Woah, didn’t know about that. Yep, and they implement it using an exception as well. That solves my question :) Thanks for that!

blog comments powered by Disqus

Previous post:

Next post: