gh-129280: Avoid cyclic reference in contextlib.contextmanager#129276
gh-129280: Avoid cyclic reference in contextlib.contextmanager#129276user202729 wants to merge 1 commit into
Conversation
Sorry, something went wrong.
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
Sorry, something went wrong.
ZeroIntensity
left a comment
There was a problem hiding this comment.
At an overview:
- This seems issue-worthy to me; could you make one, and then link to it in the PR title?
- Per the bot, we do need a blurb entry, as this is a user-facing change.
- A test case would be good too (see the devguide).
However, going back to the use-case:
This also has the practical impact of some packages (cysignals) using reference counting to detect whether the exception has been handled
I'd be very careful with that. We don't have any guarantees about reference counting, especially with built-in objects. (For example, on the free-threaded build, we have plenty of reference counting hacks that allow for multithreaded scalability--I suspect this kind of thing would break over there.)
Sorry, something went wrong.
I know that very well. But… 6 years ago, there was a difficult to debug issue with SageMath sagemath/sage#24986 , and the developers concluded using that hacky reference counting solution is the best available workaround. Turns out it causes additional issues later: sagemath/sage#39224 There exists a better solution, see sagemath/cysignals#215 (comment) , but while it is not yet implemented (there are a lot of places that need to be changed in the code base) I try to make the best of what is available. If the developers originally implemented the proper solution, we wouldn't be in this situation. But removing the workaround entirely before implementing the proper solution seems impractical at this point. (in the meantime, I'll try to figure out how to write test case and blurb, but I'd appreciate any help if possible) |
Sorry, something went wrong.
Feel free to tag me if you need any help. The devguide should have everything you need, though :) |
Sorry, something went wrong.
|
Feel best if I leave this as draft until I figure out what's the root cause of the change in behavior Python 3.11 and Python 3.12. |
Sorry, something went wrong.
|
Bisecting results in 1e197e6 being the first bad commit. Seems to make sense…? If more references to frames are added then it's more likely to create cyclic references…? |
Sorry, something went wrong.
|
More investigation shows the frame object has I haven't fully understood what the linked pull request does yet, but maybe if only ensure the shim frame is cleared without clearing the actual frame…? @markshannon Any idea about this? Codefrom contextlib import contextmanager
class MyException(Exception):
def __del__(self):
print(self.__traceback__.tb_frame.f_back)
print("deleted")
@contextmanager
def f():
try:
yield
except MyException as e:
global g
g = e
print(e.__traceback__.tb_frame.f_back)
with f():
raise MyException()
print(g.__traceback__.tb_frame.f_back) # ⟵ this prints None in Python 3.11 and <frame…> in Python 3.12
print("done") |
Sorry, something went wrong.
|
I think that this PR (which likely will be closed in favor of more general solution) is not the best place for discussion. |
Sorry, something went wrong.
|
This PR is stale because it has been open for 30 days with no activity. |
Sorry, something went wrong.
By deleting the cyclic reference between the frame object and the exception object, this allows the objects to be deleted more quickly (it doesn't need to wait until the next GC cycle)
This also has the practical impact of some packages (cysignals) using reference counting to detect whether the exception has been handled, which breaks in the presence of this situation. sagemath/sage#39142