Skip to content

Commit b17c36d

Browse files
committed
ENH: show warning when np.maximum receives more than 2 inputs
1 parent 1d271d5 commit b17c36d

File tree

3 files changed

+41
-11
lines changed

3 files changed

+41
-11
lines changed

numpy/_core/src/umath/ufunc_object.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4289,6 +4289,14 @@ ufunc_generic_fastcall(PyUFuncObject *ufunc,
42894289
{
42904290
int errval;
42914291
int nin = ufunc->nin, nout = ufunc->nout, nop = ufunc->nargs;
4292+
if (strcmp(ufunc->name, "maximum") == 0 &&
4293+
len_args > 2 &&
4294+
(kwnames == NULL || PyTuple_Size(kwnames) == 0)) {
4295+
PyErr_Format(PyExc_TypeError,
4296+
"np.maximum() takes exactly 2 input arguments (%zd given). ",
4297+
len_args);
4298+
return NULL;
4299+
}
42924300

42934301
/* All following variables are cleared in the `fail` error path */
42944302
ufunc_full_args full_args = {NULL, NULL};
@@ -4598,6 +4606,17 @@ static PyObject *
45984606
ufunc_generic_vectorcall(PyObject *ufunc,
45994607
PyObject *const *args, size_t len_args, PyObject *kwnames)
46004608
{
4609+
// Only do this for the maximum ufunc
4610+
if (strcmp(((PyUFuncObject *)ufunc)->name, "maximum") == 0 &&
4611+
len_args < 128 &&
4612+
len_args > 2 &&
4613+
(kwnames == NULL || PyTuple_Size(kwnames)==0)) {
4614+
4615+
PyErr_Format(PyExc_TypeError,
4616+
"np.maximum() takes exactly 2 input arguments (%zd given). ",
4617+
len_args);
4618+
return NULL;
4619+
}
46014620
/*
46024621
* Unlike METH_FASTCALL, `len_args` may have a flag to signal that
46034622
* args[-1] may be (temporarily) used. So normalize it here.

numpy/_core/tests/test_umath.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,7 +2383,7 @@ def test_float_nans(self):
23832383
arg1 = np.array([0, nan, nan])
23842384
arg2 = np.array([nan, 0, nan])
23852385
out = np.array([nan, nan, nan])
2386-
assert_equal(np.maximum(arg1, arg2), out)
2386+
assert_equal(np.maximum(arg1, arg2, out=out), out)
23872387

23882388
def test_object_nans(self):
23892389
# Multiple checks to give this a chance to
@@ -2393,21 +2393,24 @@ def test_object_nans(self):
23932393
x = np.array(float('nan'), object)
23942394
y = 1.0
23952395
z = np.array(float('nan'), object)
2396-
assert_(np.maximum(x, y) == 1.0)
2397-
assert_(np.maximum(z, y) == 1.0)
2396+
out1 = np.empty((), dtype=object)
2397+
out2 = np.empty((), dtype=object)
2398+
assert_(np.maximum(x, y, out=out1) == 1.0)
2399+
assert_(np.maximum(z, y, out=out2) == 1.0)
23982400

23992401
def test_complex_nans(self):
24002402
nan = np.nan
24012403
for cnan in [complex(nan, 0), complex(0, nan), complex(nan, nan)]:
24022404
arg1 = np.array([0, cnan, cnan], dtype=complex)
24032405
arg2 = np.array([cnan, 0, cnan], dtype=complex)
24042406
out = np.array([nan, nan, nan], dtype=complex)
2405-
assert_equal(np.maximum(arg1, arg2), out)
2407+
assert_equal(np.maximum(arg1, arg2, out=out), out)
24062408

24072409
def test_object_array(self):
24082410
arg1 = np.arange(5, dtype=object)
24092411
arg2 = arg1 + 1
2410-
assert_equal(np.maximum(arg1, arg2), arg2)
2412+
out = np.empty_like(arg1)
2413+
assert_equal(np.maximum(arg1, arg2, out=out), arg2)
24112414

24122415
def test_strided_array(self):
24132416
arr1 = np.array([-4.0, 1.0, 10.0, 0.0, np.nan, -np.nan, np.inf, -np.inf])
@@ -2419,7 +2422,12 @@ def test_strided_array(self):
24192422
assert_equal(np.maximum(arr1[::2], arr2[::2]), maxtrue[::2])
24202423
assert_equal(np.maximum(arr1[:4:], arr2[::2]), np.array([-2.0, np.nan, 10.0, 1.0]))
24212424
assert_equal(np.maximum(arr1[::3], arr2[:3:]), np.array([-2.0, 0.0, np.nan]))
2422-
assert_equal(np.maximum(arr1[:6:2], arr2[::3], out=out[::3]), np.array([-2.0, 10., np.nan]))
2425+
2426+
result = np.empty_like(arr1[:6:2])
2427+
np.maximum(arr1[:6:2], arr2[::3], out=result)
2428+
assert_equal(result, np.array([-2.0, 10., np.nan]))
2429+
2430+
np.maximum( arr1[:6:2], arr2[::3], out=out[::3])
24232431
assert_equal(out, out_maxtrue)
24242432

24252433
def test_precision(self):
@@ -2443,6 +2451,9 @@ def test_precision(self):
24432451
assert_equal(np.maximum([v1], [v2]), [expected])
24442452
assert_equal(np.maximum.reduce([v1, v2]), expected)
24452453

2454+
def test_maximum_too_many_args(self):
2455+
with pytest.raises(TypeError, match=r"np\.maximum\(\) takes exactly 2 input arguments \(3 given\)"):
2456+
np.maximum(1, 2, 3)
24462457

24472458
class TestMinimum(_FilterInvalids):
24482459
def test_reduce(self):

numpy/_typing/_ufunc.pyi

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ class _UFunc_Nin2_Nout1(ufunc, Generic[_NameType, _NTypes, _IDType]): # type: i
176176
x1: _ScalarLike_co,
177177
x2: _ScalarLike_co,
178178
/,
179-
out: None = None,
180179
*,
180+
out: None = None,
181181
dtype: DTypeLike | None = None,
182182
**kwds: Unpack[_UFunc3Kwargs],
183183
) -> Any: ...
@@ -187,8 +187,8 @@ class _UFunc_Nin2_Nout1(ufunc, Generic[_NameType, _NTypes, _IDType]): # type: i
187187
x1: ArrayLike,
188188
x2: NDArray[np.generic],
189189
/,
190-
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
191190
*,
191+
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
192192
dtype: DTypeLike | None = None,
193193
**kwds: Unpack[_UFunc3Kwargs],
194194
) -> NDArray[Any]: ...
@@ -198,8 +198,8 @@ class _UFunc_Nin2_Nout1(ufunc, Generic[_NameType, _NTypes, _IDType]): # type: i
198198
x1: NDArray[np.generic],
199199
x2: ArrayLike,
200200
/,
201-
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
202201
*,
202+
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
203203
dtype: DTypeLike | None = None,
204204
**kwds: Unpack[_UFunc3Kwargs],
205205
) -> NDArray[Any]: ...
@@ -209,8 +209,8 @@ class _UFunc_Nin2_Nout1(ufunc, Generic[_NameType, _NTypes, _IDType]): # type: i
209209
x1: ArrayLike,
210210
x2: ArrayLike,
211211
/,
212-
out: NDArray[np.generic] | tuple[NDArray[np.generic]],
213212
*,
213+
out: NDArray[np.generic] | tuple[NDArray[np.generic]],
214214
dtype: DTypeLike | None = None,
215215
**kwds: Unpack[_UFunc3Kwargs],
216216
) -> NDArray[Any]: ...
@@ -220,8 +220,8 @@ class _UFunc_Nin2_Nout1(ufunc, Generic[_NameType, _NTypes, _IDType]): # type: i
220220
x1: ArrayLike,
221221
x2: ArrayLike,
222222
/,
223-
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
224223
*,
224+
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
225225
dtype: DTypeLike | None = None,
226226
**kwds: Unpack[_UFunc3Kwargs],
227227
) -> NDArray[Any] | Any: ...

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy