Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
gh-106004: Add PyDict_GetItemRef() function#106005
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
Uh oh!
There was an error while loading. Please reload this page.
Conversation
vstinner commented Jun 23, 2023 • edited by github-actions bot
Loading Uh oh!
There was an error while loading. Please reload this page.
edited by github-actions bot
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
markshannon commented Jun 23, 2023
What's the rationale for not distinguishing between found and not found in the return value? |
markshannon commented Jun 23, 2023
Can we come up with a better name than Obviously, the ideal name is already taken. |
vstinner commented Jun 23, 2023
Sure, if you think that it's useful, I can return 1 if the key is present. It doesn't go against the syntax Well, I'm fine with people having different taste (if it doesn't go against my taste ;-)).
Nope, that's my local optimum name :-)
Maybe PyObject_GetItem()? :-D Just kidding, PyObject_GetItem() already exists and works for any type (doesn't crash if it's not a dict) :-) Well, that would just be 2 more functions on the top of the existing 9 functions to "get an item in dict":
Ok, let me propose a name: PyDict_GetItemOkThisTimeItShouldBeCorrect() :-) I already added the following functions with the "Ref" suffix:
The "Ref" is here to remain that this one it returns a strong reference. And also: Py_NewRef() and Py_XNewRef() (not really a "strong reference" variant of an existing function). |
markshannon commented Jun 23, 2023
Testing the result is always at least as efficient as doing a test on We made python/devguide#1121 to avoid having to repeat this discussion for every new API function. |
markshannon commented Jun 23, 2023
Can we please stop adding new functions to the C-API until we have established conventions. |
vstinner commented Jun 23, 2023
I modified the API to return 1 when the key is present (and 0 when the key is missing). |
vstinner commented Jun 23, 2023
I created capi-workgroup/problems#52 to discuss C API naming convention (when adding new functions). |
vstinner commented Jun 27, 2023
@erlend-aasland@markshannon: Are you ok with the proposed API? @erlend-aasland added some guidelines related to proposed API in the Devguide. @erlend-aasland@markshannon: About the function name, I created capi-workgroup/problems#52 but it's unclear to me what's the outcome of this naming convention discussion. What should I do to make progress on this PR? |
markshannon commented Jun 27, 2023
No, I'm not OK with the proposed API. I've already said that. Using What's the rush? |
markshannon commented Jun 27, 2023
TBH, I don't think you should have opened this PR until there was some feedback on the issue. |
vstinner commented Jun 27, 2023
By the way, draft PEP 703 – Making the Global Interpreter Lock Optional in CPython proposes |
vstinner commented Jun 27, 2023
I replied there: #106005 (comment)
I was confused by @gpshead's comment: "I don't think it matters which naming scheme we pick or even if it winds up wholly consistent."
There is no rush. I just wanted to understand the status of this PR. |
erlend-aasland left a comment
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.
I'm approving this. A new naming scheme makes sense for a new API; I'm not sure it makes sense to try and enforce a new scheme in the current API. For now, there is already precedence of the Ref suffix in the current API; I'm ok with that. Also, the current API uses PyObject * all over the place. If we are to change this, we practically will end up with a completely new API; AFAICS, there is no problem with sticking to the current practice.
vstinner commented Jul 12, 2023
This PR is ready for review, so I remove the draft status again. |
vstinner commented Jul 12, 2023
Oh. @serhiy-storchaka and @gpshead seem to be strongly against it, so I reverted the change to go back to the initial plan: I tried to use a revert, but sadly the Git history became too complicated, so instead of squashed commits and I rebased my PR. Sorry about that :-( Gregory:
Well, I was requested to set multiple guidelines for different aspects of the API on this single function addition.
PR changelog:
|
serhiy-storchaka left a comment
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.
I did not propose PyDict_GetOptionalItem() seriously, it would look confusing taking into account that other functions also return an "optional" item. I accept PyDict_GetItemRef() as token name and will accept any name whichever you choose. No need to bakeshed it to death.
I would be fine with the absent of runtime type check, not every C API function has a runtime type check, but the existing functions PyDict_GetItem() and PyDict_GetItemWithError() have a runtime type check, so why this function should be special? And compile time type check would just not work.
I confirm my approve.
erlend-aasland left a comment
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.
Confirming my approval.
I believe introducing more type structs in the Limited API is a very bad decision, so I'm glad that particular change was reverted; I prefer to stick with the existing API convention of PyObject * only. For the "Brand New API", whatever that will be, a generic "PyObject-like struct" might not be the best option.
Regarding naming, I have no preference. Personally, I think I would have considered the PEP 703 naming to try and create slightly less merge conflict havoc for Sam when if nogil is going to be merged.
encukou commented Jul 13, 2023
FWIW, here's a possible new variant: you could set |
markshannon commented Jul 13, 2023
If this function is to take |
serhiy-storchaka commented Jul 13, 2023
|
vstinner commented Jul 13, 2023
I like SystemError. I used it in the past to detect bugs in C extensions, since TypeError is too common, so it was easy to distinguish "normal" TypeError from "invalid" SystemError. For me, SystemError means "bad API usage".
IMO if TypeError is preferred, we should try to keep the whole C API consistent and raise TypeError in all similar situations, not only for newly added functions. Otherwise, it can be misleading. |
vstinner commented Jul 13, 2023
For me, it's very surprising that the purpose of a function change "that much" depending on a parameter. For example, in Python, getattr() and hasattr() are two different functions: you cannot pass None to getattr() to check if an attribute exists. I prefer to have separated functions to "get" an item/attribute and to check if an object "has" an item/attribute. I dislike having to use locale.setlocale(loc, None) to get a locale :-( I don't want to use locale.getlocale(loc) since it returns different different. This issue goes in all directions, it's a little bit hard to follow :-( |
serhiy-storchaka commented Jul 13, 2023
How does this differ from |
vstinner commented Jul 13, 2023
Can we now please focus the discussion on this PR about PyDict_GetItemRef() and only PyDict_GetItemRef()? For general C API discussions, I suggest using the https://github.com/capi-workgroup/problems/issues project. So far, the PR got 2 approvals (@gpshead removed his approval). Now I don't know if I'm supposed for wait for the SC: @gpshead created python/steering-council#201 issue but in 2 weeks, the SC didn't have time to look into this issue. |
gpshead commented Jul 13, 2023
my 2 cents on exception types: If it is a bug in code at the C API level, For now, lets let this PR sit while we wait for steering council answers. |
vstinner commented Jul 17, 2023 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
PyObject_GetItem() is the safe generic API: it raises TypeError if the API is misused, if the first argument is not a mapping (or a sequence). PyDict_GetItemWithError() is the fast specialized API: it raises SystemError if it's misused, if the first argument is not a dict or a dict subtype. |
I'm taking a break from the C API discussions; I'm removing myself from this PR for now
* Add PyDict_GetItemRef() and PyDict_GetItemStringRef() functions. Add these functions to the stable ABI version 3.13. * Add unit tests on the PyDict C API in test_capi.
vstinner commented Jul 19, 2023
I rebased my PR on the main branch to fix conflicts. |
vstinner commented Jul 21, 2023
Thanks everyone for the great reviews. I think that the final API is better than my first version. The road for that function was more bumpy than for other functions since PyDict_GetDict() is one of the commonly used function, and as I wrote before, we took this function as an opportunity to revisit some API design choices. There are some disagreements which have been discussed in length, especially in the https://github.com/capi-workgroup/problems/issues/ project. Overall, the majority seems to be in favor of this change (and I didn't see any concrete counter-proposal to solve the issue). Sadly, this PR lost two approvals in the bumpy discussion. IMO it's now time to move on and see how this function can be used to avoid bugs and how to migrate users from the cursed PyDict_GetItem() to that better PyDict_GetItemRef() function. Supporters of a new API instead of fixing the current API one function by one, I suggest continuing the discussion in https://github.com/capi-workgroup/problems/issues/ : there are a few issues related to that. So far, I didn't see any clear nor complete proposal, so for me, we are still at the same status quo: we do our best, fixing functions, one by one, when we agree that there is an issue. Same for the question of using Completely getting rid of PyDict_GetItem() may take time. Maybe we need to consider capi-workgroup/problems#54 approach for users who want to start a new C API with a clean C API without known issues like borrowed references. But well, that's out of the scope of this issue. This issue does not deprecate PyDict_GetItem() on purpose. |
* main: pythongh-106004: Add PyDict_GetItemRef() function (python#106005)
vstinner commented Jul 21, 2023
I added PyDict_GetItemRef() to pythoncapi-compat: python/pythoncapi-compat@eaff3c1 |
vstinner commented Jul 24, 2023
If we keep these new functions in Python, IMO we should consider replacing usage of the private _PyDict_GetItemStringWithError() with the public PyDict_GetItemStringRef(). And maybe even remove _PyDict_GetItemStringWithError() later. |
📚 Documentation preview 📚: https://cpython-previews--106005.org.readthedocs.build/