Code


Version 1 (modified by anonymous, 8 years ago) (diff)

--

Inspect call stack

While playing arround with djangos internals I have found the following decorator usefull. It shows the call stack up to the decorated function:

def who_called_me(show_filename=False, out=None, indent=' '):
    def _wrapper(fn):
        def _inner_wrapper(*args, **kwargs):
            import sys
            import inspect
            output = out or sys.stdout
            assert hasattr(output, 'write'), \
                'argument \'out\' of function \'who_called_me\' must have a write method'
            index = 0
            stack = inspect.stack()
            stack.reverse()
            # remove ourself from the stack list
            stack.pop()
            for record in stack:
                frame = record[0]
                line = frame.f_lineno
                func_name = frame.f_code.co_name
                if show_filename:
                    descr = frame.f_code.co_filename
                else:
                    descr = frame.f_globals["__name__"]
                print >>output, '%s%s@%s:%d' % (indent*index, descr, func_name, line)
                # to be safe explicitly delete the stack frame reference
                # @see http://docs.python.org/lib/inspect-stack.html
                del frame
                index += 1
            del stack
            if hasattr(output, 'flush'):
                output.flush()
            return fn(*args, **kwargs)
        return _inner_wrapper
    return _wrapper

Usage Examples:

@who_called_me()
def index(request):
    return render_to_response('phc/index.html', None, context_instance=RequestContext(request))

Prints this to stdout:

django.core.management@inner_run:995
 django.core.servers.basehttp@run:643
  SocketServer@serve_forever:201
   SocketServer@handle_request:222
    SocketServer@process_request:241
     SocketServer@finish_request:254
      django.core.servers.basehttp@__init__:537
       SocketServer@__init__:521
        django.core.servers.basehttp@handle:586
         django.core.servers.basehttp@run:272
          django.core.servers.basehttp@__call__:615
           django.core.handlers.wsgi@__call__:145
            django.core.handlers.base@get_response:74

Show filenames instead of module:

@who_called_me(show_filename=True)
def index(request):
    return render_to_response('phc/index.html', None, context_instance=RequestContext(request))

Prints this to stdout:

/home/me/projects/django_ma/django/core/management.py@inner_run:995
 /home/me/projects/django_ma/django/core/servers/basehttp.py@run:643
  /usr/lib/python2.4/SocketServer.py@serve_forever:201
   /usr/lib/python2.4/SocketServer.py@handle_request:222
    /usr/lib/python2.4/SocketServer.py@process_request:241
     /usr/lib/python2.4/SocketServer.py@finish_request:254
      /home/me/projects/django_ma/django/core/servers/basehttp.py@__init__:537
       /usr/lib/python2.4/SocketServer.py@__init__:521
        /home/me/projects/django_ma/django/core/servers/basehttp.py@handle:586
         /home/me/projects/django_ma/django/core/servers/basehttp.py@run:272
          /home/me/projects/django_ma/django/core/servers/basehttp.py@__call__:615
           /home/me/projects/django_ma/django/core/handlers/wsgi.py@__call__:145
            /home/me/projects/django_ma/django/core/handlers/base.py@get_response:74

Or write output to a file:

@who_called_me(out=open('/tmp/who_called_me', 'a'))
def index(request):
    return render_to_response('phc/index.html', None, context_instance=RequestContext(request))