Raja's Exocortex

Tracing Python

Sometimes it's useful to trace the execution of Python scripts to understand the code flow and exceptions.

# Python code execution tracing
# To start tracing call sys.settrace(trace_call) before your code.
# To stop tracing call sys.settrace(None) after your code.
# To trace a function, use the decorator @trace

import sys, os.path, inspect

def trace_line(frame, event, arg):
    if event != 'line':
        return

    filename = os.path.basename(frame.f_code.co_filename)
    line_no = frame.f_lineno

    first_line = frame.f_code.co_firstlineno
    lines = inspect.getsourcelines(frame)[0]
    print(f"* {filename}:{line_no}:{lines[line_no - first_line].rstrip()}")
   
    return

def trace_call(frame, event, arg):

    if event != 'call':
        return

    # Get the source file path of the current script, works better than __file__
    src_filename = os.path.basename(inspect.getfile(lambda: None))
    co_filename = os.path.basename(frame.f_code.co_filename)
    
    # Trace only the current file and not imported modules
    if co_filename != src_filename:
        return

    line_no = frame.f_lineno
    func_name = frame.f_code.co_name
    func_args = inspect.getargvalues(frame).locals

    print(f"* {co_filename}:{line_no}:{func_name}({func_args})")
    
    return trace_line

def trace(func):
    def wrapper(*args, **kwargs):
        sys.settrace(trace_call)
        result = func(*args, **kwargs)
        sys.settrace(None)
        return result
    return wrapper

TODO

  1. Trace exceptions