summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/_internal.py66
-rw-r--r--numpy/tests/test_ctypeslib.py20
2 files changed, 53 insertions, 33 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/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