summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/src/multiarray/common.c3
-rw-r--r--numpy/core/src/umath/ufunc_object.c17
-rw-r--r--numpy/core/tests/test_multiarray.py14
-rw-r--r--numpy/core/tests/test_ufunc.py16
4 files changed, 47 insertions, 3 deletions
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index c216daa95..bd566b77b 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -476,6 +476,9 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
* __len__ is not defined.
*/
if (maxdims == 0 || !PySequence_Check(obj) || PySequence_Size(obj) < 0) {
+ // clear any PySequence_Size error, which corrupts further calls to it
+ PyErr_Clear();
+
if (*out_dtype == NULL || (*out_dtype)->type_num != NPY_OBJECT) {
Py_XDECREF(*out_dtype);
*out_dtype = PyArray_DescrFromType(NPY_OBJECT);
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index a472cf9f0..c4a2b8560 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -3270,17 +3270,22 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
NPY_BEGIN_THREADS_NDITER(iter);
do {
-
dataptr_copy[0] = dataptr[0];
dataptr_copy[1] = dataptr[1];
dataptr_copy[2] = dataptr[0];
/* Copy the first element to start the reduction */
if (otype == NPY_OBJECT) {
+ /*
+ * Input (dataptr[0]) and output (dataptr[1]) may point
+ * to the same memory (i.e. np.add.accumulate(a, out=a)).
+ * In that case need to incref before decref to avoid the
+ * possibility of the reference count being zero temporarily.
+ */
+ Py_XINCREF(*(PyObject **)dataptr_copy[1]);
Py_XDECREF(*(PyObject **)dataptr_copy[0]);
*(PyObject **)dataptr_copy[0] =
*(PyObject **)dataptr_copy[1];
- Py_XINCREF(*(PyObject **)dataptr_copy[0]);
}
else {
memcpy(dataptr_copy[0], dataptr_copy[1], itemsize);
@@ -3333,10 +3338,16 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
/* Copy the first element to start the reduction */
if (otype == NPY_OBJECT) {
+ /*
+ * Input (dataptr[0]) and output (dataptr[1]) may point
+ * to the same memory (i.e. np.add.accumulate(a, out=a, axis=0)).
+ * In that case need to incref before decref to avoid the
+ * possibility of the reference count being zero temporarily.
+ */
+ Py_XINCREF(*(PyObject **)dataptr_copy[1]);
Py_XDECREF(*(PyObject **)dataptr_copy[0]);
*(PyObject **)dataptr_copy[0] =
*(PyObject **)dataptr_copy[1];
- Py_XINCREF(*(PyObject **)dataptr_copy[0]);
}
else {
memcpy(dataptr_copy[0], dataptr_copy[1], itemsize);
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index a6c8489ef..14a902b9c 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -716,6 +716,20 @@ class TestCreation(TestCase):
assert_raises(ValueError, np.array, C()) # segfault?
+ def test_failed_len_sequence(self):
+ # gh-7393
+ class A(object):
+ def __init__(self, data):
+ self._data = data
+ def __getitem__(self, item):
+ return type(self)(self._data[item])
+ def __len__(self):
+ return len(self._data)
+
+ # len(d) should give 3, but len(d[0]) will fail
+ d = A([1,2,3])
+ assert_equal(len(np.array(d)), 3)
+
class TestStructured(TestCase):
def test_subarray_field_access(self):
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index eb0985386..ab8cecff0 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -649,6 +649,22 @@ class TestUfunc(TestCase):
assert_equal(np.array([[1]], dtype=object).sum(), 1)
assert_equal(np.array([[[1, 2]]], dtype=object).sum((0, 1)), [1, 2])
+ def test_object_array_accumulate_inplace(self):
+ # Checks that in-place accumulates work, see also gh-7402
+ arr = np.ones(4, dtype=object)
+ arr[:] = [[1] for i in range(4)]
+ # Twice reproduced also for tuples:
+ np.add.accumulate(arr, out=arr)
+ np.add.accumulate(arr, out=arr)
+ assert_array_equal(arr, np.array([[1]*i for i in [1, 3, 6, 10]]))
+
+ # And the same if the axis argument is used
+ arr = np.ones((2, 4), dtype=object)
+ arr[0, :] = [[2] for i in range(4)]
+ np.add.accumulate(arr, out=arr, axis=-1)
+ np.add.accumulate(arr, out=arr, axis=-1)
+ assert_array_equal(arr[0, :], np.array([[2]*i for i in [1, 3, 6, 10]]))
+
def test_object_scalar_multiply(self):
# Tickets #2469 and #4482
arr = np.matrix([1, 2], dtype=object)