-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Differing behavior for sys.setrace
between 3.12 and 3.13
#113728
Comments
This is a events = []
with record_events(events):
next(gen())
print(events) 3.12:
3.13:
The events for 3.13 look to be correct. The additional |
This has nothing to do with monitoring or tracing. It is about the lifetime of generators. with record_events(events):
next(gen()) to g = gen()
with record_events(events):
next(g) The events recorded are the same for 3.12 and 3.13. The additional events in 3.12 are from the generator being closed. |
Bisected to #111069 |
So what's happening is this: In 3.12 the generator is closed by calling @nedbat is this a problem for coverage? |
@markshannon I think this and other sys.monitoring changes are going to require me to do a bit of a re-think. There are tests in the coverage.py test suite that check data based on the raw events. The final user-visible coverage data might come out the same, but the tests are failing now because of changes like this. I'll be working on this. |
This isn't a The change is that we no longer |
I understand. I meant to say, this and also sys.monitoring changes are changing the way I collect data, and therefore the way I test. |
So... There's nothing to see here, move along, and close the issue? |
I will re-open if needed. |
Investigating other generator tracing failures in the coverage.py test suite, I find that the trace function is invoked slightly differently for the return event when yielding. The frame.last_i value is pointing to YIELD_VALUE in Python 3.12, but points to RESUME in 3.13. Is this intentional? Will it stay this way? Test program: import dis, linecache, sys
print(sys.version)
def trace(frame, event, arg):
# The weird globals here is to avoid a NameError on shutdown...
if frame.f_code.co_filename == globals().get("__file__"):
lineno = frame.f_lineno
line = linecache.getline(__file__, lineno).rstrip()
print("{} {}: {}".format(event[:4], lineno, line))
if event == "return":
code = frame.f_code.co_code
lasti = frame.f_lasti
print(f"code[{lasti=}] is {dis.opname[code[lasti]]}")
return trace
def gen():
yield 3
dis.dis(gen)
sys.settrace(trace)
print(next(gen())) Running on 3.12:
Running on 3.13.0a2:
Running on the tip of 3.13:
|
tl;dr: Long answer: The semantics of @iritkatriel fixed all that in #109094 replacing the internal "previous code unit pointer" with a more understandable "instruction pointer". @iritkatriel is this summary correct? |
Thanks for the detail. It's a bit odd to have |
During a call the lasti of the calling frame points to the beginning of the CALL instruction. Same with SEND. |
During a yield from a generator, frame.f_lasti used to point to the YIELD bytecode. In 3.13, it now points to the RESUME that follows it. python/cpython#113728
During a yield from a generator, frame.f_lasti used to point to the YIELD bytecode. In 3.13, it now points to the RESUME that follows it. python/cpython#113728
During a yield from a generator, frame.f_lasti used to point to the YIELD bytecode. In 3.13, it now points to the RESUME that follows it. python/cpython#113728
During a yield from a generator, frame.f_lasti used to point to the YIELD bytecode. In 3.13, it now points to the RESUME that follows it. python/cpython#113728
I think this is all sorted. |
Bug report
Bug description:
3.12 events
main:
Note the extra
except
andreturn
events for 3.12.Originally discovered by @nedbat #113680 (comment)
CPython versions tested on:
3.12, 3.13
Operating systems tested on:
No response
The text was updated successfully, but these errors were encountered: