Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I step to use the python debugger to break at every function call?

I want to closely monitor the chain of function calls which are called from a certain function.

import pdb; pdb.set_trace()
res = api.InsertVideoEntry(video_entry, video)

I'm looking for a way to easily see that api.insertVideoEntry(video_entry, video) calls foo() which calls bar() which calls baz(),

Here's a really crude diagram to show what I mean. I don't need it in this form, but this is the kind kind of information I'm looking for.

api.insertVideoEntry()
    foo()
        bar()
            baz()
            baz2()
        log()
    finish()
like image 396
sente Avatar asked Oct 08 '22 03:10

sente


1 Answers

This was an interesting learning experience to write up. Maybe you can use the code shown here? This demonstration should give you an idea of the type of output you can expect when using trace.

# Functions to trace
# ==================

def baz():
    pass

def baz2():
    pass

def bar():
    baz()
    baz2()

def log():
    pass

def foo():
    bar()
    log()

def finish():
    pass

def insertVideoEntry():
    foo()
    finish()

# Names to trace
# ==============

names = list(locals())

# Machinery for tracing
# =====================

import os
import sys

def trace(start, *names):
    def tracefunc(frame, event, arg):
        if event == 'call':
            code = frame.f_code
            name = code.co_name
            if name in names:
                level = -start
                while frame:
                    frame = frame.f_back
                    level += 1
                print('{}{}.{}()'.format(
                    '    ' * level,
                    os.path.splitext(os.path.basename(code.co_filename))[0],
                    name))
                return tracefunc
    sys.settrace(tracefunc)

# Demonstration of tracing
# ========================

trace(2, *names)

insertVideoEntry()

If you are interested in a recursive demo, you might like this variation with a called arguments readout:

import os
import sys

def main(discs):
    a, b, c = list(range(discs, 0, -1)), [], []
    line = '-' * len(repr(a))
    print(a, b, c, sep='\n')
    for source, destination in towers_of_hanoi(discs, a, b, c):
        destination.append(source.pop())
        print(line, a, b, c, sep='\n')

def towers_of_hanoi(count, source, via, destination):
    if count > 0:
        count -= 1
        yield from towers_of_hanoi(count, source, destination, via)
        yield source, destination
        yield from towers_of_hanoi(count, via, source, destination)

def trace(start, *names):
    def tracefunc(frame, event, arg):
        if event == 'call':
            code = frame.f_code
            name = code.co_name
            if name in names:
                level = -start
                args = ', '.join(repr(frame.f_locals[name]) for name in
                                 code.co_varnames[:code.co_argcount])
                while frame:
                    frame = frame.f_back
                    level += 1
                print('{}{}.{}({})'.format(
                    ' ' * (level * 4),
                    os.path.splitext(os.path.basename(code.co_filename))[0],
                    name, args))
                return tracefunc
    sys.settrace(tracefunc)

if __name__ == '__main__':
    trace(3, 'main', 'towers_of_hanoi')
    main(3)
like image 194
Noctis Skytower Avatar answered Oct 10 '22 21:10

Noctis Skytower