-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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
[PEP 558 - WIP] bpo-30744: Trace hooks no longer reset closure state #3640
[PEP 558 - WIP] bpo-30744: Trace hooks no longer reset closure state #3640
Conversation
Previously, trace hooks running on a nested function could incorrectly reset the state of a closure cell. This avoids that by slightly changing the semantics of the locals namespace in functions, generators, and coroutines, such that closure references are represented in the locals namespace by their actual cell objects while a trace hook implemented in Python is running. Depends on PEP 558 and bpo-17960 to cover the underlying change to frame.f_locals semantics.
05a351e
to
7626a0e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rebase needed and build failures needed addressing.
@njsmith Aside from the TODO's in the PR itself, this is a pretty complete implementation of the current version of PEP 558 now. |
One other known issue: the header file updates still need to be modified to conform with the new conventions. |
I don't know if this is already addressed elsewhere, but I'm getting a strange error. Running the below script with python.exe built with this branch (I removed an unused parameter to make it compile):
gives
but this error is absent for certain values of x, say:
|
Hmm, looks like I may have a refcounting bug, and the small integer cache is able to provoke it into crashing. |
I can report that not all small numbers trigger this error. On my machine |
Running |
Last push resolves the test_frame segfault, but adds a TODO noting that the locals proxy may still misbehave after a frame has been cleared (or is in the process of being destroyed). There's also a threading test which checks reference cycles aren't being created through the frames, which is currently failing (quite possibly for a related reason) |
Ugh, the refcyle issue detected by test_threading is kinda inherent in the current implementation: once I'm going to try forcibly breaking the cycle when an optimized frame exits (before the eval loop drops its own reference). |
I've pushed an update that resolves almost all of my own "PEP 558 TODO" items in the code (and ticked them off in the checklist above as well):
I will be adding another todo item to the checklist, which is to explicitly test the handling of cleared frames. Implementing For the merge conflict, I'm hoping to get #27525 merged before I try to sync this branch with the main branch again. It was my first attempt at doing that which prompted me to file bpo-44800 in the first place, as it was quite unclear how the conflicts should be resolved given the currently checked in variable naming conventions. |
|
This PR is stale because it has been open for 30 days with no activity. |
I have a concern about raising Was it possible for If not, then it would be nice to have that explicitly documented (at least in the PEP, maybe elsewhere if appropriate and not too noisy to include it). But So I think it might be a bit of a challenge for third parties to write code that
Because it seems like code released today:
For what it's worth, this isn't insurmountable - in my little toy library that mutates functions' variables through TL;DR: because change takes |
This PR is stale because it has been open for 30 days with no activity. |
This PR is stale because it has been open for 30 days with no activity. |
Closing as per the deferral notice in https://github.com/python/peps/pull/3050/files |
(Declined as per the PEP deferral notice in https://github.com/python/peps/pull/3050/files - this reference implementation was useful at the time, but after the frame management changes in Python 3.11 any implementation of the updated semantics in PEP 558 or PEP 667 would be best off starting from scratch. The test cases from this branch might still be useful, but those can always be copied out to a new branch easily enough)
Previously, trace hooks running on a nested function
could incorrectly reset the state of a closure cell.
This avoids that by changing the semantics of the
f_locals namespace on function frames to use a
write-through proxy, such that changes are made
immediately rather than being written back some
arbitrary time later.
PEP 558 and bpo-17960 cover additional changes
to locals() and frame.f_locals semantics that are
part of this update.
Remaining TODO items before this PR could be considered complete:
_PyInterpreterFrame
to_Py_framedata
#27525 and resync this PR with the main branchlocals()
,vars()
, and potentially others (check alllocals
mentions)locals()
(and potentiallyvars()
)PyEval_*
C API documentation updatesPyFrame_*
C API documentation updatesFix C API header layout to follow modern conventions(bpo-35134: Migrate frameobject.h contents to cpython/frameobject.h #18052)PyFrameObject
redefinitioneval()
default locals namespace toPyLocals_Get()
exec()
default locals namespace toPyLocals_Get()
IMPORT_STAR
opcode is encountered in aCO_OPTIMIZED
framePyFrame_LocalsToFast()
runtime errorPyLocals_Get()
andPyEval_GetLocals()
at different scopessetdefault()
popitem()
clear()
update()
(theoretically already implemented, but needs explicit tests)Desirable code structure improvements (current plan for these is to put any duplicated into a sharable location in this PR, but file separate maintainability issues to migrate to using the shared code in the original locations, to avoid the diff size impact on this PR):
odictobject.c
Move the(obsolete task, as frame locals proxy is now independent of mapping proxy)DictProxy
code out ofdescrobject.c
https://bugs.python.org/issue30744