summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/umath/override.c4
-rw-r--r--numpy/core/src/umath/ufunc_object.c18
-rw-r--r--numpy/core/tests/test_multiarray.py2
-rw-r--r--numpy/core/tests/test_umath.py92
4 files changed, 94 insertions, 22 deletions
diff --git a/numpy/core/src/umath/override.c b/numpy/core/src/umath/override.c
index a899b0bd0..66fb759a4 100644
--- a/numpy/core/src/umath/override.c
+++ b/numpy/core/src/umath/override.c
@@ -366,11 +366,11 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method,
if (out != NULL) {
int nout = ufunc->nout;
- if (PyTuple_Check(out)) {
+ if (PyTuple_CheckExact(out)) {
int all_none = 1;
if (PyTuple_GET_SIZE(out) != nout) {
- PyErr_Format(PyExc_TypeError,
+ PyErr_Format(PyExc_ValueError,
"The 'out' tuple must have exactly "
"%d entries: one per ufunc output", nout);
goto fail;
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index e1219039c..ea99560ea 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -1084,7 +1084,7 @@ get_ufunc_arguments(PyUFuncObject *ufunc,
"positional and keyword argument");
goto fail;
}
- if (PyTuple_Check(value)) {
+ if (PyTuple_CheckExact(value)) {
if (PyTuple_GET_SIZE(value) != nout) {
PyErr_SetString(PyExc_ValueError,
"The 'out' tuple must have exactly "
@@ -3894,6 +3894,7 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args,
PyObject *obj_ind, *context;
PyArrayObject *indices = NULL;
PyArray_Descr *otype = NULL;
+ PyObject *out_obj = NULL;
PyArrayObject *out = NULL;
int keepdims = 0;
static char *reduce_kwlist[] = {
@@ -3927,7 +3928,20 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args,
_reduce_type[operation]);
return NULL;
}
-
+ /* if there is a tuple of 1 for `out` in kwds, unpack it */
+ if (kwds != NULL) {
+ PyObject *out_obj = PyDict_GetItem(kwds, npy_um_str_out);
+ if (out_obj != NULL && PyTuple_CheckExact(out_obj)) {
+ if (PyTuple_GET_SIZE(out_obj) != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "The 'out' tuple must have exactly one entry");
+ return NULL;
+ }
+ out_obj = PyTuple_GET_ITEM(out_obj, 0);
+ PyDict_SetItem(kwds, npy_um_str_out, out_obj);
+ }
+ }
+
if (operation == UFUNC_REDUCEAT) {
PyArray_Descr *indtype;
indtype = PyArray_DescrFromType(NPY_INTP);
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 835d03528..2b25d478e 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -3107,7 +3107,7 @@ class TestBinop(object):
warnings.filterwarnings('always', '', DeprecationWarning)
assert_equal(np.modf(dummy, out=a), (0,))
assert_(w[0].category is DeprecationWarning)
- assert_raises(TypeError, np.modf, dummy, out=(a,))
+ assert_raises(ValueError, np.modf, dummy, out=(a,))
# 2 inputs, 1 output
assert_equal(np.add(a, dummy), 0)
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 32969bc68..120844c82 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -1765,8 +1765,8 @@ class TestSpecialMethods(TestCase):
assert_equal(res[4], {'axis': None, 'dtype': None})
# reduce, wrong args
- assert_raises(TypeError, np.multiply.reduce, a, out=())
- assert_raises(TypeError, np.multiply.reduce, a, out=('out0', 'out1'))
+ assert_raises(ValueError, np.multiply.reduce, a, out=())
+ assert_raises(ValueError, np.multiply.reduce, a, out=('out0', 'out1'))
assert_raises(TypeError, np.multiply.reduce, a, 'axis0', axis='axis0')
# accumulate, pos args
@@ -1799,8 +1799,8 @@ class TestSpecialMethods(TestCase):
assert_equal(res[4], {'axis': None, 'dtype': None})
# accumulate, wrong args
- assert_raises(TypeError, np.multiply.accumulate, a, out=())
- assert_raises(TypeError, np.multiply.accumulate, a,
+ assert_raises(ValueError, np.multiply.accumulate, a, out=())
+ assert_raises(ValueError, np.multiply.accumulate, a,
out=('out0', 'out1'))
assert_raises(TypeError, np.multiply.accumulate, a,
'axis0', axis='axis0')
@@ -1835,8 +1835,8 @@ class TestSpecialMethods(TestCase):
assert_equal(res[4], {'axis': None, 'dtype': None})
# reduceat, wrong args
- assert_raises(TypeError, np.multiply.reduce, a, [4, 2], out=())
- assert_raises(TypeError, np.multiply.reduce, a, [4, 2],
+ assert_raises(ValueError, np.multiply.reduce, a, [4, 2], out=())
+ assert_raises(ValueError, np.multiply.reduce, a, [4, 2],
out=('out0', 'out1'))
assert_raises(TypeError, np.multiply.reduce, a, [4, 2],
'axis0', axis='axis0')
@@ -1914,12 +1914,12 @@ class TestSpecialMethods(TestCase):
# wrong number of arguments in the tuple is an error too.
assert_raises(TypeError, np.multiply, a, b, 'one', out='two')
assert_raises(TypeError, np.multiply, a, b, 'one', 'two')
- assert_raises(TypeError, np.multiply, a, b, out=('one', 'two'))
- assert_raises(TypeError, np.multiply, a, out=())
+ assert_raises(ValueError, np.multiply, a, b, out=('one', 'two'))
+ assert_raises(ValueError, np.multiply, a, out=())
assert_raises(TypeError, np.modf, a, 'one', out=('two', 'three'))
assert_raises(TypeError, np.modf, a, 'one', 'two', 'three')
- assert_raises(TypeError, np.modf, a, out=('one', 'two', 'three'))
- assert_raises(TypeError, np.modf, a, out=('one',))
+ assert_raises(ValueError, np.modf, a, out=('one', 'two', 'three'))
+ assert_raises(ValueError, np.modf, a, out=('one',))
def test_ufunc_override_exception(self):
@@ -2006,8 +2006,8 @@ class TestSpecialMethods(TestCase):
assert_raises(TypeError, inner1d, a, out='two')
assert_raises(TypeError, inner1d, a, a, 'one', out='two')
assert_raises(TypeError, inner1d, a, a, 'one', 'two')
- assert_raises(TypeError, inner1d, a, a, out=('one', 'two'))
- assert_raises(TypeError, inner1d, a, a, out=())
+ assert_raises(ValueError, inner1d, a, a, out=('one', 'two'))
+ assert_raises(ValueError, inner1d, a, a, out=())
def test_ufunc_override_with_super(self):
@@ -2048,6 +2048,8 @@ class TestSpecialMethods(TestCase):
return NotImplemented
if method == 'at':
+ if isinstance(inputs[0], A):
+ inputs[0].info = info
return
if ufunc.nout == 1:
@@ -2114,14 +2116,70 @@ class TestSpecialMethods(TestCase):
assert_(a.__array_ufunc__(np.add, '__call__', a, b) is NotImplemented)
assert_(b.__array_ufunc__(np.add, '__call__', a, b) == "A!")
assert_(np.add(a, b) == "A!")
- # regression check for gh-9102
- a = np.array([[1, 2, 3], [1, 2, 3]]).view(A)
+ # regression check for gh-9102 -- tests ufunc.reduce implicitly.
+ d = np.array([[1, 2, 3], [1, 2, 3]])
+ a = d.view(A)
+ c = a.any()
+ check = d.any()
+ assert_equal(c, check)
+ assert_(c.info, {'inputs': [0]})
c = a.max()
- assert_equal(c, 3)
+ check = d.max()
+ assert_equal(c, check)
assert_(c.info, {'inputs': [0]})
- c = a.any()
- assert_equal(c, True)
+ b = np.array(0).view(A)
+ c = a.max(out=b)
+ assert_equal(c, check)
+ assert_(c is b)
+ assert_(c.info, {'inputs': [0], 'outputs': [0]})
+ check = a.max(axis=0)
+ b = np.zeros_like(check).view(A)
+ c = a.max(axis=0, out=b)
+ assert_equal(c, check)
+ assert_(c is b)
+ assert_(c.info, {'inputs': [0], 'outputs': [0]})
+ # simple explicit tests of reduce, accumulate, reduceat
+ check = np.add.reduce(d, axis=1)
+ c = np.add.reduce(a, axis=1)
+ assert_equal(c, check)
+ assert_(c.info, {'inputs': [0]})
+ b = np.zeros_like(c)
+ c = np.add.reduce(a, 1, None, b)
+ assert_equal(c, check)
+ assert_(c is b)
+ assert_(c.info, {'inputs': [0], 'outputs': [0]})
+ check = np.add.accumulate(d, axis=0)
+ c = np.add.accumulate(a, axis=0)
+ assert_equal(c, check)
+ assert_(c.info, {'inputs': [0]})
+ b = np.zeros_like(c)
+ c = np.add.accumulate(a, 0, None, b)
+ assert_equal(c, check)
+ assert_(c is b)
+ assert_(c.info, {'inputs': [0], 'outputs': [0]})
+ indices = [0, 2, 1]
+ check = np.add.reduceat(d, indices, axis=1)
+ c = np.add.reduceat(a, indices, axis=1)
+ assert_equal(c, check)
assert_(c.info, {'inputs': [0]})
+ b = np.zeros_like(c)
+ c = np.add.reduceat(a, indices, 1, None, b)
+ assert_equal(c, check)
+ assert_(c is b)
+ assert_(c.info, {'inputs': [0], 'outputs': [0]})
+ # and a few tests for at
+ d = np.array([[1, 2, 3], [1, 2, 3]])
+ check = d.copy()
+ a = d.copy().view(A)
+ np.add.at(check, ([0, 1], [0, 2]), 1.)
+ np.add.at(a, ([0, 1], [0, 2]), 1.)
+ assert_equal(a, check)
+ assert_(a.info, {'inputs': [0]})
+ b = np.array(1.).view(A)
+ a = d.copy().view(A)
+ np.add.at(a, ([0, 1], [0, 2]), b)
+ assert_equal(a, check)
+ assert_(a.info, {'inputs': [0, 2]})
class TestChoose(TestCase):