-
-
Notifications
You must be signed in to change notification settings - Fork 23
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 667: correct/clarify handling of PyEval_GetLocals #245
Comments
See python/cpython#119769 for further discussion (it may be possible to have |
We've now identified a few potential resolutions for the discrepancy, and could benefit from a release-manager-or-SC casting vote to resolve a disagreement between @gaogaotiantian and I as to which of them is the least bad option for Python 3.13 (we wouldn't categorise any of them as good options - there are multiple reasons the PEP deprecated this API!).
The current state of Where @gaogaotiantian and I are disagreeing is in how we weigh the value of achieving internal semantic consistency between APIs in Python 3.13 vs potentially introducing a risk of segfaults in unlikely-but-historically-valid code that calls Neither of us are fans of the first option listed (although we do accept it's a valid option), but I favour tolerating the legacy Python 3.12 semantics in |
I think we should to stick to the PEP as written. In other words:
There are a few reasons why:
|
That resolution sounds like a good option to me. I thought it had been ruled out during in-person discussions in Pittsburgh in favour of the sample code defining it in terms of The docs for that approach also mostly exist already, so I can largely pull them from the commit history and have them ready again for beta 3. |
There is a serious problem to return a The fundamantal issue here is - it's a C API, not a Python one. Even in Python, we kept the behavior of Because they would use And this is a much much more common pattern in the market than the "possible segfault" when the user calls For example, my project VizTracer (4k+ stars) uses this and the change will just crash my code. And it's not that I'm stupid, yappi (1.4k stars) has the similar pattern That's just some quick search and I believe there are more than a few popular libraries that would suffer from this. It's also possible that they want to Because of the reasons above, I don't believe the proposal to make |
Some quick summary of why I favored the second option:
|
Hopefully, it will increase the chance of a crash. Crashes are easy to diagnose and fix. I'm more worried about hard to spot changes in semantics. That The yappi code is already full of For a profiler, I would think that considerably reduced overhead of the new API would be well worth the cost of moving to the new API anyway. You seem to think it is possible to avoid breaking code. It isn't, because Trying to hide the breakages will make thing worse in the long term, IMO.
This is already quite broken in 3.11 as any call to a trace function could have updates the locals anyway via |
I picked those two repos as an example, just to illustrate the impact of the change. There are a lot of others that have similar issues.
If that's the case, we should remove the API directly so that everyone just crashes and they are required to find a new solution. Because anyone that really uses the return value of this API will be crashed with the proposed change (assuming the return value is a dict simply will not work). We kept this API and allow a deprecation phase because we want our users to be less disturbed. I agree that
That's why I don't like the idea of making it behave like 3.12. Then we will have 3 behaviors - 3.12,
and
should give user the consistence as well - the latter ones are the strong reference version of the former ones. The I also agree that we should fail fast when the user is doing something that's not supported well. That's why I chose 2 over 1, but I think we should try to make user not crash. I don't believe we can, with some efforts, save the users so all of their code will work. But I believe in many simple cases, it can work just as before, with the semantic changes of |
I am baffled by this statement.
However quirky, underdocumented and undersupported the previous API was, it was possible to use it correctly -- for example, by avoiding tracing, or by figuring out what the lifetime of some borrowed reference was in practice. |
I'll note that As far as the risk of segfaults arising from passing proxy instances to One idea I did have that would make me more in favour of @gaogaotiantian's approach (i.e. making previously borrowed references expire on each call to |
Having thought about this some more. Here's an approach that will hopefully keep everyone happy, with almost no change for users if they keep using General idea
The old and new APIsNew APIPython
C
The old APIPython
C
Implementation of locals() and PyEval_GetLocals()Both Rather than returning an instantaneous snapshot of In other words def locals():
frame = sys._getframe(1)
f_locals = frame.f_locals
if not isinstance(f_locals, FrameLocalsProxy):
return f_locals
if frame.locals_cache is NULL:
frame.locals_cache = {}
frame.locals_cache.update(f_locals)
return frame.locals_cache The only change in behavior from 3.12 is that stores to |
The downside of this is that it creates more cycles, but no more than 3.12. We shouldn't worry about the old API creating cycles. |
|
As @carljm suggests, my own preferred option is to have No segfault risks, no increase in potential memory usage relative to Python 3.12, and it confines the legacy behaviour to a now inherently ambiguous API which has clear replacements that unambiguously implement the new semantics ( We would still eventually get to the fully consistent state with only the new semantics being available, it would just take a couple more releases than @gaogaotiantian hoped it would (presumably 3.15 if we keep Losing the clarification of Simply saying " This ambiguity in intent doesn't apply to |
I agree that we should not revert the behavior for I think from the discussion above, even though we can't fully agree on which is the best way for |
OK, so it sounds like the consensus is to keep the new behavior for That leaves
Any objections to my suggestion for making |
It's not my first choice, but I find it acceptable, as long as we can mark it deprecated in 3.13. If not, well it's still not unacceptable but I think that would cause more chaos in the future. |
I would still like to have a C API that's a direct mirror of Given the naming pattern used in other parts of the API where an API returning a borrowed reference (e.g
The deprecation notice on |
I also believe a C API that behaves like At this point, I'm a bit tired arguing about |
It isn't ideal, but it's important to remember that:
The only other potential name for the C API |
I'm not super opposed to the idea. But to me, it feels like this:
The "inconsistency" in C APIs reflects the "inconsistency" in Python. It's not the same to call For most of our C API users, that probably makes more sense - most of them are looking for the Python equivalent. |
From the discussion in the discord, the C API might have implicit impacts on |
Note that the beta2 docs cover the impact on It's also called out explicitly in the porting notes: https://docs.python.org/dev/whatsnew/3.13.html#pep667-porting-notes-py Affected functions further have this note added to them:
This change was something PEP 667 inherited from PEP 558, so the primary notification of this change in the PEPs themselves is actually in PEP 558: https://peps.python.org/pep-0558/#what-happens-with-the-default-args-for-eval-and-exec @gaogaotiantian has started a PR to make this impact of the PEP 667 changes clearly in PEP 667 itself: python/peps#3845 |
Some clarifications from the Steering Council regarding this discussion: we have been discussing the PEP and the issue and reviewing the conversation so far and here are some points we want to make or clarify:
Please, comment here or reach out to us if something in these points its not clear or if you want us to consider something else. In representation of the SC, |
Thank you for the comments from the SC, it seems like at least we got the deprecation - that's great. If we can get a deprecation warning at compile time, I'm okay with either option. If we keep the same semantics for |
Thanks folks. I think that means the beta2 docs are correct as written, but I'll double check them to make sure. @gaogaotiantian As far as the backwards compatibility section in the PEP goes,
Edit: PEP PR moved to python/peps#3845 |
@pablogsal Just confirming this point, since the SC comment didn't specifically address it, although it had come up earlier in the thread as something to consider changing:
(This is what the accepted PEP specified, and is what is currently implemented and documented, so leaving it the way it is would be entirely reasonable. @markshannon just noted during this discussion that his intention had been for |
Just noting this request for further SC review on the PEP PR here: python/peps#3845 (comment) (I think what we've written is in line with the SC's directive above, but the SC members are the best judges of their intent)
Oops, @hugovk is right, the 16th is the last 3.13 beta opportunity to get this fully resolved (primarily getting the PEP updated and switching python/cpython#119769 to restore the 3.12 semantics) |
I think you might be looking at the 3.11 schedule? For 3.13: beta 4 is scheduled for the 16th with RC1 on the 30th. No beta 5 currently planned. |
@Yhg1s to confirm - I believe we're done with this issue here and that the PEP 667 changes in python/peps#3845 are good? |
We had one final late breaking adjustment due to a bug report against 3.13.0, but it was a clearly undesirable compatibility break with a straightforward fix (allowing So with python/peps#3845 merged, I think this is all done now. |
While writing the docs for python/cpython#74929 and reviewing python/cpython#118934, I discovered a discrepancy in the way PEP 667 described the updates affecting
PyEval_GetLocals
(what the text described didn't match the proposed implementation given).After discussing it with @gaogaotiantian in python/cpython#118934 (comment) I'm happy that the discrepancy should be resolved in favour of the proposed implementation, but I'd also like the SC to ratify that since we're arguably changing a user-facing detail of an accepted PEP.
python/peps#3809 updates the PEP text to resolve the inconsistency (since it's referenced from the Python 3.13 What's New and leaving it as is might be confusing for users ofPyEval_GetLocals
)Edit: PEP PR moved to python/peps#3845
The text was updated successfully, but these errors were encountered: