Thanks to visit codestin.com
Credit goes to github.com

Skip to content

MNT: replace _PyDict_GetItemStringWithError with PyDict_GetItemStringRef #26282

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

Merged
merged 5 commits into from
Apr 17, 2024

Conversation

ngoldbaum
Copy link
Member

@ngoldbaum ngoldbaum commented Apr 15, 2024

Replaces all usages of the private _PyDict_GetItemStringWithError Python C API function with PyDict_GetItemStringRef. The latter is available in the python 3.13 C API and via python-capicompat in older python versions.

The new function has the same semantics as PyDict_GetItemRef but takes a UTF-8 C string instead of a python object. Like _PyDict_GetItemStringWithError, it does not suppress errors. It also has the nice improvement that the return type is now int and it signals success or failure. This lets me re-structure control flow a bit and avoid PyErr_Occurred() calls.

I used the new PyDict_ContainsString function if all we care about is whether a key is in the dict. I also used Py_SETREF in a few places that were using the unsafe decref then set pattern.

See #26159 for the relevant tracking issue.

@ngoldbaum ngoldbaum added 03 - Maintenance 39 - free-threading PRs and issues related to support for free-threading CPython (a.k.a. no-GIL, PEP 703) labels Apr 15, 2024
Copy link
Contributor

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @serhiy-storchaka who made similar changes and might also want to review this numpy change :-)

@ngoldbaum ngoldbaum force-pushed the replace-_PyDict_GetItemStringWithError branch from 06417b0 to 26f7421 Compare April 16, 2024 16:50
Copy link
Contributor

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (but I'm not a numpy developer).

Copy link
Member

@seberg seberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, some of that code looks like it could use more love, but it isn't directly related to the change. The change looks fine to me and I am sure Victor has a great eye for spotting refcounting errors as well.

So putting this in, thanks Nathan.

goto fail;
}
if (!is_default) {
if (PyArray_DescrConverter2(descr, &new_dtype) != NPY_SUCCEED) {
Py_DECREF(descr);
goto fail;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird how we use goto fail here, but not below it. But OK.

@@ -142,8 +142,10 @@ PyUFunc_clearfperr()
NPY_NO_EXPORT int
set_matmul_flags(PyObject *d)
{
PyObject *matmul = _PyDict_GetItemStringWithError(d, "matmul");
if (matmul == NULL) {
PyObject *matmul = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need an init? If it does, might make sense to mention that in the Python docs, @vstinner, even if not a big deal. (I.e. that it effectively uses Py_SETREF(res, ...) internally.

But this would be a silly nitpick here to actually remove it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@seberg seberg Apr 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the docs are fine. It isn't like result can be reasonably set to a e.g. a default value before the call: The code here unnecessarily initializes it, which made me wonder.

EDIT: Sorry, right... it lists that result is set on all paths, so it is very obvious.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to initialize variables in C code even if I don't strictly need to. Probably a knee-jerk response from experiences of reading from an uninitialized variable causing heisenbugs.

@seberg seberg merged commit 50a705c into numpy:main Apr 17, 2024
64 checks passed
}

Py_DECREF(descr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ngoldbaum this is at the wrong indentation level. It's too late here, and I am not sure where to put a test though. cunumeric notices this, it seems they use void (I suspect unstructured but dunno), without a descr.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, thanks for catching. I unfortunately can't help with a test, I was doing a mechanical refactor here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must have some __array_interface__ tests. It shouldn't be hard to create a dict that runs into this, tbh. Although I could overlook it, it would be nice to just have.

Copy link
Member Author

@ngoldbaum ngoldbaum Aug 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial reading of your message was that it was a head's up and an ask for help. I'm happy to fix this but if, in the future, you want me to look at something, it would help me if you could say that explicitly in your initial message to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the indentation level is wrong, doesn't it just need to be an xdecref?

I also don't immediately see how to write a test for this, the existing __array_interface__ tests mostly use the ndarray __array_interface__ implementation. It would be a good idea to improve the tests there but I don't want to do that just to fix this bug.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have just created an issue. I wanted to look at it quickly, but realized that adding a test was not quite as quick as I had hoped, and hoped you might have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
03 - Maintenance 39 - free-threading PRs and issues related to support for free-threading CPython (a.k.a. no-GIL, PEP 703)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants