summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/_internal.py66
-rw-r--r--numpy/core/src/multiarray/calculation.c33
-rw-r--r--numpy/core/tests/test_numeric.py20
-rw-r--r--numpy/tests/test_ctypeslib.py20
4 files changed, 92 insertions, 47 deletions
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py
index 9990bacf0..1cf89aab0 100644
--- a/numpy/core/_internal.py
+++ b/numpy/core/_internal.py
@@ -444,46 +444,46 @@ _pep3118_standard_map = {
}
_pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys())
-def _dtype_from_pep3118(spec):
- class Stream(object):
- def __init__(self, s):
- self.s = s
- self.byteorder = '@'
+class _Stream(object):
+ def __init__(self, s):
+ self.s = s
+ self.byteorder = '@'
- def advance(self, n):
- res = self.s[:n]
- self.s = self.s[n:]
- return res
+ def advance(self, n):
+ res = self.s[:n]
+ self.s = self.s[n:]
+ return res
- def consume(self, c):
- if self.s[:len(c)] == c:
- self.advance(len(c))
- return True
- return False
-
- def consume_until(self, c):
- if callable(c):
- i = 0
- while i < len(self.s) and not c(self.s[i]):
- i = i + 1
- return self.advance(i)
- else:
- i = self.s.index(c)
- res = self.advance(i)
- self.advance(len(c))
- return res
+ def consume(self, c):
+ if self.s[:len(c)] == c:
+ self.advance(len(c))
+ return True
+ return False
- @property
- def next(self):
- return self.s[0]
+ def consume_until(self, c):
+ if callable(c):
+ i = 0
+ while i < len(self.s) and not c(self.s[i]):
+ i = i + 1
+ return self.advance(i)
+ else:
+ i = self.s.index(c)
+ res = self.advance(i)
+ self.advance(len(c))
+ return res
- def __bool__(self):
- return bool(self.s)
- __nonzero__ = __bool__
+ @property
+ def next(self):
+ return self.s[0]
- stream = Stream(spec)
+ def __bool__(self):
+ return bool(self.s)
+ __nonzero__ = __bool__
+
+def _dtype_from_pep3118(spec):
+ stream = _Stream(spec)
dtype, align = __dtype_from_pep3118(stream, is_subdtype=False)
return dtype
diff --git a/numpy/core/src/multiarray/calculation.c b/numpy/core/src/multiarray/calculation.c
index e47dd81b9..90ee2c5b2 100644
--- a/numpy/core/src/multiarray/calculation.c
+++ b/numpy/core/src/multiarray/calculation.c
@@ -5,6 +5,7 @@
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
#include "numpy/arrayobject.h"
+#include "lowlevel_strided_loops.h"
#include "npy_config.h"
@@ -1102,7 +1103,18 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o
if (out == newin) {
outgood = 1;
}
- if (!outgood && PyArray_ISONESEGMENT(out) &&
+
+
+ /* make sure the shape of the output array is the same */
+ if (!PyArray_SAMESHAPE(newin, out)) {
+ PyErr_SetString(PyExc_ValueError, "clip: Output array must have the"
+ "same shape as the input.");
+ goto fail;
+ }
+
+ if (!outgood && PyArray_EQUIVALENTLY_ITERABLE(
+ self, out, PyArray_TRIVIALLY_ITERABLE_OP_READ,
+ PyArray_TRIVIALLY_ITERABLE_OP_NOREAD) &&
PyArray_CHKFLAGS(out, NPY_ARRAY_ALIGNED) &&
PyArray_ISNOTSWAPPED(out) &&
PyArray_EquivTypes(PyArray_DESCR(out), indescr)) {
@@ -1111,15 +1123,19 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o
/*
* Do we still not have a suitable output array?
- * Create one, now
+ * Create one, now. No matter why the array is not suitable a copy has
+ * to be made. This may be just to avoid memory overlap though.
*/
if (!outgood) {
int oflags;
- if (PyArray_ISFORTRAN(out))
+ if (PyArray_ISFORTRAN(self)) {
oflags = NPY_ARRAY_FARRAY;
- else
+ }
+ else {
oflags = NPY_ARRAY_CARRAY;
- oflags |= NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_FORCECAST;
+ }
+ oflags |= (NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_FORCECAST |
+ NPY_ARRAY_ENSURECOPY);
Py_INCREF(indescr);
newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags);
if (newout == NULL) {
@@ -1131,13 +1147,6 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o
Py_INCREF(newout);
}
- /* make sure the shape of the output array is the same */
- if (!PyArray_SAMESHAPE(newin, newout)) {
- PyErr_SetString(PyExc_ValueError, "clip: Output array must have the"
- "same shape as the input.");
- goto fail;
- }
-
/* Now we can call the fast-clip function */
min_data = max_data = NULL;
if (mina != NULL) {
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index 53486dc51..a1a92ef32 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -1530,7 +1530,7 @@ class TestClip(object):
m = -0.5
M = 0.6
self.fastclip(a, m, M, a)
- self.clip(a, m, M, ac)
+ self.clip(ac, m, M, ac)
assert_array_strict_equal(a, ac)
def test_noncontig_inplace(self):
@@ -1543,7 +1543,7 @@ class TestClip(object):
m = -0.5
M = 0.6
self.fastclip(a, m, M, a)
- self.clip(a, m, M, ac)
+ self.clip(ac, m, M, ac)
assert_array_equal(a, ac)
def test_type_cast_01(self):
@@ -1722,6 +1722,22 @@ class TestClip(object):
self.clip(a, m, M, act)
assert_array_strict_equal(ac, act)
+ def test_clip_with_out_transposed(self):
+ # Test that the out argument works when tranposed
+ a = np.arange(16).reshape(4, 4)
+ out = np.empty_like(a).T
+ a.clip(4, 10, out=out)
+ expected = self.clip(a, 4, 10)
+ assert_array_equal(out, expected)
+
+ def test_clip_with_out_memory_overlap(self):
+ # Test that the out argument works when it has memory overlap
+ a = np.arange(16).reshape(4, 4)
+ ac = a.copy()
+ a[:-1].clip(4, 10, out=a[1:])
+ expected = self.clip(ac[:-1], 4, 10)
+ assert_array_equal(a[1:], expected)
+
def test_clip_inplace_array(self):
# Test native double input with array min/max
a = self._generate_data(self.nr, self.nc)
diff --git a/numpy/tests/test_ctypeslib.py b/numpy/tests/test_ctypeslib.py
index 75ce9c8ca..62793a9d6 100644
--- a/numpy/tests/test_ctypeslib.py
+++ b/numpy/tests/test_ctypeslib.py
@@ -170,3 +170,23 @@ class TestAsArray(object):
check(as_array(pointer(c_array), shape=()))
check(as_array(pointer(c_array[0]), shape=(2,)))
check(as_array(pointer(c_array[0][0]), shape=(2, 3)))
+
+ def test_reference_cycles(self):
+ # related to gh-6511
+ import ctypes
+
+ # create array to work with
+ # don't use int/long to avoid running into bpo-10746
+ N = 100
+ a = np.arange(N, dtype=np.short)
+
+ # get pointer to array
+ pnt = np.ctypeslib.as_ctypes(a)
+
+ with np.testing.assert_no_gc_cycles():
+ # decay the array above to a pointer to its first element
+ newpnt = ctypes.cast(pnt, ctypes.POINTER(ctypes.c_short))
+ # and construct an array using this data
+ b = np.ctypeslib.as_array(newpnt, (N,))
+ # now delete both, which should cleanup both objects
+ del newpnt, b