Skip to content

Commit e4d6fa4

Browse files
committed
ENH: show warning when np.maximum receives more than 2 inputs
1 parent 7d2e441 commit e4d6fa4

File tree

2 files changed

+27
-16
lines changed

2 files changed

+27
-16
lines changed

numpy/_core/src/umath/ufunc_object.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4316,20 +4316,27 @@ ufunc_generic_fastcall(PyUFuncObject *ufunc,
43164316
* Outputs and inputs are stored in `full_args.in` and `full_args.out`
43174317
* as tuples (or NULL when no outputs are passed).
43184318
*/
4319-
43204319
/* Check number of arguments */
4321-
if (NPY_UNLIKELY((len_args < nin) || (len_args > nop))) {
4320+
// 1 Bounds check: common case, fails quickly
4321+
if (NPY_UNLIKELY(len_args < nin) || (len_args > nop)) {
43224322
PyErr_Format(PyExc_TypeError,
4323-
"%s() takes from %d to %d positional arguments but "
4324-
"%zd were given",
4325-
ufunc_get_name_cstr(ufunc) , nin, nop, len_args);
4323+
"%s() takes from %d to %d positional arguments by %zd were given",
4324+
ufunc_get_name_cstr(ufunc), nin, nop, len_args);
43264325
goto fail;
43274326
}
4328-
4329-
/* Fetch input arguments. */
4330-
full_args.in = PyArray_TupleFromItems(ufunc->nin, args, 0);
4331-
if (full_args.in == NULL) {
4332-
goto fail;
4327+
4328+
// 2 Only when there are extra pos args and no keywords
4329+
if (len_args > nin && (kwnames==NULL || PyTuple_Size(kwnames)==0)) {
4330+
// 3 Check if it's the maximum ufunc
4331+
if (strcmp(ufunc->name, "maximum") == 0) {
4332+
PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
4333+
"Passing more than 2 positional arguments to np.maximum "
4334+
"is deprecaated; use out=keywords or np.maximum.reduce.");
4335+
PyErr_Format(PyExc_TypeError,
4336+
"np.maximum() takes exactly 2 input arguments (%zd given).",
4337+
len_args);
4338+
goto fail;
4339+
}
43334340
}
43344341

43354342
/*
@@ -4598,12 +4605,12 @@ static PyObject *
45984605
ufunc_generic_vectorcall(PyObject *ufunc,
45994606
PyObject *const *args, size_t len_args, PyObject *kwnames)
46004607
{
4601-
/*
4602-
* Unlike METH_FASTCALL, `len_args` may have a flag to signal that
4603-
* args[-1] may be (temporarily) used. So normalize it here.
4604-
*/
4605-
return ufunc_generic_fastcall((PyUFuncObject *)ufunc,
4606-
args, PyVectorcall_NARGS(len_args), kwnames, NPY_FALSE);
4608+
return ufunc_generic_fastcall(
4609+
(PyUFuncObject *)ufunc,
4610+
args,
4611+
PyVectorcall_NARGS(len_args),
4612+
kwnames,
4613+
NPY_FALSE);
46074614
}
46084615

46094616

numpy/_core/tests/test_umath.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2420,6 +2420,7 @@ def test_strided_array(self):
24202420
assert_equal(np.maximum(arr1[:4:], arr2[::2]), np.array([-2.0, np.nan, 10.0, 1.0]))
24212421
assert_equal(np.maximum(arr1[::3], arr2[:3:]), np.array([-2.0, 0.0, np.nan]))
24222422
assert_equal(np.maximum(arr1[:6:2], arr2[::3], out=out[::3]), np.array([-2.0, 10., np.nan]))
2423+
24232424
assert_equal(out, out_maxtrue)
24242425

24252426
def test_precision(self):
@@ -2443,6 +2444,9 @@ def test_precision(self):
24432444
assert_equal(np.maximum([v1], [v2]), [expected])
24442445
assert_equal(np.maximum.reduce([v1, v2]), expected)
24452446

2447+
def test_maximum_too_many_args(self):
2448+
with pytest.raises(TypeError, match=r"np\.maximum\(\) takes exactly 2 input arguments \(3 given\)"):
2449+
np.maximum(1, 2, 3)
24462450

24472451
class TestMinimum(_FilterInvalids):
24482452
def test_reduce(self):

0 commit comments

Comments
 (0)