def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs): # Lightly modified version of # https://numpy.org/doc/stable/reference/generated/numpy.lib.mixins.NDArrayOperatorsMixin.html # The primary modification is not boxing scalar return values # in PandasArray, since pandas' ExtensionArrays are 1-d. out = kwargs.get("out", ()) result = ops.maybe_dispatch_ufunc_to_dunder_op( self, ufunc, method, *inputs, **kwargs ) if result is not NotImplemented: return result if "out" in kwargs: # e.g. test_ufunc_unary return arraylike.dispatch_ufunc_with_out( self, ufunc, method, *inputs, **kwargs ) if method == "reduce": result = arraylike.dispatch_reduction_ufunc( self, ufunc, method, *inputs, **kwargs ) if result is not NotImplemented: # e.g. tests.series.test_ufunc.TestNumpyReductions return result # Defer to the implementation of the ufunc on unwrapped values. inputs = tuple(x._ndarray if isinstance(x, PandasArray) else x for x in inputs) if out: kwargs["out"] = tuple( x._ndarray if isinstance(x, PandasArray) else x for x in out ) result = getattr(ufunc, method)(*inputs, **kwargs) if ufunc.nout > 1: # multiple return values; re-box array-like results return tuple(type(self)(x) for x in result) elif method == "at": # no return value return None elif method == "reduce": if isinstance(result, np.ndarray): # e.g. test_np_reduce_2d return type(self)(result) # e.g. test_np_max_nested_tuples return result else: # one return value; re-box array-like results return type(self)(result)
def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs): # if not all( isinstance(t, self._HANDLED_TYPES + (DecimalArray,)) for t in inputs ): return NotImplemented result = arraylike.maybe_dispatch_ufunc_to_dunder_op( self, ufunc, method, *inputs, **kwargs ) if result is not NotImplemented: # e.g. test_array_ufunc_series_scalar_other return result if "out" in kwargs: return arraylike.dispatch_ufunc_with_out( self, ufunc, method, *inputs, **kwargs ) inputs = tuple(x._data if isinstance(x, DecimalArray) else x for x in inputs) result = getattr(ufunc, method)(*inputs, **kwargs) if method == "reduce": result = arraylike.dispatch_reduction_ufunc( self, ufunc, method, *inputs, **kwargs ) if result is not NotImplemented: return result def reconstruct(x): if isinstance(x, (decimal.Decimal, numbers.Number)): return x else: return DecimalArray._from_sequence(x) if ufunc.nout > 1: return tuple(reconstruct(x) for x in result) else: return reconstruct(result)
def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs): # For MaskedArray inputs, we apply the ufunc to ._data # and mask the result. out = kwargs.get("out", ()) for x in inputs + out: if not isinstance(x, self._HANDLED_TYPES + (BaseMaskedArray,)): return NotImplemented # for binary ops, use our custom dunder methods result = ops.maybe_dispatch_ufunc_to_dunder_op( self, ufunc, method, *inputs, **kwargs ) if result is not NotImplemented: return result if "out" in kwargs: # e.g. test_ufunc_with_out return arraylike.dispatch_ufunc_with_out( self, ufunc, method, *inputs, **kwargs ) if method == "reduce": result = arraylike.dispatch_reduction_ufunc( self, ufunc, method, *inputs, **kwargs ) if result is not NotImplemented: return result mask = np.zeros(len(self), dtype=bool) inputs2 = [] for x in inputs: if isinstance(x, BaseMaskedArray): mask |= x._mask inputs2.append(x._data) else: inputs2.append(x) def reconstruct(x): # we don't worry about scalar `x` here, since we # raise for reduce up above. from pandas.core.arrays import ( BooleanArray, FloatingArray, IntegerArray, ) if is_bool_dtype(x.dtype): m = mask.copy() return BooleanArray(x, m) elif is_integer_dtype(x.dtype): m = mask.copy() return IntegerArray(x, m) elif is_float_dtype(x.dtype): m = mask.copy() if x.dtype == np.float16: # reached in e.g. np.sqrt on BooleanArray # we don't support float16 x = x.astype(np.float32) return FloatingArray(x, m) else: x[mask] = np.nan return x result = getattr(ufunc, method)(*inputs2, **kwargs) if ufunc.nout > 1: # e.g. np.divmod return tuple(reconstruct(x) for x in result) elif method == "reduce": # e.g. np.add.reduce; test_ufunc_reduce_raises if self._mask.any(): return self._na_value return result else: return reconstruct(result)