summaryrefslogtreecommitdiff
path: root/tests/memoryview
diff options
context:
space:
mode:
Diffstat (limited to 'tests/memoryview')
-rw-r--r--tests/memoryview/cfunc_convert_with_memoryview.pyx51
-rw-r--r--tests/memoryview/cythonarray.pyx115
-rw-r--r--tests/memoryview/error_declarations.pyx18
-rw-r--r--tests/memoryview/memoryview.pyx179
-rw-r--r--tests/memoryview/memoryview_acq_count.srctree2
-rw-r--r--tests/memoryview/memoryview_annotation_typing.py68
-rw-r--r--tests/memoryview/memoryview_cache_builtins.srctree21
-rw-r--r--tests/memoryview/memoryview_no_binding_T3613.pyx21
-rw-r--r--tests/memoryview/memoryview_no_withgil_check.pyx11
-rw-r--r--tests/memoryview/memoryview_pep484_typing.pyx (renamed from tests/memoryview/memoryview_pep489_typing.pyx)2
-rw-r--r--tests/memoryview/memoryviewattrs.pyx22
-rw-r--r--tests/memoryview/memslice.pyx126
-rw-r--r--tests/memoryview/numpy_memoryview.pyx77
-rw-r--r--tests/memoryview/relaxed_strides.pyx14
-rw-r--r--tests/memoryview/view_return_errors.pyx26
15 files changed, 630 insertions, 123 deletions
diff --git a/tests/memoryview/cfunc_convert_with_memoryview.pyx b/tests/memoryview/cfunc_convert_with_memoryview.pyx
new file mode 100644
index 000000000..55bd02205
--- /dev/null
+++ b/tests/memoryview/cfunc_convert_with_memoryview.pyx
@@ -0,0 +1,51 @@
+# mode: run
+# tag: autowrap
+# cython: always_allow_keywords=True
+
+cdef void memoryview_func_a(double [:] x):
+ x[0] = 1
+
+cdef void memoryview_func_b(double [::1] x):
+ x[0] = 2
+
+cdef void memoryview_func_c(int [:] x):
+ x[0] = 1
+
+cdef void memoryview_func_d(int [:] x):
+ x[0] = 2
+
+cdef void memoryview_func_e(int [:,::1] x):
+ x[0,0] = 4
+
+cdef void memoryview_func_f(int [::1,:] x):
+ x[0,0] = 4
+
+
+def test_memview_wrapping():
+ """
+ We're mainly concerned that the code compiles without the names clashing
+ >>> test_memview_wrapping()
+ 1.0
+ 2.0
+ 1
+ 2
+ """
+ cdef a = memoryview_func_a
+ cdef b = memoryview_func_b
+ cdef c = memoryview_func_c
+ cdef d = memoryview_func_d
+ cdef e = memoryview_func_e
+ cdef f = memoryview_func_f
+ cdef double[1] double_arr = [0]
+ cdef int[1] int_arr = [0]
+
+ a(<double[:1]> double_arr)
+ print(double_arr[0])
+ b(<double[:1:1]> double_arr)
+ print(double_arr[0])
+ c(<int[:1]> int_arr)
+ print(int_arr[0])
+ d(<int[:1:1]> int_arr)
+ print(int_arr[0])
+ # don't call e and f because it's harder without needing extra dependencies
+ # it's mostly a compile test for them
diff --git a/tests/memoryview/cythonarray.pyx b/tests/memoryview/cythonarray.pyx
index 83ff09754..15d61d086 100644
--- a/tests/memoryview/cythonarray.pyx
+++ b/tests/memoryview/cythonarray.pyx
@@ -130,7 +130,7 @@ cdef int *getp(int dim1=10, int dim2=10, dim3=1) except NULL:
return p
-cdef void callback_free_data(void *p):
+cdef void callback_free_data(void *p) noexcept:
print 'callback free data called'
free(p)
@@ -209,3 +209,116 @@ def test_cyarray_from_carray():
mslice = a
print mslice[0, 0], mslice[1, 0], mslice[2, 5]
+
+class InheritFrom(v.array):
+ """
+ Test is just to confirm it works, not to do anything meaningful with it
+ (Be aware that itemsize isn't necessarily right)
+ >>> inst = InheritFrom(shape=(3, 3, 3), itemsize=4, format="i")
+ """
+ pass
+
+
+def test_char_array_in_python_api(*shape):
+ """
+ >>> import sys
+ >>> if sys.version_info[0] < 3:
+ ... def bytes(b): return memoryview(b).tobytes() # don't call str()
+
+ >>> arr1d = test_char_array_in_python_api(10)
+ >>> print(bytes(arr1d).decode('ascii'))
+ xxxxxxxxxx
+ >>> len(bytes(arr1d))
+ 10
+ >>> arr2d = test_char_array_in_python_api(10, 2)
+ >>> print(bytes(arr2d).decode('ascii'))
+ xxxxxxxxxxxxxxxxxxxx
+ >>> len(bytes(arr2d))
+ 20
+
+ # memoryview
+ >>> len(bytes(memoryview(arr1d)))
+ 10
+ >>> bytes(memoryview(arr1d)) == bytes(arr1d)
+ True
+ >>> len(bytes(memoryview(arr2d)))
+ 20
+ >>> bytes(memoryview(arr2d)) == bytes(arr2d)
+ True
+
+ # BytesIO
+ >>> from io import BytesIO
+ >>> BytesIO(arr1d).read() == bytes(arr1d)
+ True
+ >>> BytesIO(arr2d).read() == bytes(arr2d)
+ True
+
+ >>> b = BytesIO()
+ >>> print(b.write(arr1d))
+ 10
+ >>> b.getvalue() == bytes(arr1d) or b.getvalue()
+ True
+
+ >>> b = BytesIO()
+ >>> print(b.write(arr2d))
+ 20
+ >>> b.getvalue() == bytes(arr2d) or b.getvalue()
+ True
+
+ # BufferedWriter (uses PyBUF_SIMPLE, see https://github.com/cython/cython/issues/3775)
+ >>> from io import BufferedWriter
+ >>> b = BytesIO()
+ >>> bw = BufferedWriter(b)
+ >>> print(bw.write(arr1d))
+ 10
+ >>> bw.flush()
+ >>> b.getvalue() == bytes(arr1d)
+ True
+
+ >>> b = BytesIO()
+ >>> bw = BufferedWriter(b)
+ >>> print(bw.write(arr2d))
+ 20
+ >>> bw.flush()
+ >>> b.getvalue() == bytes(arr2d)
+ True
+ """
+ arr = array(shape=shape, itemsize=sizeof(char), format='c', mode='c')
+ arr[:] = b'x'
+ return arr
+
+def test_is_Sequence():
+ """
+ >>> test_is_Sequence()
+ 1
+ 1
+ True
+ """
+ import sys
+ if sys.version_info < (3, 3):
+ from collections import Sequence
+ else:
+ from collections.abc import Sequence
+
+ arr = array(shape=(5,), itemsize=sizeof(char), format='c', mode='c')
+ for i in range(arr.shape[0]):
+ arr[i] = f'{i}'.encode('ascii')
+ print(arr.count(b'1')) # test for presence of added collection method
+ print(arr.index(b'1')) # test for presence of added collection method
+
+ if sys.version_info >= (3, 10):
+ # test structural pattern match in Python
+ # (because Cython hasn't implemented it yet, and because the details
+ # of what Python considers a sequence are important)
+ globs = {'arr': arr}
+ exec("""
+match arr:
+ case [*_]:
+ res = True
+ case _:
+ res = False
+""", globs)
+ assert globs['res']
+
+ return isinstance(arr, Sequence)
+
diff --git a/tests/memoryview/error_declarations.pyx b/tests/memoryview/error_declarations.pyx
index 0f6c52043..8c4f12a56 100644
--- a/tests/memoryview/error_declarations.pyx
+++ b/tests/memoryview/error_declarations.pyx
@@ -73,24 +73,24 @@ _ERRORS = u'''
13:19: Step must be omitted, 1, or a valid specifier.
14:20: Step must be omitted, 1, or a valid specifier.
15:20: Step must be omitted, 1, or a valid specifier.
-16:17: Start must not be given.
-17:18: Start must not be given.
+16:15: Start must not be given.
+17:17: Start must not be given.
18:22: Axis specification only allowed in the 'step' slot.
-19:19: Fortran contiguous specifier must follow an indirect dimension
+19:18: Fortran contiguous specifier must follow an indirect dimension
20:22: Invalid axis specification.
21:19: Invalid axis specification.
22:22: no expressions allowed in axis spec, only names and literals.
25:37: Memoryview 'object[::1, :]' not conformable to memoryview 'object[:, ::1]'.
28:17: Different base types for memoryviews (int, Python object)
-31:9: Dimension may not be contiguous
-37:9: Only one direct contiguous axis may be specified.
-38:9:Only dimensions 3 and 2 may be contiguous and direct
-44:10: Invalid base type for memoryview slice: intp
+31:8: Dimension may not be contiguous
+37:8: Only one direct contiguous axis may be specified.
+38:8:Only dimensions 3 and 2 may be contiguous and direct
+44:9: Invalid base type for memoryview slice: intp
46:35: Can only create cython.array from pointer or array
47:24: Cannot assign type 'double' to 'Py_ssize_t'
-55:13: Invalid base type for memoryview slice: Invalid
+55:12: Invalid base type for memoryview slice: Invalid
58:6: More dimensions than the maximum number of buffer dimensions were used.
59:6: More dimensions than the maximum number of buffer dimensions were used.
-61:9: More dimensions than the maximum number of buffer dimensions were used.
+61:8: More dimensions than the maximum number of buffer dimensions were used.
64:13: Cannot take address of memoryview slice
'''
diff --git a/tests/memoryview/memoryview.pyx b/tests/memoryview/memoryview.pyx
index 15c71d481..344d11840 100644
--- a/tests/memoryview/memoryview.pyx
+++ b/tests/memoryview/memoryview.pyx
@@ -1,5 +1,7 @@
# mode: run
+# Test declarations, behaviour and coercions of the memoryview type itself.
+
u'''
>>> f()
>>> g()
@@ -155,6 +157,7 @@ def assignmvs():
cdef int[:] mv3
mv1 = array((10,), itemsize=sizeof(int), format='i')
mv2 = mv1
+ mv1 = mv1
mv1 = mv2
mv3 = mv2
@@ -247,7 +250,7 @@ def basic_struct(MyStruct[:] mslice):
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ccqii"))
[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
"""
- buf = mslice
+ cdef object buf = mslice
print sorted([(k, int(v)) for k, v in buf[0].items()])
def nested_struct(NestedStruct[:] mslice):
@@ -259,7 +262,7 @@ def nested_struct(NestedStruct[:] mslice):
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{ii}T{2i}i"))
1 2 3 4 5
"""
- buf = mslice
+ cdef object buf = mslice
d = buf[0]
print d['x']['a'], d['x']['b'], d['y']['a'], d['y']['b'], d['z']
@@ -275,7 +278,7 @@ def packed_struct(PackedStruct[:] mslice):
1 2
"""
- buf = mslice
+ cdef object buf = mslice
print buf[0]['a'], buf[0]['b']
def nested_packed_struct(NestedPackedStruct[:] mslice):
@@ -289,7 +292,7 @@ def nested_packed_struct(NestedPackedStruct[:] mslice):
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="^c@i^ci@i"))
1 2 3 4 5
"""
- buf = mslice
+ cdef object buf = mslice
d = buf[0]
print d['a'], d['b'], d['sub']['a'], d['sub']['b'], d['c']
@@ -299,7 +302,7 @@ def complex_dtype(long double complex[:] mslice):
>>> complex_dtype(LongComplexMockBuffer(None, [(0, -1)]))
-1j
"""
- buf = mslice
+ cdef object buf = mslice
print buf[0]
def complex_inplace(long double complex[:] mslice):
@@ -307,7 +310,7 @@ def complex_inplace(long double complex[:] mslice):
>>> complex_inplace(LongComplexMockBuffer(None, [(0, -1)]))
(1+1j)
"""
- buf = mslice
+ cdef object buf = mslice
buf[0] = buf[0] + 1 + 2j
print buf[0]
@@ -318,7 +321,7 @@ def complex_struct_dtype(LongComplex[:] mslice):
>>> complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)]))
0.0 -1.0
"""
- buf = mslice
+ cdef object buf = mslice
print buf[0]['real'], buf[0]['imag']
#
@@ -356,7 +359,7 @@ def get_int_2d(int[:, :] mslice, int i, int j):
...
IndexError: Out of bounds on buffer access (axis 1)
"""
- buf = mslice
+ cdef object buf = mslice
return buf[i, j]
def set_int_2d(int[:, :] mslice, int i, int j, int value):
@@ -409,11 +412,50 @@ def set_int_2d(int[:, :] mslice, int i, int j, int value):
IndexError: Out of bounds on buffer access (axis 1)
"""
- buf = mslice
+ cdef object buf = mslice
buf[i, j] = value
#
+# auto type inference
+# (note that for most numeric types "might_overflow" stops the type inference from working well)
+#
+def type_infer(double[:, :] arg):
+ """
+ >>> type_infer(DoubleMockBuffer(None, range(6), (2,3)))
+ double
+ double[:]
+ double[:]
+ double[:, :]
+ """
+ a = arg[0,0]
+ print(cython.typeof(a))
+ b = arg[0]
+ print(cython.typeof(b))
+ c = arg[0,:]
+ print(cython.typeof(c))
+ d = arg[:,:]
+ print(cython.typeof(d))
+
+#
+# Loop optimization
+#
+@cython.test_fail_if_path_exists("//CoerceToPyTypeNode")
+def memview_iter(double[:, :] arg):
+ """
+ >>> memview_iter(DoubleMockBuffer("C", range(6), (2,3)))
+ acquired C
+ released C
+ True
+ """
+ cdef double total = 0
+ for mview1d in arg:
+ for val in mview1d:
+ total += val
+ if total == 15:
+ return True
+
+#
# Test all kinds of indexing and flags
#
@@ -426,7 +468,7 @@ def writable(unsigned short int[:, :, :] mslice):
>>> [str(x) for x in R.received_flags] # Py2/3
['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
"""
- buf = mslice
+ cdef object buf = mslice
buf[2, 2, 1] = 23
def strided(int[:] mslice):
@@ -441,7 +483,7 @@ def strided(int[:] mslice):
>>> A.release_ok
True
"""
- buf = mslice
+ cdef object buf = mslice
return buf[2]
def c_contig(int[::1] mslice):
@@ -450,7 +492,7 @@ def c_contig(int[::1] mslice):
>>> c_contig(A)
2
"""
- buf = mslice
+ cdef object buf = mslice
return buf[2]
def c_contig_2d(int[:, ::1] mslice):
@@ -461,7 +503,7 @@ def c_contig_2d(int[:, ::1] mslice):
>>> c_contig_2d(A)
7
"""
- buf = mslice
+ cdef object buf = mslice
return buf[1, 3]
def f_contig(int[::1, :] mslice):
@@ -470,7 +512,7 @@ def f_contig(int[::1, :] mslice):
>>> f_contig(A)
2
"""
- buf = mslice
+ cdef object buf = mslice
return buf[0, 1]
def f_contig_2d(int[::1, :] mslice):
@@ -481,7 +523,7 @@ def f_contig_2d(int[::1, :] mslice):
>>> f_contig_2d(A)
7
"""
- buf = mslice
+ cdef object buf = mslice
return buf[3, 1]
def generic(int[::view.generic, ::view.generic] mslice1,
@@ -552,7 +594,7 @@ def printbuf_td_cy_int(td_cy_int[:] mslice, shape):
...
ValueError: Buffer dtype mismatch, expected 'td_cy_int' but got 'short'
"""
- buf = mslice
+ cdef object buf = mslice
cdef int i
for i in range(shape[0]):
print buf[i],
@@ -567,7 +609,7 @@ def printbuf_td_h_short(td_h_short[:] mslice, shape):
...
ValueError: Buffer dtype mismatch, expected 'td_h_short' but got 'int'
"""
- buf = mslice
+ cdef object buf = mslice
cdef int i
for i in range(shape[0]):
print buf[i],
@@ -582,7 +624,7 @@ def printbuf_td_h_cy_short(td_h_cy_short[:] mslice, shape):
...
ValueError: Buffer dtype mismatch, expected 'td_h_cy_short' but got 'int'
"""
- buf = mslice
+ cdef object buf = mslice
cdef int i
for i in range(shape[0]):
print buf[i],
@@ -597,7 +639,7 @@ def printbuf_td_h_ushort(td_h_ushort[:] mslice, shape):
...
ValueError: Buffer dtype mismatch, expected 'td_h_ushort' but got 'short'
"""
- buf = mslice
+ cdef object buf = mslice
cdef int i
for i in range(shape[0]):
print buf[i],
@@ -612,7 +654,7 @@ def printbuf_td_h_double(td_h_double[:] mslice, shape):
...
ValueError: Buffer dtype mismatch, expected 'td_h_double' but got 'float'
"""
- buf = mslice
+ cdef object buf = mslice
cdef int i
for i in range(shape[0]):
print buf[i],
@@ -626,6 +668,8 @@ def addref(*args):
def decref(*args):
for item in args: Py_DECREF(item)
+@cython.binding(False)
+@cython.always_allow_keywords(False)
def get_refcount(x):
return (<PyObject*>x).ob_refcnt
@@ -647,7 +691,7 @@ def printbuf_object(object[:] mslice, shape):
{4: 23} 2
[34, 3] 2
"""
- buf = mslice
+ cdef object buf = mslice
cdef int i
for i in range(shape[0]):
print repr(buf[i]), (<PyObject*>buf[i]).ob_refcnt
@@ -668,7 +712,7 @@ def assign_to_object(object[:] mslice, int idx, obj):
(2, 3)
>>> decref(b)
"""
- buf = mslice
+ cdef object buf = mslice
buf[idx] = obj
def assign_temporary_to_object(object[:] mslice):
@@ -695,7 +739,7 @@ def assign_temporary_to_object(object[:] mslice):
>>> assign_to_object(A, 1, a)
>>> decref(a)
"""
- buf = mslice
+ cdef object buf = mslice
buf[1] = {3-2: 2+(2*4)-2}
@@ -743,7 +787,7 @@ def test_generic_slicing(arg, indirect=False):
"""
cdef int[::view.generic, ::view.generic, :] _a = arg
- a = _a
+ cdef object a = _a
b = a[2:8:2, -4:1:-1, 1:3]
print b.shape
@@ -826,7 +870,7 @@ def test_direct_slicing(arg):
released A
"""
cdef int[:, :, :] _a = arg
- a = _a
+ cdef object a = _a
b = a[2:8:2, -4:1:-1, 1:3]
print b.shape
@@ -854,7 +898,7 @@ def test_slicing_and_indexing(arg):
released A
"""
cdef int[:, :, :] _a = arg
- a = _a
+ cdef object a = _a
b = a[-5:, 1, 1::2]
c = b[4:1:-1, ::-1]
d = c[2, 1:2]
@@ -1099,7 +1143,7 @@ def optimised_index_of_slice(int[:,:,:] arr, int x, int y, int z):
def test_assign_from_byteslike(byteslike):
- # Once http://python3statement.org is accepted, should be just
+ # Once https://python3statement.org/ is accepted, should be just
# >>> test_assign_from_byteslike(bytes(b'hello'))
# b'hello'
# ...
@@ -1130,3 +1174,84 @@ def test_assign_from_byteslike(byteslike):
return (<unsigned char*>buf)[:5]
finally:
free(buf)
+
+def multiple_memoryview_def(double[:] a, double[:] b):
+ return a[0] + b[0]
+
+cpdef multiple_memoryview_cpdef(double[:] a, double[:] b):
+ return a[0] + b[0]
+
+cdef multiple_memoryview_cdef(double[:] a, double[:] b):
+ return a[0] + b[0]
+
+multiple_memoryview_cdef_wrapper = multiple_memoryview_cdef
+
+def test_conversion_failures():
+ """
+ What we're concerned with here is that we don't lose references if one
+ of several memoryview arguments fails to convert.
+
+ >>> test_conversion_failures()
+ """
+ imb = IntMockBuffer("", range(1), shape=(1,))
+ dmb = DoubleMockBuffer("", range(1), shape=(1,))
+ for first, second in [(imb, dmb), (dmb, imb)]:
+ for func in [multiple_memoryview_def, multiple_memoryview_cpdef, multiple_memoryview_cdef_wrapper]:
+ # note - using python call of "multiple_memoryview_cpdef" deliberately
+ imb_before = get_refcount(imb)
+ dmb_before = get_refcount(dmb)
+ try:
+ func(first, second)
+ except:
+ assert get_refcount(imb) == imb_before, "before %s after %s" % (imb_before, get_refcount(imb))
+ assert get_refcount(dmb) == dmb_before, "before %s after %s" % (dmb_before, get_refcount(dmb))
+ else:
+ assert False, "Conversion should fail!"
+
+def test_is_Sequence(double[:] a):
+ """
+ >>> test_is_Sequence(DoubleMockBuffer(None, range(6), shape=(6,)))
+ 1
+ 1
+ True
+ """
+ if sys.version_info < (3, 3):
+ from collections import Sequence
+ else:
+ from collections.abc import Sequence
+
+ for i in range(a.shape[0]):
+ a[i] = i
+ print(a.count(1.0)) # test for presence of added collection method
+ print(a.index(1.0)) # test for presence of added collection method
+
+ if sys.version_info >= (3, 10):
+ # test structural pattern match in Python
+ # (because Cython hasn't implemented it yet, and because the details
+ # of what Python considers a sequence are important)
+ globs = {'arr': a}
+ exec("""
+match arr:
+ case [*_]:
+ res = True
+ case _:
+ res = False
+""", globs)
+ assert globs['res']
+
+ return isinstance(<object>a, Sequence)
+
+
+ctypedef int aliasT
+def test_assignment_typedef():
+ """
+ >>> test_assignment_typedef()
+ 1
+ 2
+ """
+ cdef int[2] x
+ cdef aliasT[:] y
+ x[:] = [1, 2]
+ y = x
+ for v in y:
+ print(v)
diff --git a/tests/memoryview/memoryview_acq_count.srctree b/tests/memoryview/memoryview_acq_count.srctree
index e7e6dfc69..3bc2f1cc9 100644
--- a/tests/memoryview/memoryview_acq_count.srctree
+++ b/tests/memoryview/memoryview_acq_count.srctree
@@ -35,7 +35,7 @@ cdef Py_ssize_t i
for i in prange(1000000, nogil=True, num_threads=16):
use_slice(m[::2])
-cdef int use_slice(int[:] m) nogil except -1:
+cdef int use_slice(int[:] m) except -1 nogil:
cdef int[:] m2 = m[1:]
m = m2[:-1]
del m, m2
diff --git a/tests/memoryview/memoryview_annotation_typing.py b/tests/memoryview/memoryview_annotation_typing.py
index 260e9ffeb..57299c835 100644
--- a/tests/memoryview/memoryview_annotation_typing.py
+++ b/tests/memoryview/memoryview_annotation_typing.py
@@ -1,7 +1,9 @@
# mode: run
-# tag: pep484, numpy, pure3.0
+# tag: pep484, numpy, pure3.7
##, warnings
+from __future__ import annotations # object[:] cannot be evaluated
+
import cython
import numpy
@@ -52,3 +54,67 @@ def one_dim_nogil_cfunc(a: cython.double[:]):
with cython.nogil:
result = _one_dim_nogil_cfunc(a)
return result
+
+
+def generic_object_memoryview(a: object[:]):
+ """
+ >>> a = numpy.ones((10,), dtype=object)
+ >>> generic_object_memoryview(a)
+ 10
+ """
+ sum = 0
+ for ai in a:
+ sum += ai
+ if cython.compiled:
+ assert cython.typeof(a) == "object[:]", cython.typeof(a)
+ return sum
+
+
+def generic_object_memoryview_contig(a: object[::1]):
+ """
+ >>> a = numpy.ones((10,), dtype=object)
+ >>> generic_object_memoryview_contig(a)
+ 10
+ """
+ sum = 0
+ for ai in a:
+ sum += ai
+ if cython.compiled:
+ assert cython.typeof(a) == "object[::1]", cython.typeof(a)
+ return sum
+
+
+@cython.cclass
+class C:
+ x: cython.int
+
+ def __init__(self, value):
+ self.x = value
+
+
+def ext_type_object_memoryview(a: C[:]):
+ """
+ >>> a = numpy.array([C(i) for i in range(10)], dtype=object)
+ >>> ext_type_object_memoryview(a)
+ 45
+ """
+ sum = 0
+ for ai in a:
+ sum += ai.x
+ if cython.compiled:
+ assert cython.typeof(a) == "C[:]", cython.typeof(a)
+ return sum
+
+
+def ext_type_object_memoryview_contig(a: C[::1]):
+ """
+ >>> a = numpy.array([C(i) for i in range(10)], dtype=object)
+ >>> ext_type_object_memoryview_contig(a)
+ 45
+ """
+ sum = 0
+ for ai in a:
+ sum += ai.x
+ if cython.compiled:
+ assert cython.typeof(a) == "C[::1]", cython.typeof(a)
+ return sum
diff --git a/tests/memoryview/memoryview_cache_builtins.srctree b/tests/memoryview/memoryview_cache_builtins.srctree
new file mode 100644
index 000000000..91b1c4753
--- /dev/null
+++ b/tests/memoryview/memoryview_cache_builtins.srctree
@@ -0,0 +1,21 @@
+PYTHON setup.py build_ext --inplace
+
+################ setup.py #####################
+
+from distutils.core import setup
+from Cython.Build import cythonize
+from Cython.Compiler import Options
+
+Options.cache_builtins = False
+
+setup(
+ ext_modules = cythonize("mview.pyx")
+)
+
+############### mview.pyx ################
+
+# https://github.com/cython/cython/issues/3406
+# Failure was at Cython compilation stage
+
+def f(double [::1] x):
+ pass
diff --git a/tests/memoryview/memoryview_no_binding_T3613.pyx b/tests/memoryview/memoryview_no_binding_T3613.pyx
new file mode 100644
index 000000000..1c736359e
--- /dev/null
+++ b/tests/memoryview/memoryview_no_binding_T3613.pyx
@@ -0,0 +1,21 @@
+# mode: compile
+# tag: memoryview
+
+# cython: binding=False
+
+# See GH 3613 - when memoryviews were compiled with binding off they ended up in an
+# inconsistent state where different directives were applied at different stages
+# of the pipeline
+
+import cython
+
+def f(double[:] a):
+ pass
+
+@cython.binding(False)
+def g(double[:] a):
+ pass
+
+@cython.binding(True)
+def h(double[:] a):
+ pass
diff --git a/tests/memoryview/memoryview_no_withgil_check.pyx b/tests/memoryview/memoryview_no_withgil_check.pyx
new file mode 100644
index 000000000..4753bab12
--- /dev/null
+++ b/tests/memoryview/memoryview_no_withgil_check.pyx
@@ -0,0 +1,11 @@
+# mode: compile
+
+# cython: test_fail_if_c_code_has = __Pyx_ErrOccurredWithGIL
+
+# cython-generated memoryview code shouldn't resort to
+# __Pyx_ErrOccurredWithGIL for error checking (because it's inefficient
+# inside a nogil block)
+
+def assign(double[:] a, double[:] b):
+ with nogil:
+ a[:] = b[:]
diff --git a/tests/memoryview/memoryview_pep489_typing.pyx b/tests/memoryview/memoryview_pep484_typing.pyx
index 0a62ff624..66445a1b7 100644
--- a/tests/memoryview/memoryview_pep489_typing.pyx
+++ b/tests/memoryview/memoryview_pep484_typing.pyx
@@ -1,5 +1,5 @@
# mode: run
-# tag: pep489, memoryview
+# tag: pep484, memoryview
cimport cython
diff --git a/tests/memoryview/memoryviewattrs.pyx b/tests/memoryview/memoryviewattrs.pyx
index 66bc9da56..7322424c3 100644
--- a/tests/memoryview/memoryviewattrs.pyx
+++ b/tests/memoryview/memoryviewattrs.pyx
@@ -1,13 +1,6 @@
# mode: run
# tag: numpy
-__test__ = {}
-
-def testcase(func):
- __test__[func.__name__] = func.__doc__
- return func
-
-
cimport cython
from cython.view cimport array
@@ -15,7 +8,6 @@ import numpy as np
cimport numpy as np
-@testcase
def test_shape_stride_suboffset():
u'''
>>> test_shape_stride_suboffset()
@@ -49,7 +41,6 @@ def test_shape_stride_suboffset():
print c_contig.suboffsets[0], c_contig.suboffsets[1], c_contig.suboffsets[2]
-@testcase
def test_copy_to():
u'''
>>> test_copy_to()
@@ -72,7 +63,6 @@ def test_copy_to():
print ' '.join(str(to_data[i]) for i in range(2*2*2))
-@testcase
def test_overlapping_copy():
"""
>>> test_overlapping_copy()
@@ -88,7 +78,6 @@ def test_overlapping_copy():
assert slice[i] == 10 - 1 - i
-@testcase
def test_copy_return_type():
"""
>>> test_copy_return_type()
@@ -103,7 +92,6 @@ def test_copy_return_type():
print(f_contig[2, 2])
-@testcase
def test_partly_overlapping():
"""
>>> test_partly_overlapping()
@@ -119,7 +107,6 @@ def test_partly_overlapping():
for i in range(5):
assert slice2[i] == i + 4
-@testcase
@cython.nonecheck(True)
def test_nonecheck1():
u'''
@@ -131,7 +118,6 @@ def test_nonecheck1():
cdef int[:,:,:] uninitialized
print uninitialized.is_c_contig()
-@testcase
@cython.nonecheck(True)
def test_nonecheck2():
u'''
@@ -143,7 +129,6 @@ def test_nonecheck2():
cdef int[:,:,:] uninitialized
print uninitialized.is_f_contig()
-@testcase
@cython.nonecheck(True)
def test_nonecheck3():
u'''
@@ -155,7 +140,6 @@ def test_nonecheck3():
cdef int[:,:,:] uninitialized
uninitialized.copy()
-@testcase
@cython.nonecheck(True)
def test_nonecheck4():
u'''
@@ -167,7 +151,6 @@ def test_nonecheck4():
cdef int[:,:,:] uninitialized
uninitialized.copy_fortran()
-@testcase
@cython.nonecheck(True)
def test_nonecheck5():
u'''
@@ -179,7 +162,6 @@ def test_nonecheck5():
cdef int[:,:,:] uninitialized
uninitialized._data
-@testcase
def test_copy_mismatch():
u'''
>>> test_copy_mismatch()
@@ -193,7 +175,6 @@ def test_copy_mismatch():
mv1[...] = mv2
-@testcase
def test_is_contiguous():
u"""
>>> test_is_contiguous()
@@ -222,7 +203,6 @@ def test_is_contiguous():
print 'strided', strided[::2].is_c_contig()
-@testcase
def call():
u'''
>>> call()
@@ -265,7 +245,6 @@ def call():
assert len(mv3) == 3
-@testcase
def two_dee():
u'''
>>> two_dee()
@@ -313,7 +292,6 @@ def two_dee():
print (<long*>mv3._data)[0] , (<long*>mv3._data)[1] , (<long*>mv3._data)[2] , (<long*>mv3._data)[3]
-@testcase
def fort_two_dee():
u'''
>>> fort_two_dee()
diff --git a/tests/memoryview/memslice.pyx b/tests/memoryview/memslice.pyx
index 2d496821f..0de47d9b6 100644
--- a/tests/memoryview/memslice.pyx
+++ b/tests/memoryview/memslice.pyx
@@ -1,5 +1,7 @@
# mode: run
+# Test the behaviour of memoryview slicing and indexing, contiguity, etc.
+
# Note: see also bufaccess.pyx
from __future__ import unicode_literals
@@ -1064,6 +1066,8 @@ def addref(*args):
def decref(*args):
for item in args: Py_DECREF(item)
+@cython.binding(False)
+@cython.always_allow_keywords(False)
def get_refcount(x):
return (<PyObject*>x).ob_refcnt
@@ -1626,7 +1630,7 @@ def test_index_slicing_away_direct_indirect():
All dimensions preceding dimension 1 must be indexed and not sliced
"""
cdef int[:, ::view.indirect, :] a = TestIndexSlicingDirectIndirectDims()
- a_obj = a
+ cdef object a_obj = a
print a[1][2][3]
print a[1, 2, 3]
@@ -1724,7 +1728,7 @@ def test_oob():
print a[:, 20]
-cdef int nogil_oob(int[:, :] a) nogil except 0:
+cdef int nogil_oob(int[:, :] a) except 0 nogil:
a[100, 9:]
return 1
@@ -1768,7 +1772,7 @@ def test_nogil_oob2():
a[100, 9:]
@cython.boundscheck(False)
-cdef int cdef_nogil(int[:, :] a) nogil except 0:
+cdef int cdef_nogil(int[:, :] a) except 0 nogil:
cdef int i, j
cdef int[:, :] b = a[::-1, 3:10:2]
for i in range(b.shape[0]):
@@ -1956,11 +1960,7 @@ def test_struct_attributes_format():
"""
cdef TestAttrs[10] array
cdef TestAttrs[:] struct_memview = array
-
- if sys.version_info[:2] >= (2, 7):
- print builtins.memoryview(struct_memview).format
- else:
- print "T{i:int_attrib:c:char_attrib:}"
+ print builtins.memoryview(struct_memview).format
# Test padding at the end of structs in the buffer support
@@ -2248,7 +2248,7 @@ def test_object_dtype_copying():
7
8
9
- 2 5
+ 5
1 5
"""
cdef int i
@@ -2269,10 +2269,12 @@ def test_object_dtype_copying():
print m2[i]
obj = m2[5]
- print get_refcount(obj), obj
+ refcount1 = get_refcount(obj)
+ print obj
del m2
- print get_refcount(obj), obj
+ refcount2 = get_refcount(obj)
+ print refcount1 - refcount2, obj
assert unique_refcount == get_refcount(unique), (unique_refcount, get_refcount(unique))
@@ -2359,7 +2361,9 @@ def test_contig_scalar_to_slice_assignment():
"""
>>> test_contig_scalar_to_slice_assignment()
14 14 14 14
+ 30 14 30 14
20 20 20 20
+ 30 30 20 20
"""
cdef int[5][10] a
cdef int[:, ::1] m = a
@@ -2367,9 +2371,15 @@ def test_contig_scalar_to_slice_assignment():
m[...] = 14
print m[0, 0], m[-1, -1], m[3, 2], m[4, 9]
+ m[:, :1] = 30
+ print m[0, 0], m[0, 1], m[1, 0], m[1, 1]
+
m[:, :] = 20
print m[0, 0], m[-1, -1], m[3, 2], m[4, 9]
+ m[:1, :] = 30
+ print m[0, 0], m[0, 1], m[1, 0], m[1, 1]
+
@testcase
def test_dtype_object_scalar_assignment():
"""
@@ -2558,6 +2568,53 @@ def test_const_buffer(const int[:] a):
@testcase
+def test_loop(int[:] a, throw_exception):
+ """
+ >>> A = IntMockBuffer("A", range(6), shape=(6,))
+ >>> test_loop(A, False)
+ acquired A
+ 15
+ released A
+ >>> try:
+ ... test_loop(A, True)
+ ... except ValueError:
+ ... pass
+ acquired A
+ released A
+ """
+ cdef int sum = 0
+ for ai in a:
+ sum += ai
+ if throw_exception:
+ raise ValueError()
+ print(sum)
+
+
+@testcase
+def test_loop_reassign(int[:] a):
+ """
+ >>> A = IntMockBuffer("A", range(6), shape=(6,))
+ >>> test_loop_reassign(A)
+ acquired A
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 15
+ released A
+ """
+ cdef int sum = 0
+ for ai in a:
+ sum += ai
+ print(ai)
+ a = None # this should not mess up the loop though!
+ print(sum)
+ # release happens in the wrapper function
+
+
+@testcase
def test_arg_in_closure(int [:] a):
"""
>>> A = IntMockBuffer("A", range(6), shape=(6,))
@@ -2594,3 +2651,50 @@ def test_arg_in_closure_cdef(a):
"""
return arg_in_closure_cdef(a)
+
+@testcase
+def test_local_in_closure(a):
+ """
+ >>> A = IntMockBuffer("A", range(6), shape=(6,))
+ >>> inner = test_local_in_closure(A)
+ acquired A
+ >>> inner()
+ (0, 1)
+
+ The assignment below is just to avoid printing what was collected
+ >>> del inner; ignore_me = gc.collect()
+ released A
+ """
+ cdef int[:] a_view = a
+ def inner():
+ return (a_view[0], a_view[1])
+ return inner
+
+@testcase
+def test_local_in_generator_expression(a, initialize, execute_now):
+ """
+ >>> A1 = IntMockBuffer("A1", range(6), shape=(6,))
+ >>> A2 = IntMockBuffer("A2", range(6), shape=(6,))
+ >>> test_local_in_generator_expression(A1, initialize=False, execute_now=False) # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ UnboundLocalError...
+
+ >>> test_local_in_generator_expression(A1, initialize=True, execute_now=True)
+ acquired A1
+ released A1
+ True
+
+ >>> genexp = test_local_in_generator_expression(A2, initialize=True, execute_now=False)
+ acquired A2
+ >>> sum(genexp)
+ released A2
+ 2
+ """
+ cdef int[:] a_view
+ if initialize:
+ a_view = a
+ if execute_now:
+ return any(ai > 3 for ai in a_view)
+ else:
+ return (ai > 3 for ai in a_view)
diff --git a/tests/memoryview/numpy_memoryview.pyx b/tests/memoryview/numpy_memoryview.pyx
index 3b3c15dba..7f98352a6 100644
--- a/tests/memoryview/numpy_memoryview.pyx
+++ b/tests/memoryview/numpy_memoryview.pyx
@@ -17,6 +17,10 @@ include "../buffers/mockbuffers.pxi"
ctypedef np.int32_t dtype_t
+IS_PYPY = hasattr(sys, 'pypy_version_info')
+NUMPY_VERSION = tuple(int(v) for v in np.__version__.split('.')[:2])
+print(NUMPY_VERSION)
+
def get_array():
# We need to type our array to get a __pyx_get_buffer() that typechecks
# for np.ndarray and calls __getbuffer__ in numpy.pxd
@@ -32,22 +36,13 @@ def ae(*args):
if x != args[0]:
raise AssertionError(args)
-__test__ = {}
-
-def testcase(f):
- __test__[f.__name__] = f.__doc__
+def testcase_no_pypy(f, _is_pypy=hasattr(sys, "pypy_version_info")):
+ if _is_pypy:
+ f.__doc__ = "" # disable the tests
return f
-def testcase_numpy_1_5(f):
- major, minor, *rest = np.__version__.split('.')
- if (int(major), int(minor)) >= (1, 5):
- __test__[f.__name__] = f.__doc__
- return f
-
-
def gc_collect_if_required():
- major, minor, *rest = np.__version__.split('.')
- if (int(major), int(minor)) >= (1, 14):
+ if NUMPY_VERSION >= (1, 14) or IS_PYPY:
import gc
gc.collect()
@@ -56,7 +51,6 @@ def gc_collect_if_required():
### Test slicing memoryview slices
#
-@testcase
def test_partial_slicing(array):
"""
>>> test_partial_slicing(a)
@@ -72,7 +66,6 @@ def test_partial_slicing(array):
ae(b.strides[0], c.strides[0], obj.strides[0])
ae(b.strides[1], c.strides[1], obj.strides[1])
-@testcase
def test_ellipsis(array):
"""
>>> test_ellipsis(a)
@@ -114,7 +107,6 @@ def test_ellipsis(array):
#
### Test slicing memoryview objects
#
-@testcase
def test_partial_slicing_memoryview(array):
"""
>>> test_partial_slicing_memoryview(a)
@@ -131,7 +123,6 @@ def test_partial_slicing_memoryview(array):
ae(b.strides[0], c.strides[0], obj.strides[0])
ae(b.strides[1], c.strides[1], obj.strides[1])
-@testcase
def test_ellipsis_memoryview(array):
"""
>>> test_ellipsis_memoryview(a)
@@ -172,7 +163,6 @@ def test_ellipsis_memoryview(array):
ae(e.strides[0], e_obj.strides[0])
-@testcase
def test_transpose():
"""
>>> test_transpose()
@@ -186,7 +176,7 @@ def test_transpose():
numpy_obj = np.arange(4 * 3, dtype=np.int32).reshape(4, 3)
a = numpy_obj
- a_obj = a
+ cdef object a_obj = a
cdef dtype_t[:, :] b = a.T
print a.T.shape[0], a.T.shape[1]
@@ -203,7 +193,6 @@ def test_transpose():
print a[3, 2], a.T[2, 3], a_obj[3, 2], a_obj.T[2, 3], numpy_obj[3, 2], numpy_obj.T[2, 3]
-@testcase
def test_transpose_type(a):
"""
>>> a = np.zeros((5, 10), dtype=np.float64)
@@ -216,12 +205,8 @@ def test_transpose_type(a):
print m_transpose[6, 4]
-@testcase_numpy_1_5
def test_numpy_like_attributes(cyarray):
"""
- For some reason this fails in numpy 1.4, with shape () and strides (40, 8)
- instead of 20, 4 on my machine. Investigate this.
-
>>> cyarray = create_array(shape=(8, 5), mode="c")
>>> test_numpy_like_attributes(cyarray)
>>> test_numpy_like_attributes(cyarray.memview)
@@ -237,14 +222,13 @@ def test_numpy_like_attributes(cyarray):
cdef int[:, :] mslice = numarray
assert (<object> mslice).base is numarray
-@testcase_numpy_1_5
def test_copy_and_contig_attributes(a):
"""
>>> a = np.arange(20, dtype=np.int32).reshape(5, 4)
>>> test_copy_and_contig_attributes(a)
"""
cdef np.int32_t[:, :] mslice = a
- m = mslice
+ cdef object m = mslice # object copy
# Test object copy attributes
assert np.all(a == np.array(m.copy()))
@@ -264,7 +248,7 @@ cdef extern from "bufaccess.h":
ctypedef unsigned int td_h_ushort # Defined as unsigned short
ctypedef td_h_short td_h_cy_short
-cdef void dealloc_callback(void *data):
+cdef void dealloc_callback(void *data) noexcept:
print "deallocating..."
def build_numarray(array array):
@@ -274,7 +258,7 @@ def build_numarray(array array):
def index(array array):
print build_numarray(array)[3, 2]
-@testcase_numpy_1_5
+@testcase_no_pypy
def test_coerce_to_numpy():
"""
Test coercion to NumPy arrays, especially with automatically
@@ -355,6 +339,7 @@ def test_coerce_to_numpy():
'e': 800,
}
+
smallstructs[idx] = { 'a': 600, 'b': 700 }
nestedstructs[idx] = {
@@ -412,7 +397,7 @@ def test_coerce_to_numpy():
index(<td_h_ushort[:4, :5]> <td_h_ushort *> h_ushorts)
-@testcase_numpy_1_5
+@testcase_no_pypy
def test_memslice_getbuffer():
"""
>>> test_memslice_getbuffer(); gc_collect_if_required()
@@ -451,7 +436,6 @@ cdef packed struct StructArray:
int a[4]
signed char b[5]
-@testcase_numpy_1_5
def test_memslice_structarray(data, dtype):
"""
>>> def b(s): return s.encode('ascii')
@@ -507,7 +491,6 @@ def test_memslice_structarray(data, dtype):
print myslice[i].a[j]
print myslice[i].b.decode('ASCII')
-@testcase_numpy_1_5
def test_structarray_errors(StructArray[:] a):
"""
>>> dtype = np.dtype([('a', '4i'), ('b', '5b')])
@@ -554,7 +537,6 @@ def stringstructtest(StringStruct[:] view):
def stringtest(String[:] view):
pass
-@testcase_numpy_1_5
def test_string_invalid_dims():
"""
>>> def b(s): return s.encode('ascii')
@@ -575,7 +557,6 @@ ctypedef struct AttributesStruct:
float attrib2
StringStruct attrib3
-@testcase_numpy_1_5
def test_struct_attributes():
"""
>>> test_struct_attributes()
@@ -631,7 +612,6 @@ cdef class SuboffsetsNoStridesBuffer(Buffer):
getbuffer(self, info)
info.suboffsets = self._shape
-@testcase
def test_null_strides(Buffer buffer_obj):
"""
>>> test_null_strides(Buffer())
@@ -651,7 +631,6 @@ def test_null_strides(Buffer buffer_obj):
assert m2[i, j] == buffer_obj.m[i, j], (i, j, m2[i, j], buffer_obj.m[i, j])
assert m3[i, j] == buffer_obj.m[i, j]
-@testcase
def test_null_strides_error(buffer_obj):
"""
>>> test_null_strides_error(Buffer())
@@ -725,7 +704,6 @@ ctypedef struct SameTypeAfterArraysStructSimple:
double b[16]
double c
-@testcase
def same_type_after_arrays_simple():
"""
>>> same_type_after_arrays_simple()
@@ -747,7 +725,6 @@ ctypedef struct SameTypeAfterArraysStructComposite:
double h[4]
int i
-@testcase
def same_type_after_arrays_composite():
"""
>>> same_type_after_arrays_composite() if sys.version_info[:2] >= (3, 5) else None
@@ -757,3 +734,29 @@ def same_type_after_arrays_composite():
cdef SameTypeAfterArraysStructComposite element
arr = np.ones(2, np.asarray(<SameTypeAfterArraysStructComposite[:1]>&element).dtype)
cdef SameTypeAfterArraysStructComposite[:] memview = arr
+
+ctypedef fused np_numeric_t:
+ np.float64_t
+
+def test_invalid_buffer_fused_memoryview(np_numeric_t[:] A):
+ """
+ >>> import numpy as np
+ >>> zz = np.zeros([5], dtype='M')
+ >>> test_invalid_buffer_fused_memoryview(zz)
+ Traceback (most recent call last):
+ ...
+ TypeError: No matching signature found
+ """
+ return
+
+ctypedef fused np_numeric_object_t:
+ np.float64_t[:]
+ object
+
+def test_valid_buffer_fused_memoryview(np_numeric_object_t A):
+ """
+ >>> import numpy as np
+ >>> zz = np.zeros([5], dtype='M')
+ >>> test_valid_buffer_fused_memoryview(zz)
+ """
+ return
diff --git a/tests/memoryview/relaxed_strides.pyx b/tests/memoryview/relaxed_strides.pyx
index 1743f23d0..6f90f4db5 100644
--- a/tests/memoryview/relaxed_strides.pyx
+++ b/tests/memoryview/relaxed_strides.pyx
@@ -10,12 +10,12 @@ Thanks to Nathaniel Smith and Sebastian Berg.
See also:
Mailing list threads:
- http://thread.gmane.org/gmane.comp.python.cython.devel/14762
- http://thread.gmane.org/gmane.comp.python.cython.devel/14634
+ https://thread.gmane.org/gmane.comp.python.cython.devel/14762
+ https://thread.gmane.org/gmane.comp.python.cython.devel/14634
Detailed discussion of the difference between numpy/cython's current
definition of "contiguity", and the correct definition:
- http://thread.gmane.org/gmane.comp.python.cython.devel/14634/focus=14640
+ https://thread.gmane.org/gmane.comp.python.cython.devel/14634/focus=14640
The PR implementing NPY_RELAXED_STRIDES_CHECKING:
https://github.com/numpy/numpy/pull/3162
@@ -37,13 +37,6 @@ NUMPY_HAS_RELAXED_STRIDES = (
np.ones((10, 1), order="C").flags.f_contiguous)
-def not_py26(f):
- import sys
- if sys.version_info < (2, 7):
- return lambda a: None
- return f
-
-
def test_one_sized(array):
"""
>>> contig = np.ascontiguousarray(np.arange(10, dtype=np.double)[::100])
@@ -81,7 +74,6 @@ def test_zero_sized_multidim_ccontig(array):
cdef double[:, :, ::1] a = array
return a
-@not_py26
def test_zero_sized_multidim_fcontig(array):
"""
>>> contig = np.ascontiguousarray(np.zeros((4,4,4))[::2, 2:2, ::2])
diff --git a/tests/memoryview/view_return_errors.pyx b/tests/memoryview/view_return_errors.pyx
index 8e9443108..6cedef969 100644
--- a/tests/memoryview/view_return_errors.pyx
+++ b/tests/memoryview/view_return_errors.pyx
@@ -13,7 +13,18 @@ cdef double[:] foo(int i):
raise TypeError('dummy')
-def propagate(i):
+cdef double[:] foo_nogil(int i) nogil:
+ if i == 1:
+ raise AttributeError('dummy')
+ if i == 2:
+ raise RuntimeError('dummy')
+ if i == 3:
+ raise ValueError('dummy')
+ if i == 4:
+ raise TypeError('dummy')
+
+
+def propagate(i, bint nogil=False):
"""
>>> propagate(0)
TypeError('Memoryview return value is not initialized')
@@ -25,9 +36,20 @@ def propagate(i):
ValueError('dummy')
>>> propagate(4)
TypeError('dummy')
+
+ >>> propagate(0, nogil=True)
+ TypeError('Memoryview return value is not initialized')
+ >>> propagate(1, nogil=True)
+ AttributeError('dummy')
+ >>> propagate(2, nogil=True)
+ RuntimeError('dummy')
+ >>> propagate(3, nogil=True)
+ ValueError('dummy')
+ >>> propagate(4, nogil=True)
+ TypeError('dummy')
"""
try:
- foo(i)
+ foo_nogil(i) if nogil else foo(i)
except Exception as e:
print '%s(%r)' % (e.__class__.__name__, e.args[0])
else: