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
ENH: Implement correct scalar and integer overflow errors for NEP 50 #21875
Conversation
OK, I still don't love the scalar code, but considering that the ufunc code is at least well localized and the scalar code could use more cleanup (as in conversion function introduction probably via C++), I will mark this as ready for review. I simply did not have a clear idea for how to improve it meaningfully. |
if (!PyTypeNum_ISCOMPLEX(NPY_@TYPE@)) { | ||
return PROMOTION_REQUIRED; | ||
} | ||
return CONVERT_PYSCALAR; |
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.
Is this line really skipped during testing or is codecoverage mistaken?
I would prefer not to, if we can avoid more methods |
056850c
to
f096789
Compare
fb136f8
to
ede4ca4
Compare
Hmm, trying to untangle the state of this. The reason for custom handling was that we can allow these to remain unmodified:
i.e. we still allow the forced cast in some cases, but not in the new paths. This seems almost exclusively relevant for that use-case where you use -1 to mean However, we are already changing quite a lot, so maybe it is OK to just change that as well, with the one possible exception that we could hard-code The other question is only relevant if we do not want to change the above. That was where I was coming from. But I don't really see that it makes things clearer by not being a method (since methods are the typical path now, I think). |
Lets discuss this on Wednesday a bit, maybe we can make a decision then (I think the code coverage/tests should be fine now, but will fix it up if not). |
bae8510
to
8ac5f3f
Compare
This requires adding a path that uses the "normal" Python object to dtype conversion (setitem) function, rather than always converting to the default dtype.
The new weak promotion preserves the original type, this makes the `//= 2**32` fail for certain inputs. The alternative would be typing that as `np.int64(2**32)`, but using Python integers seems easier and cleaner. The code was effectively OK before, since the inputs were guaranteed signed (or Python integers) at that point and 2**32 would have been considered like a NumPy `int64`. (Which would be an alternative fix.)
This is the *actual* correct fix for the test adaptations. The test adaptations should only be necessary when running in weak-promotion mode, but they are NOT doing that currently.
…values This should be fixed in `choose` to not do the unnecessary cast, see numpygh-22237.
Especially adding coverage also for the power operator which does not share its code perfectly.
8ac5f3f
to
d9da02d
Compare
OK, this is rebased to account for gh-22385. (I will have another scroll through myself later today just to make sure there are no small cleanups needed still). |
@pytest.mark.parametrize("dtype", np.typecodes["AllInteger"]) | ||
def test_nep50_weak_integers(dtype): | ||
# Avoids warning (different code path for scalars) | ||
np._set_promotion_state("weak") |
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.
Should the tests reset global state at finish?
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.
Yes, there is a module wide auto-fixture that defaults to "weak_and_warn"
and resets the state at the end.
d563343
to
ee3c20b
Compare
Can we move forward with this, soon? I would like to make sure we have full optional NEP 50 logic by next release for testing. |
Thanks @seberg |
This adds the main missing chunk of NEP 50 support. Unfortunately, I feel this is still fairly complex, although I am not sure it can be helped...
For the ufuncs, it may be possible to move the special handling to later. For the scalars, the special handling has a bit of additional complexity because of the "defer" check (if we did it always it would be easier logic flow).
Unfortunately, for the scalars it makes sense to keep the "faster" version for the safe cast around (for speed reasons).
The other question is whether we want to do this as a distinct method on the DType, although I don't think we have to settle that yet. It should be easy to change.
A small oddity is that the user has to
resolve
from one of the "int" dtypes (int32, int64, uint64, object). That seems OK to me, although it also seems like something that we may well know better later.Marking as draft, I need to let this sink in a bit to see if I have a better idea. Bug, this should be ready for a test ride and may complete NEP 50 logic (with the exception of possibly allowing Python scalars for example in
np.can_cast(123, np.int8))