-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
API: Make numpy.h
compatible with both NumPy 1.x and 2.x
#5050
Conversation
Thanks @seberg for getting the ball rolling.
My assessment/opinion: Having been in situations like that, I think that's pretty terrible. Measured across the entire pybind11 ecosystem, I'd expect a lot of lost time. I believe a more environmentally friendly approach is to fork the header: pybind11/numpy2.h (and to add guards so that only one can be used in a given translation unit) Obviously that's significantly more work right here (e.g. we'll need to test both), but compared to what we'd put the rest of the world through otherwise it's nothing. Tagging contributors to numpy.h, to see who has free bandwidth to work on this (I don't, at least not for a couple months): @wjakob @jagerman @aldanor @dean0x7d @Skylion007 @EthanSteinberg |
Well, the only ones that are likely to notice would be users of structured dtypes, so I would think that is few and they can work around with manual casts too, but don't know. I was thinking as a worst case, until helpers are added to cover usecases which might be lost. |
Sounds fair, I just don't know at all how many people will be affected.
I don't know that, too. Lot's of uncertainty on my part == not good. You could help me understand more by adding tests for exactly what will be affected/broken. That will probably give us ideas for ways to best manage the numpy2 transition. Or wait to see if someone with more relevant background steps up here. But there is another question buzzing in my mind: do you expect that there will be more numpy2-specific tweaks like this needed in the future? I'm asking that question because I'm still wondering: Is it better to freeze pybind11/numpy.h and to fork-and-modify to pybind11/numpy2.h? Or stick with only pybind11/numpy.h and hope we can control the probably increasing messiness of it in the long run? |
@seberg Thank you for taking the initiative here, but I'm really unsure that this is the best path forward. We really shouldn't be using NumPy's C API at all. We need to migrate over to Numpy's Python API That would make us robust to the NumPy 1 vs 2 switch and also significantly reduce the complexity and brittleness of our code. @seberg Do you think you could take on migrating us to the Python API? |
Probably not right now, I don't know how quickly it can be done, and time's running out (how much depends on whether e.g. matplotlib needs it, I am hoping not but dunno) I will note agaain the only thing this breaks signifanctly is direct struct access to the dtype by the user for structured dtypes. If you worry sbout those struct fields, I can add them to descr or document the cast to the versioned struct for access? |
include/pybind11/numpy.h
Outdated
ssize_t alignment; | ||
PyObject *metadata; | ||
Py_hash_t hash; | ||
void *reserved_null; |
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.
void *reserved_null; | |
void *reserved_null[2]; |
OK, it sounds to me like creating a (Had segfaults running nox locally so seeing that it works here, planning to change the tests to use EDIT: sorry for the noise, lots of silly mistake, although now also a crash in the tests which I didn't understand yet... |
dc9b59a
to
1a76257
Compare
This means that users of `numpy.h` cannot be broken, but need to update to `numpy2.h` if they want to compile for NumPy 2. Using Macros simply and didn't bother to try to remove unnecessary code paths.
So maybe a |
Thanks @seberg for all the work! Two quick comments: I'm super busy with other things at the moment but will try to find a block of time to carefully look here asap. @EthanSteinberg wrote:
That's my highly-preferred solution, too, but I'm under the impression that'll be an XL-size effort. I wouldn't want to twist anyones arm doing that to unblock numpy2 support. I believe it'll be sufficient if we ensure that numpy1 and numpy2 are supported simultaneously for some period of time. I want to keep an open mind to how exactly that's done. Which brings me to a related question: is there an official EOL for numpy1? |
Not before the Q3/Q4 2025, according to https://scientific-python.org/specs/spec-0000/. Some users/packages may keep support for longer that that, since 2 years is not a very long window (sufficient for open source, not for certain types of industry and academic users).
It's important to emphasize that this really is about very few users. It would not surprise me if it's zero users, because:
I'd vote for not creating a On the other hand, if you do go with Also note that most packages do not include upper bounds in their pybind11 dependency declaration, and they may be doing releases shortly after numpy 2.0.0rc1 is out (so in 10 days maybe). If you release a Why not go with the minimal |
Meta: At the moment I only have a few minutes to look here. I'm still hoping someone with more relevant background than I have will step up to take the lead seeing this through. I realize it's urgent, so I'll help what I can if nobody else steps up, but I might have weird questions and ideas at first. (I also want to add that the mere existence of the current pybind11/numpy.h implementation badly rubs me the wrong way, but I'll try to hide that as much as I can.)
Sounds good. But a couple more quick question (I hope that will help me pick up here later when I have a block of time):
Do we also need a guard for the opposite situation? |
Aren’t structured dtypes the way you access arbitrary C structs from NumPy? If that’s what you mean, then many pybind11 projects use them, including two of the three projects I work on (boost-histogram and awkward array), which have tons of structured data. But I assume if this only affects some method of access, it wouldn’t be a problem. We mostly have arrays of structured data from that need to be cast into NumPy structured arrays and I can’t see that changing? I’m off on paternity leave currently, so can’t investigate throughly yet. |
Hmm, that should be done automatically if possible. Erroring out unless the user defined it would also be a breaking change for every user, just like having to opt in to @seberg I guess the problems you ran into is that you need it at preprocess time, so can't use the
Makes sense. Let me offer some help here, to do more than pitch in suggestions. I'll work on this by tomorrow unless someone else has it in progress already.
Then one extension will be compatible with 1.x and 2.x, and the other won't be. So the resulting install will only work on 1.x. Not
Yes that's it, and yes only some accesses are affected (not array creation). I searched both code bases for use of things like |
In either case that only matters if you make NumPy 2 support the default or only way, and the last iteration made it so that users have to opt-in.
NumPy can (and should) fail hard with a "this module wasn't compiled for 2.x" error/print out. That message can include a note to ensure to use The newer
I'll try to have a look, but no promises yet. |
A couple quick remarks: @seberg wrote:
Confirmed. Sorry my thinking here was incorrect. I need to spend some time to see what we can do. @henryiii wrote:
Sounds good to me! I won't try too hard then go fix my idea with the |
This also doesn't work as a wished:
After thinking about it more, I came to believe my wish for a reliable @seberg wrote:
Keep it? (Because it is a very simple implementation, and does at least help a little bit.) |
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.
Some minor suggestions and a few questions, possibly naive (I don't know a lot about numpy internals).
Before replying to specific comments: I'm probably having somewhat of an unusual perspective, working at Google: Almost every single change I make (in pybind11 or PyCLIF) triggers tens of millions of tests. Quite often, everything works, except, say, 10. Then I might spend anywhere between 5 minutes and 1+ week to find out what is special about those 10 out of 10 million use cases, and I need to fix it somehow, before I can move on. Therefore I've grown to be hyper sensitive to any form of subtle changes, especially removing tests, or changes for which there is no documented rationale. I'm always thinking: The external world pays the same price, multiplied by a significant unknown factor, because multiple people have to ramp up root causing. What's "nice" though for core library developers: it's not them having to pay that price. The bill is footed by the user community. |
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.
Nice, thanks! With the extra comments I don't feel so clueless anymore looking through the diffs. Those are exactly the kind of clues that'll help me (and I think others) root causing the one in a million failures I wrote about before.
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.
This LGTM from the perspective of NumPy usage. I also tested with SciPy after reverting the workaround for ->elsize
that we were carrying, and that all worked like a charm.
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Tests pass: Looks Good To Me! |
This makes changes necessary with numpy/numpy#25943 and finalizes other NumPy 2 changes (the
GetParams
function has been deprecated/disabled for a while).I have tested this with SciPy and SciPy is happy. Some (TBH, I don't really expect it much) users may be unhappy if they actually try accessing the structured dtype info.
My feeling on that last thing would be that if it is a problem it can be fixed up in a follow up. Users who can't migrate to NumPy 2 immediately could pin to an older version of
pybind11
, I presume.I am very happy if someone takes over here (not sure what else is needed). But wanted to do the main changes to see that it isn't terribly hard.
Suggested changelog entry:
Maybe additional information if you would like: