diff options
author | Stefan Behnel <stefan_ml@behnel.de> | 2021-10-25 14:29:02 +0200 |
---|---|---|
committer | Stefan Behnel <stefan_ml@behnel.de> | 2021-10-25 14:29:02 +0200 |
commit | 1461e514c00056eef58c7c18262012b1510ba692 (patch) | |
tree | f275d6e9759082933f40111e0d850c7ac7150a99 | |
parent | 68bb7164d4f93573c4e6a7249561b742818b39cb (diff) | |
download | cython-1461e514c00056eef58c7c18262012b1510ba692.tar.gz |
Clean up the NumPy integration test by moving the doctests into the functions that they test.
-rw-r--r-- | tests/run/numpy_test.pyx | 405 |
1 files changed, 225 insertions, 180 deletions
diff --git a/tests/run/numpy_test.pyx b/tests/run/numpy_test.pyx index 67db2b638..11b72054b 100644 --- a/tests/run/numpy_test.pyx +++ b/tests/run/numpy_test.pyx @@ -1,8 +1,11 @@ +# mode: run # tag: numpy cimport numpy as np cimport cython +import numpy as np + import re @@ -16,6 +19,7 @@ def testcase(f): # but is a useful indicator of what functions are designed as tests return f + if little_endian(): my_endian = '<' other_endian = '>' @@ -23,17 +27,55 @@ else: my_endian = '>' other_endian = '<' -try: - import numpy as np - __doc__ = u""" +def assert_dtype_sizes(): + """ >>> assert_dtype_sizes() + """ + assert sizeof(np.int8_t) == 1 + assert sizeof(np.int16_t) == 2 + assert sizeof(np.int32_t) == 4 + assert sizeof(np.int64_t) == 8 + assert sizeof(np.uint8_t) == 1 + assert sizeof(np.uint16_t) == 2 + assert sizeof(np.uint32_t) == 4 + assert sizeof(np.uint64_t) == 8 + assert sizeof(np.float32_t) == 4 + assert sizeof(np.float64_t) == 8 + assert sizeof(np.complex64_t) == 8 + assert sizeof(np.complex128_t) == 16 + +@testcase +def test_enums(): + """ + >>> test_enums() + """ + cdef np.NPY_CASTING nc = np.NPY_NO_CASTING + assert nc != np.NPY_SAFE_CASTING + + +def ndarray_str(arr): + u""" + Work around display differences in NumPy 1.14. + """ + return re.sub(ur'\[ +', '[', unicode(arr)) + + +def basic(): + """ >>> basic() [[0 1 2 3 4] [5 6 7 8 9]] 2 0 9 5 + """ + cdef object[int, ndim=2] buf = np.arange(10, dtype='i').reshape((2, 5)) + print buf + print buf[0, 2], buf[0, 0], buf[1, 4], buf[1, 0] + +def three_dim(): + """ >>> three_dim() # doctest: +NORMALIZE_WHITESPACE [[[0. 1. 2. 3.] [4. 5. 6. 7.]] @@ -44,11 +86,25 @@ try: [[16. 17. 18. 19.] [20. 21. 22. 23.]]] 6.0 0.0 13.0 8.0 + """ + cdef object[double, ndim=3] buf = np.arange(24, dtype='d').reshape((3,2,4)) + print ndarray_str(buf) + print buf[0, 1, 2], buf[0, 0, 0], buf[1, 1, 1], buf[1, 0, 0] + +def obj_array(): + """ >>> obj_array() [a 1 {}] a 1 {} + """ + cdef object[object, ndim=1] buf = np.array(["a", 1, {}]) + print str(buf).replace('"', '').replace("'", '') + print buf[0], buf[1], buf[2] + +def print_long_2d(np.ndarray[long, ndim=2] arr): + """ Test various forms of slicing, picking etc. >>> a = np.arange(10, dtype='l').reshape(2, 5) >>> print_long_2d(a) @@ -78,9 +134,16 @@ try: 2 7 3 8 4 9 + """ + cdef int i, j + for i in range(arr.shape[0]): + print u" ".join([unicode(arr[i, j]) for j in range(arr.shape[1])]) + +def put_range_long_1d(np.ndarray[long] arr): + """ Write to slices - >>> b = a.copy() + >>> b = np.arange(10, dtype='l').reshape(2, 5) >>> put_range_long_1d(b[:, 3]) >>> print (b) [[0 1 2 0 4] @@ -101,7 +164,16 @@ try: >>> print (a) [[0 0 0 0 0] [0 0 0 0 0]] + """ + # Writes 0,1,2,... to array and returns array + cdef int value = 0, i + for i in range(arr.shape[0]): + arr[i] = value + value += 1 + +def test_c_contig(np.ndarray[int, ndim=2, mode='c'] arr): + """ Test contiguous access modes: >>> c_arr = np.array(np.arange(12, dtype='i').reshape(3,4), order='C') >>> f_arr = np.array(np.arange(12, dtype='i').reshape(3,4), order='F') @@ -109,200 +181,39 @@ try: 0 1 2 3 4 5 6 7 8 9 10 11 - >>> test_f_contig(f_arr) - 0 1 2 3 - 4 5 6 7 - 8 9 10 11 >>> test_c_contig(f_arr) #doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: ndarray is not C...contiguous - >>> test_f_contig(c_arr) #doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: ndarray is not Fortran contiguous >>> test_c_contig(c_arr[::2,::2]) #doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: ndarray is not C...contiguous - - >>> test_dtype('?', inc1_bool) - >>> test_dtype('b', inc1_byte) - >>> test_dtype('B', inc1_ubyte) - >>> test_dtype('h', inc1_short) - >>> test_dtype('H', inc1_ushort) - >>> test_dtype('i', inc1_int) - >>> test_dtype('I', inc1_uint) - >>> test_dtype('l', inc1_long) - >>> test_dtype('L', inc1_ulong) - - >>> test_dtype('f', inc1_float) - >>> test_dtype('d', inc1_double) - >>> test_dtype('g', inc1_longdouble) - >>> test_dtype('O', inc1_object) - >>> test_dtype('F', inc1_cfloat) # numpy format codes differ from buffer ones here - >>> test_dtype('D', inc1_cdouble) - >>> test_dtype('G', inc1_clongdouble) - >>> test_dtype('F', inc1_cfloat_struct) - >>> test_dtype('D', inc1_cdouble_struct) - >>> test_dtype('G', inc1_clongdouble_struct) - - >>> test_dtype(np.int, inc1_int_t) - >>> test_dtype(np.longlong, inc1_longlong_t) - >>> test_dtype(np.float, inc1_float_t) - >>> test_dtype(np.double, inc1_double_t) - >>> test_dtype(np.intp, inc1_intp_t) - >>> test_dtype(np.uintp, inc1_uintp_t) - - >>> test_dtype(np.longdouble, inc1_longdouble_t) - - >>> test_dtype(np.int32, inc1_int32_t) - >>> test_dtype(np.float64, inc1_float64_t) - - Endian tests: - >>> test_dtype('%si' % my_endian, inc1_int) - >>> test_dtype('%si' % other_endian, inc1_int) #doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: ... - - - - >>> test_recordarray() - - >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\ - ('a', np.dtype('i,i')),\ - ('b', np.dtype('i,i'))\ - ])))) # doctest: +NORMALIZE_WHITESPACE - array([((0, 0), (0, 0)), ((1, 2), (1, 4)), ((1, 2), (1, 4))], - dtype=[('a', [('f0', '!i4'), ('f1', '!i4')]), ('b', [('f0', '!i4'), ('f1', '!i4')])]) - - >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\ - ('a', np.dtype('i,f')),\ - ('b', np.dtype('i,i'))\ - ])))) - Traceback (most recent call last): - ... - ValueError: Buffer dtype mismatch, expected 'int' but got 'float' in 'DoubleInt.y' - - >>> print(test_packed_align(np.zeros((1,), dtype=np.dtype('b,i', align=False)))) - [(22, 23)] - - - The output changed in Python 3: - >> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=True)))) - array([(22, 23)], - dtype=[('f0', '|i1'), ('', '|V3'), ('f1', '!i4')]) - - -> - - array([(22, 23)], - dtype={'names':['f0','f1'], 'formats':['i1','!i4'], 'offsets':[0,4], 'itemsize':8, 'aligned':True}) - - - >>> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=True)))) - [(22, 23)] - - >>> print(test_packed_align(np.zeros((1,), dtype=np.dtype('b,i', align=True)))) #doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: ... - - >>> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=False)))) #doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: ... - - - >>> test_good_cast() - True - >>> test_bad_cast() - Traceback (most recent call last): - ... - ValueError: Item size of buffer (1 byte) does not match size of 'int' (4 bytes) - - >>> test_complextypes() - 1,1 - 1,1 - 8,16 - - >>> test_point_record() # doctest: +NORMALIZE_WHITESPACE - array([(0., 0.), (1., -1.), (2., -2.)], - dtype=[('x', '!f8'), ('y', '!f8')]) - -""" -except: - __doc__ = u"" - - -def assert_dtype_sizes(): - assert sizeof(np.int8_t) == 1 - assert sizeof(np.int16_t) == 2 - assert sizeof(np.int32_t) == 4 - assert sizeof(np.int64_t) == 8 - assert sizeof(np.uint8_t) == 1 - assert sizeof(np.uint16_t) == 2 - assert sizeof(np.uint32_t) == 4 - assert sizeof(np.uint64_t) == 8 - assert sizeof(np.float32_t) == 4 - assert sizeof(np.float64_t) == 8 - assert sizeof(np.complex64_t) == 8 - assert sizeof(np.complex128_t) == 16 - - -@testcase -def test_enums(): - """ - >>> test_enums() """ - cdef np.NPY_CASTING nc = np.NPY_NO_CASTING - assert nc != np.NPY_SAFE_CASTING - - -def ndarray_str(arr): - u""" - Work around display differences in NumPy 1.14. - """ - return re.sub(ur'\[ +', '[', unicode(arr)) - -def basic(): - cdef object[int, ndim=2] buf = np.arange(10, dtype='i').reshape((2, 5)) - print buf - print buf[0, 2], buf[0, 0], buf[1, 4], buf[1, 0] - -def three_dim(): - cdef object[double, ndim=3] buf = np.arange(24, dtype='d').reshape((3,2,4)) - print ndarray_str(buf) - print buf[0, 1, 2], buf[0, 0, 0], buf[1, 1, 1], buf[1, 0, 0] - -def obj_array(): - cdef object[object, ndim=1] buf = np.array(["a", 1, {}]) - print str(buf).replace('"', '').replace("'", '') - print buf[0], buf[1], buf[2] - - -def print_long_2d(np.ndarray[long, ndim=2] arr): cdef int i, j for i in range(arr.shape[0]): print u" ".join([unicode(arr[i, j]) for j in range(arr.shape[1])]) -def put_range_long_1d(np.ndarray[long] arr): - u"""Writes 0,1,2,... to array and returns array""" - cdef int value = 0, i - for i in range(arr.shape[0]): - arr[i] = value - value += 1 - -def test_c_contig(np.ndarray[int, ndim=2, mode='c'] arr): - cdef int i, j - for i in range(arr.shape[0]): - print u" ".join([unicode(arr[i, j]) for j in range(arr.shape[1])]) def test_f_contig(np.ndarray[int, ndim=2, mode='fortran'] arr): + """ + Test contiguous access modes: + >>> c_arr = np.array(np.arange(12, dtype='i').reshape(3,4), order='C') + >>> f_arr = np.array(np.arange(12, dtype='i').reshape(3,4), order='F') + >>> test_f_contig(f_arr) + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + >>> test_f_contig(c_arr) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: ndarray is not Fortran contiguous + """ cdef int i, j for i in range(arr.shape[0]): print u" ".join([unicode(arr[i, j]) for j in range(arr.shape[1])]) + # Exhaustive dtype tests -- increments element [1] by 1 (or 1+1j) for all dtypes def inc1_bool(np.ndarray[unsigned char] arr): arr[1] += 1 def inc1_byte(np.ndarray[char] arr): arr[1] += 1 @@ -343,7 +254,6 @@ def inc1_object(np.ndarray[object] arr): o += 1 arr[1] = o # unfortunately, += segfaults for objects - def inc1_int_t(np.ndarray[np.int_t] arr): arr[1] += 1 def inc1_long_t(np.ndarray[np.long_t] arr): arr[1] += 1 def inc1_longlong_t(np.ndarray[np.longlong_t] arr): arr[1] += 1 @@ -359,6 +269,47 @@ def inc1_float64_t(np.ndarray[np.float64_t] arr): arr[1] += 1 def test_dtype(dtype, inc1): + """ + >>> test_dtype('?', inc1_bool) + >>> test_dtype('b', inc1_byte) + >>> test_dtype('B', inc1_ubyte) + >>> test_dtype('h', inc1_short) + >>> test_dtype('H', inc1_ushort) + >>> test_dtype('i', inc1_int) + >>> test_dtype('I', inc1_uint) + >>> test_dtype('l', inc1_long) + >>> test_dtype('L', inc1_ulong) + + >>> test_dtype('f', inc1_float) + >>> test_dtype('d', inc1_double) + >>> test_dtype('g', inc1_longdouble) + >>> test_dtype('O', inc1_object) + >>> test_dtype('F', inc1_cfloat) # numpy format codes differ from buffer ones here + >>> test_dtype('D', inc1_cdouble) + >>> test_dtype('G', inc1_clongdouble) + >>> test_dtype('F', inc1_cfloat_struct) + >>> test_dtype('D', inc1_cdouble_struct) + >>> test_dtype('G', inc1_clongdouble_struct) + + >>> test_dtype(np.int, inc1_int_t) + >>> test_dtype(np.longlong, inc1_longlong_t) + >>> test_dtype(np.float, inc1_float_t) + >>> test_dtype(np.double, inc1_double_t) + >>> test_dtype(np.intp, inc1_intp_t) + >>> test_dtype(np.uintp, inc1_uintp_t) + + >>> test_dtype(np.longdouble, inc1_longdouble_t) + + >>> test_dtype(np.int32, inc1_int32_t) + >>> test_dtype(np.float64, inc1_float64_t) + + Endian tests: + >>> test_dtype('%si' % my_endian, inc1_int) + >>> test_dtype('%si' % other_endian, inc1_int) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: ... + """ if dtype in ("g", np.longdouble, "G", np.clongdouble): if sizeof(double) == sizeof(long double): # MSVC @@ -379,10 +330,14 @@ def test_dtype(dtype, inc1): inc1(a) if a[1] != 11: print u"failed!" + cdef struct DoubleInt: int x, y def test_recordarray(): + """ + >>> test_recordarray() + """ cdef object[DoubleInt] arr arr = np.array([(5,5), (4, 6)], dtype=np.dtype('i,i')) cdef DoubleInt rec @@ -398,6 +353,7 @@ def test_recordarray(): if arr[1].x != 5: print u"failed" if arr[1].y != 10: print u"failed" + cdef struct NestedStruct: DoubleInt a DoubleInt b @@ -411,6 +367,22 @@ cdef struct BadNestedStruct: BadDoubleInt b def test_nested_dtypes(obj): + """ + >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\ + ('a', np.dtype('i,i')),\ + ('b', np.dtype('i,i'))\ + ])))) # doctest: +NORMALIZE_WHITESPACE + array([((0, 0), (0, 0)), ((1, 2), (1, 4)), ((1, 2), (1, 4))], + dtype=[('a', [('f0', '!i4'), ('f1', '!i4')]), ('b', [('f0', '!i4'), ('f1', '!i4')])]) + + >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\ + ('a', np.dtype('i,f')),\ + ('b', np.dtype('i,i'))\ + ])))) + Traceback (most recent call last): + ... + ValueError: Buffer dtype mismatch, expected 'int' but got 'float' in 'DoubleInt.y' + """ cdef object[NestedStruct] arr = obj arr[1].a.x = 1 arr[1].a.y = 2 @@ -419,19 +391,36 @@ def test_nested_dtypes(obj): arr[2] = arr[1] return repr(arr).replace('<', '!').replace('>', '!') + def test_bad_nested_dtypes(): + """ + >>> test_bad_nested_dtypes() + """ cdef object[BadNestedStruct] arr + def test_good_cast(): + """ + >>> test_good_cast() + True + """ # Check that a signed int can round-trip through casted unsigned int access cdef np.ndarray[unsigned int, cast=True] arr = np.array([-100], dtype='i') cdef unsigned int data = arr[0] return -100 == <int>data + def test_bad_cast(): + """ + >>> test_bad_cast() + Traceback (most recent call last): + ... + ValueError: Item size of buffer (1 byte) does not match size of 'int' (4 bytes) + """ # This should raise an exception cdef np.ndarray[int, cast=True] arr = np.array([1], dtype='b') + cdef packed struct PackedStruct: char a int b @@ -453,16 +442,45 @@ cdef packed struct PartiallyPackedStruct2: UnpackedStruct sub def test_packed_align(np.ndarray[PackedStruct] arr): + """ + >>> print(test_packed_align(np.zeros((1,), dtype=np.dtype('b,i', align=False)))) + [(22, 23)] + >>> print(test_packed_align(np.zeros((1,), dtype=np.dtype('b,i', align=True)))) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: ... + """ arr[0].a = 22 arr[0].b = 23 return list(arr) + def test_unpacked_align(np.ndarray[UnpackedStruct] arr): + """ + The output changed in Python 3: + >> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=True)))) + array([(22, 23)], + dtype=[('f0', '|i1'), ('', '|V3'), ('f1', '!i4')]) + + -> + + array([(22, 23)], + dtype={'names':['f0','f1'], 'formats':['i1','!i4'], 'offsets':[0,4], 'itemsize':8, 'aligned':True}) + + + >>> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=True)))) + [(22, 23)] + >>> print(test_unpacked_align(np.zeros((1,), dtype=np.dtype('b,i', align=False)))) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: ... + """ arr[0].a = 22 arr[0].b = 23 # return repr(arr).replace('<', '!').replace('>', '!') return list(arr) + def test_partially_packed_align(np.ndarray[PartiallyPackedStruct] arr): arr[0].a = 22 arr[0].b = 23 @@ -471,6 +489,7 @@ def test_partially_packed_align(np.ndarray[PartiallyPackedStruct] arr): arr[0].c = 26 return repr(arr).replace('<', '!').replace('>', '!') + def test_partially_packed_align_2(np.ndarray[PartiallyPackedStruct2] arr): arr[0].a = 22 arr[0].b = 23 @@ -479,7 +498,14 @@ def test_partially_packed_align_2(np.ndarray[PartiallyPackedStruct2] arr): arr[0].sub.b = 28 return repr(arr).replace('<', '!').replace('>', '!') + def test_complextypes(): + """ + >>> test_complextypes() + 1,1 + 1,1 + 8,16 + """ cdef np.complex64_t x64 = 1, y64 = 1j cdef np.complex128_t x128 = 1, y128 = 1j x64 = x64 + y64 @@ -493,6 +519,11 @@ cdef struct Point: np.float64_t x, y def test_point_record(): + """ + >>> test_point_record() # doctest: +NORMALIZE_WHITESPACE + array([(0., 0.), (1., -1.), (2., -2.)], + dtype=[('x', '!f8'), ('y', '!f8')]) + """ cdef np.ndarray[Point] test Point_dtype = np.dtype([('x', np.float64), ('y', np.float64)]) test = np.zeros(3, Point_dtype) @@ -504,6 +535,7 @@ def test_point_record(): r'\.0+\b', '.', repr(test).replace('<', '!').replace('>', '!') .replace('( ', '(').replace(', ', ', ')) + # Test fused np.ndarray dtypes and runtime dispatch @testcase def test_fused_ndarray_floating_dtype(np.ndarray[cython.floating, ndim=1] a): @@ -536,6 +568,7 @@ cdef fused fused_external: np.float32_t np.float64_t + @testcase def test_fused_external(np.ndarray[fused_external, ndim=1] a): """ @@ -554,6 +587,7 @@ def test_fused_external(np.ndarray[fused_external, ndim=1] a): """ print a.dtype + cdef fused fused_buffers: np.ndarray[np.int32_t, ndim=1] np.int64_t[::1] @@ -565,6 +599,7 @@ def test_fused_buffers(fused_buffers arg): ['int64_t[::1]', 'ndarray[int32_t,ndim=1]'] """ + cpdef _fused_cpdef_buffers(np.ndarray[fused_external] a): print a.dtype @@ -580,6 +615,7 @@ def test_fused_cpdef_buffers(): cdef np.ndarray[np.int32_t] typed_array = int32_array _fused_cpdef_buffers(typed_array) + @testcase def test_fused_ndarray_integral_dtype(np.ndarray[cython.integral, ndim=1] a): """ @@ -602,6 +638,7 @@ def test_fused_ndarray_integral_dtype(np.ndarray[cython.integral, ndim=1] a): # select different integer types with equal sizeof() print a[5], b[6] + cdef fused fused_dtype: float complex double complex @@ -668,6 +705,7 @@ def test_fused_ndarray(fused_ndarray a): else: print b[5] + cpdef test_fused_cpdef_ndarray(fused_ndarray a): """ >>> import cython @@ -692,6 +730,7 @@ cpdef test_fused_cpdef_ndarray(fused_ndarray a): else: print b[5] + def test_fused_cpdef_ndarray_cdef_call(): """ >>> test_fused_cpdef_ndarray_cdef_call() @@ -701,6 +740,7 @@ def test_fused_cpdef_ndarray_cdef_call(): cdef np.ndarray[Foo, ndim=1] foo_array = get_Foo_array() test_fused_cpdef_ndarray(foo_array) + cdef fused int_type: np.int32_t np.int64_t @@ -729,6 +769,7 @@ def test_dispatch_non_clashing_declarations_repeating_types(np.ndarray[cython.fl """ print a1[1], a2[2], a3[3], a4[4] + ctypedef np.int32_t typedeffed_type cdef fused typedeffed_fused_type: @@ -763,6 +804,7 @@ def test_dispatch_external_typedef(np.ndarray[confusing_fused_typedef] a): """ print a[3] + # test fused memoryview slices cdef fused memslice_fused_dtype: float @@ -793,6 +835,7 @@ def test_fused_memslice_other_dtypes(memslice_fused_dtype[:] a): cdef memslice_fused_dtype[:] b = a print cython.typeof(a), cython.typeof(b), a[5], b[6] + cdef fused memslice_fused: float[:] double[:] @@ -822,6 +865,7 @@ def test_fused_memslice(memslice_fused a): cdef memslice_fused b = a print cython.typeof(a), cython.typeof(b), a[5], b[6] + @testcase def test_dispatch_memoryview_object(): """ @@ -833,6 +877,7 @@ def test_dispatch_memoryview_object(): cdef int[:] m3 = <object> m test_fused_memslice(m3) + cdef fused ndim_t: double[:] double[:, :] |