Commit 1461e514 authored by Stefan Behnel's avatar Stefan Behnel

Clean up the NumPy integration test by moving the doctests into the functions that they test.

parent 68bb7164
# 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[:, :]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment