Here's an example of how to use it (obviously a minimal case, you can customise your handler do do whatever you need):
def mytrace(frame, event, arg):
if event == "call":
print("call", frame.f_code.co_name, frame.f_locals)
elif event == "return":
print("return", frame.f_code.co_name, arg)
return mytrace
import sys
sys.settrace(mytrace)
For example, given the following code: def three(z):
return 3
def two(y):
return three("BBB") - 1
def one():
return two("AAA") - 1
one()
It will output: call one {}
call two {'y': 'AAA'}
call three {'z': 'BBB'}
return three 3
return two 2
return one 1I can't recall the last time I needed to enable tracing, in the last couple of decades, besides bash scripts.
Has a pretty nice and importantly colored output by default, which I find much easier to follow. In many cases snooping one specific function has done the job. It has an easy to use decorator to decorate any function without having to otherwise intercept the main python invocation or set something up at the start. Good for libraries etc.
pysnooper has mostly been enough for me but the "snoop" mentioned in the article seems to be a superset and more. Will have to give it a go next time.
Outside of this if I want to understand performance or more roughly what code paths are executing (and not a per-statement trace) then austin and py-spy are both amazing.. convert to flamescope and drop into flamescope.app.
Great article!