summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-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
-rw-r--r--numpy/lib/function_base.py74
-rw-r--r--numpy/lib/stride_tricks.py2
-rw-r--r--numpy/lib/tests/test_function_base.py83
-rw-r--r--numpy/lib/twodim_base.py8
8 files changed, 208 insertions, 9 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)
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py
index efa51173a..a2a24618b 100644
--- a/numpy/lib/function_base.py
+++ b/numpy/lib/function_base.py
@@ -36,7 +36,7 @@ if sys.version_info[0] < 3:
__all__ = [
'select', 'piecewise', 'trim_zeros', 'copy', 'iterable', 'percentile',
- 'diff', 'gradient', 'angle', 'unwrap', 'sort_complex', 'disp',
+ 'diff', 'gradient', 'angle', 'unwrap', 'sort_complex', 'disp', 'flip',
'extract', 'place', 'vectorize', 'asarray_chkfinite', 'average',
'histogram', 'histogramdd', 'bincount', 'digitize', 'cov', 'corrcoef',
'msort', 'median', 'sinc', 'hamming', 'hanning', 'bartlett',
@@ -45,6 +45,78 @@ __all__ = [
]
+def flip(m, axis):
+ """
+ Reverse the order of elements in an array along the given axis.
+
+ The shape of the array is preserved, but the elements are reordered.
+
+ .. versionadded:: 1.12.0
+
+ Parameters
+ ----------
+ m : array_like
+ Input array.
+ axis: integer
+ Axis in array, which entries are reversed.
+
+
+ Returns
+ -------
+ out : array_like
+ A view of `m` with the entries of axis reversed. Since a view is
+ returned, this operation is done in constant time.
+
+ See Also
+ --------
+ flipud : Flip an array vertically (axis=0).
+ fliplr : Flip an array horizontally (axis=1).
+
+ Notes
+ -----
+ flip(m, 0) is equivalent to flipud(m).
+ flip(m, 1) is equivalent to fliplr(m).
+ flip(m, n) corresponds to ``m[...,::-1,...]`` with ``::-1`` at position n.
+
+ Examples
+ --------
+ >>> A = np.arange(8).reshape((2,2,2))
+ >>> A
+ array([[[0, 1],
+ [2, 3]],
+
+ [[4, 5],
+ [6, 7]]])
+
+ >>> flip(A, 0)
+ array([[[4, 5],
+ [6, 7]],
+
+ [[0, 1],
+ [2, 3]]])
+
+ >>> flip(A, 1)
+ array([[[2, 3],
+ [0, 1]],
+
+ [[6, 7],
+ [4, 5]]])
+
+ >>> A = np.random.randn(3,4,5)
+ >>> np.all(flip(A,2) == A[:,:,::-1,...])
+ True
+ """
+ if not hasattr(m, 'ndim'):
+ m = asarray(m)
+ indexer = [slice(None)] * m.ndim
+ try:
+ indexer[axis] = slice(None, None, -1)
+ except IndexError:
+ raise ValueError("axis=%i is invalid for the %i-dimensional input array"
+ % (axis, m.ndim))
+ return m[tuple(indexer)]
+
+
def iterable(y):
"""
Check whether or not an object can be iterated over.
diff --git a/numpy/lib/stride_tricks.py b/numpy/lib/stride_tricks.py
index af09fd373..a87c34fb5 100644
--- a/numpy/lib/stride_tricks.py
+++ b/numpy/lib/stride_tricks.py
@@ -175,7 +175,7 @@ def broadcast_to(array, shape, subok=False):
def _broadcast_shape(*args):
- """Returns the shape of the ararys that would result from broadcasting the
+ """Returns the shape of the arrays that would result from broadcasting the
supplied arrays against each other.
"""
if not args:
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index 943544dd5..91ead0998 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -23,6 +23,89 @@ from numpy.lib import (
from numpy.compat import long
+def get_mat(n):
+ data = np.arange(n)
+ data = np.add.outer(data, data)
+ return data
+
+
+class TestFlip(TestCase):
+ def test_axes(self):
+ self.assertRaises(ValueError, np.flip, np.ones(4), axis=1)
+ self.assertRaises(ValueError, np.flip, np.ones((4, 4)), axis=2)
+ self.assertRaises(ValueError, np.flip, np.ones((4, 4)), axis=-3)
+
+ def test_basic_lr(self):
+ a = get_mat(4)
+ b = a[:, ::-1]
+ assert_equal(np.flip(a, 1), b)
+ a = [[0, 1, 2],
+ [3, 4, 5]]
+ b = [[2, 1, 0],
+ [5, 4, 3]]
+ assert_equal(np.flip(a, 1), b)
+
+ def test_basic_ud(self):
+ a = get_mat(4)
+ b = a[::-1, :]
+ assert_equal(np.flip(a, 0), b)
+ a = [[0, 1, 2],
+ [3, 4, 5]]
+ b = [[3, 4, 5],
+ [0, 1, 2]]
+ assert_equal(np.flip(a, 0), b)
+
+ def test_3d_swap_axis0(self):
+ a = np.array([[[0, 1],
+ [2, 3]],
+
+ [[4, 5],
+ [6, 7]]])
+
+ b = np.array([[[4, 5],
+ [6, 7]],
+
+ [[0, 1],
+ [2, 3]]])
+
+ assert_equal(np.flip(a, 0), b)
+
+ def test_3d_swap_axis1(self):
+ a = np.array([[[0, 1],
+ [2, 3]],
+
+ [[4, 5],
+ [6, 7]]])
+
+ b = np.array([[[2, 3],
+ [0, 1]],
+
+ [[6, 7],
+ [4, 5]]])
+
+ assert_equal(np.flip(a, 1), b)
+
+ def test_3d_swap_axis2(self):
+ a = np.array([[[0, 1],
+ [2, 3]],
+
+ [[4, 5],
+ [6, 7]]])
+
+ b = np.array([[[1, 0],
+ [3, 2]],
+
+ [[5, 4],
+ [7, 6]]])
+
+ assert_equal(np.flip(a, 2), b)
+
+ def test_4d(self):
+ a = np.arange(2 * 3 * 4 * 5).reshape(2, 3, 4, 5)
+ for i in range(a.ndim):
+ assert_equal(np.flip(a, i), np.flipud(a.swapaxes(0, i)).swapaxes(i, 0))
+
+
class TestAny(TestCase):
def test_basic(self):
diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py
index 6728ab7ec..aefe8d64b 100644
--- a/numpy/lib/twodim_base.py
+++ b/numpy/lib/twodim_base.py
@@ -57,7 +57,7 @@ def fliplr(m):
Notes
-----
- Equivalent to A[:,::-1]. Requires the array to be at least 2-D.
+ Equivalent to m[:,::-1]. Requires the array to be at least 2-D.
Examples
--------
@@ -72,7 +72,7 @@ def fliplr(m):
[ 3., 0., 0.]])
>>> A = np.random.randn(2,3,5)
- >>> np.all(np.fliplr(A)==A[:,::-1,...])
+ >>> np.all(np.fliplr(A) == A[:,::-1,...])
True
"""
@@ -107,7 +107,7 @@ def flipud(m):
Notes
-----
- Equivalent to ``A[::-1,...]``.
+ Equivalent to ``m[::-1,...]``.
Does not require the array to be two-dimensional.
Examples
@@ -123,7 +123,7 @@ def flipud(m):
[ 1., 0., 0.]])
>>> A = np.random.randn(2,3,5)
- >>> np.all(np.flipud(A)==A[::-1,...])
+ >>> np.all(np.flipud(A) == A[::-1,...])
True
>>> np.flipud([1,2])