BUG: MaskedArray arithmetic with Python scalars ignores NEP 50 weak-type#31871
BUG: MaskedArray arithmetic with Python scalars ignores NEP 50 weak-type#31871shipitdev wants to merge 1 commit into
Conversation
When a Python scalar is passed to MaskedArray arithmetic, getdata() converts it to a 0-d numpy array before the ufunc sees it. This turns it from a NEP 50 'weak' type into a 'strong' type, causing unnecessary dtype promotion (e.g. int8 + int -> int64 instead of int8). Skip getdata() for Python scalars in _MaskedBinaryOperation.__call__ and in power(), so the ufunc receives them directly. Closes numpygh-31868
|
I first tried fixing this inside |
Relation to prior workThis issue was previously reported in #27029 and #27679. A more comprehensive fix covering both regular and in-place operations exists in #28567. This PR addresses the non-in-place case only, using a call-site approach (bypassing If a maintainer feels this is not relevant or conflicting with #28567. I have no problem abandoning this, However if the comprehensive pr stall for any longer, i feel that this narrower fix covers the most common user-facing case. |
Closes #31868
Problem
MaskedArray arithmetic with Python scalars produces a different dtype
than the same operation on a plain ndarray:
This was due to:
_MaskedBinaryOperation.__call__callsgetdata()on both operands before calling the ufunc. For Python scalars,getdata()has no._datato grab, so it falls back tonp.array(50)which creates a 0-d int64 array. Under NEP 50 that's a "strong" type, so the ufuncpromotes int8 to int64. The standalone
power()function has the same issue.Fix
Skip
getdata()for Python scalars (int,float,complex) in the two call sites, passing them straight to the ufunc where NEP 50treats them as weak types.
Test & Enviornment
Added
test_scalar_arithmetic_preserves_dtype_nep50covering int8,float32, four operators, reversed operand order, and numpy-scalar promotion.AI Disclosure
AI was used only to strictly format this PR for maintainer readability and ease I also Used an AI assistant to help trace the call chain from
MaskedArray.__add__through_MaskedBinaryOperation.__call__togetdata, and to confirm the root cause.The diagnosis, fix, and tests were written and verified manually.