cool-RR / PySnooper

Never use print for debugging again
MIT License
16.31k stars 954 forks source link

Restore previous f_trace after snoop is done #214

Open alexmojaki opened 3 years ago

alexmojaki commented 3 years ago

See https://github.com/alexmojaki/snoop/pull/34

Basically you need to do this:

https://github.com/alexmojaki/snoop/blob/437956c661184ab458a3f60fcf97c81c31ea2db1/snoop/tracer.py#L213-L217

In particular you need calling_frame.f_trace = previous_trace in addition to the existing sys.settrace(previous_trace).

This is obviously good for restoring the other tracer properly, which I confirmed with the PyCharm debugger. But I stumbled across this because pp stopped working after with snoop: exited. It turns out that if you don't reset f_trace then the frame line number becomes wrong. Here's a demo:

import inspect
import pysnooper

with pysnooper.snoop():
    pass

print(inspect.currentframe().f_trace)
print(inspect.currentframe().f_lineno)  # wrong lineno
1/0  # wrong lineno in traceback

In particular note the weird traceback:

Traceback (most recent call last):
  File "...", line 5, in <module>
    pass
ZeroDivisionError: division by zero

Here's a pure python version of the demo:

import inspect
import sys

frame = inspect.currentframe()

frame.f_trace = lambda *_: print('tracing', frame.f_lineno) or frame.f_trace
sys.settrace(frame.f_trace)

# frame.f_trace = None  # uncomment to fix
sys.settrace(None)

print('after trace', frame.f_lineno)  # wrong lineno
1/0  # wrong lineno in traceback

This is a bug which is apparently fixed in 3.10: https://bugs.python.org/issue42823

cool-RR commented 3 years ago