Skip to content

Commit aa225b2

Browse files
mzeitlin11simonjayhawkinsjorisvandenbossche
authored
REGR: ufunc with DataFrame input not passing all kwargs (#40878)
Co-authored-by: Simon Hawkins <[email protected]> Co-authored-by: Joris Van den Bossche <[email protected]>
1 parent 58721f7 commit aa225b2

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

doc/source/whatsnew/v1.2.4.rst

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Fixed regressions
2121
- Fixed regression in :meth:`DataFrame.where` not returning a copy in the case of an all True condition (:issue:`39595`)
2222
- Fixed regression in :meth:`DataFrame.replace` raising ``IndexError`` when ``regex`` was a multi-key dictionary (:issue:`39338`)
2323
- Fixed regression in repr of floats in an ``object`` column not respecting ``float_format`` when printed in the console or outputted through :meth:`DataFrame.to_string`, :meth:`DataFrame.to_html`, and :meth:`DataFrame.to_latex` (:issue:`40024`)
24+
- Fixed regression in NumPy ufuncs such as ``np.add`` not passing through all arguments for :class:`DataFrame` (:issue:`40662`)
2425

2526
.. ---------------------------------------------------------------------------
2627

pandas/core/arraylike.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -357,15 +357,17 @@ def reconstruct(result):
357357
# * len(inputs) > 1 is doable when we know that we have
358358
# aligned blocks / dtypes.
359359
inputs = tuple(np.asarray(x) for x in inputs)
360-
result = getattr(ufunc, method)(*inputs)
360+
result = getattr(ufunc, method)(*inputs, **kwargs)
361361
elif self.ndim == 1:
362362
# ufunc(series, ...)
363363
inputs = tuple(extract_array(x, extract_numpy=True) for x in inputs)
364364
result = getattr(ufunc, method)(*inputs, **kwargs)
365365
else:
366366
# ufunc(dataframe)
367-
if method == "__call__":
367+
if method == "__call__" and not kwargs:
368368
# for np.<ufunc>(..) calls
369+
# kwargs cannot necessarily be handled block-by-block, so only
370+
# take this path if there are no kwargs
369371
mgr = inputs[0]._mgr
370372
result = mgr.apply(getattr(ufunc, method))
371373
else:

pandas/tests/frame/test_ufunc.py

+38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import partial
2+
13
import numpy as np
24
import pytest
35

@@ -60,6 +62,42 @@ def test_binary_input_dispatch_binop(dtype):
6062
tm.assert_frame_equal(result, expected)
6163

6264

65+
@pytest.mark.parametrize(
66+
"func,arg,expected",
67+
[
68+
(np.add, 1, [2, 3, 4, 5]),
69+
(
70+
partial(np.add, where=[[False, True], [True, False]]),
71+
np.array([[1, 1], [1, 1]]),
72+
[0, 3, 4, 0],
73+
),
74+
(np.power, np.array([[1, 1], [2, 2]]), [1, 2, 9, 16]),
75+
(np.subtract, 2, [-1, 0, 1, 2]),
76+
(
77+
partial(np.negative, where=np.array([[False, True], [True, False]])),
78+
None,
79+
[0, -2, -3, 0],
80+
),
81+
],
82+
)
83+
def test_ufunc_passes_args(func, arg, expected, request):
84+
# GH#40662
85+
arr = np.array([[1, 2], [3, 4]])
86+
df = pd.DataFrame(arr)
87+
result_inplace = np.zeros_like(arr)
88+
# 1-argument ufunc
89+
if arg is None:
90+
result = func(df, out=result_inplace)
91+
else:
92+
result = func(df, arg, out=result_inplace)
93+
94+
expected = np.array(expected).reshape(2, 2)
95+
tm.assert_numpy_array_equal(result_inplace, expected)
96+
97+
expected = pd.DataFrame(expected)
98+
tm.assert_frame_equal(result, expected)
99+
100+
63101
@pytest.mark.parametrize("dtype_a", dtypes)
64102
@pytest.mark.parametrize("dtype_b", dtypes)
65103
def test_binary_input_aligns_columns(request, dtype_a, dtype_b):

0 commit comments

Comments
 (0)