blob: 24803a97f63cd500c02eba5e539c9cae87635609 [file] [log] [blame]
Ivan Smirnovc5466552016-10-31 13:54:43 +00001import re
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02002import pytest
Ivan Smirnovc5466552016-10-31 13:54:43 +00003
Jason Rhinelander2a757842017-01-24 11:26:51 -05004pytestmark = pytest.requires_numpy
5
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02006with pytest.suppress(ImportError):
7 import numpy as np
8
Ivan Smirnovc5466552016-10-31 13:54:43 +00009
10@pytest.fixture(scope='module')
11def simple_dtype():
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050012 ld = np.dtype('longdouble')
13 return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'],
14 'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)],
15 'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]})
Ivan Smirnovc5466552016-10-31 13:54:43 +000016
17
18@pytest.fixture(scope='module')
19def packed_dtype():
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050020 return np.dtype([('bool_', '?'), ('uint_', 'u4'), ('float_', 'f4'), ('ldbl_', 'g')])
21
22
23def dt_fmt():
Jason Rhinelander0861be02017-02-25 16:43:01 -050024 from sys import byteorder
25 e = '<' if byteorder == 'little' else '>'
26 return ("{{'names':['bool_','uint_','float_','ldbl_'],"
27 " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050028 " 'offsets':[0,4,8,{}], 'itemsize':{}}}")
29
30
31def simple_dtype_fmt():
32 ld = np.dtype('longdouble')
33 simple_ld_off = 12 + 4 * (ld.alignment > 4)
34 return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)
35
36
37def packed_dtype_fmt():
Jason Rhinelander0861be02017-02-25 16:43:01 -050038 from sys import byteorder
39 return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format(
40 np.dtype('longdouble').itemsize, e='<' if byteorder == 'little' else '>')
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050041
42
43def partial_ld_offset():
44 return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * (
45 np.dtype('longdouble').alignment > 8)
46
47
48def partial_dtype_fmt():
49 ld = np.dtype('longdouble')
50 partial_ld_off = partial_ld_offset()
51 return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)
52
53
54def partial_nested_fmt():
55 ld = np.dtype('longdouble')
56 partial_nested_off = 8 + 8 * (ld.alignment > 8)
57 partial_ld_off = partial_ld_offset()
58 partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize
59 return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format(
60 partial_dtype_fmt(), partial_nested_off, partial_nested_size)
Dean Moldovan23919172016-08-25 17:08:09 +020061
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020062
63def assert_equal(actual, expected_data, expected_dtype):
64 np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype))
65
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020066
Dean Moldovan665e8802016-08-12 22:28:31 +020067def test_format_descriptors():
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020068 from pybind11_tests import get_format_unbound, print_format_descriptors
69
70 with pytest.raises(RuntimeError) as excinfo:
71 get_format_unbound()
Ivan Smirnov2184f6d2016-10-31 13:52:32 +000072 assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020073
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050074 ld = np.dtype('longdouble')
75 ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char
Bruce Merryb82c0f02017-05-10 11:36:24 +020076 ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050077 dbl = np.dtype('double')
Bruce Merryb82c0f02017-05-10 11:36:24 +020078 partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" +
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050079 str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
80 "xg:ldbl_:}")
81 nested_extra = str(max(8, ld.alignment))
Dean Moldovan665e8802016-08-12 22:28:31 +020082 assert print_format_descriptors() == [
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050083 ss_fmt,
Bruce Merryb82c0f02017-05-10 11:36:24 +020084 "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
85 "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -050086 partial_fmt,
Bruce Merryb82c0f02017-05-10 11:36:24 +020087 "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
88 "^T{3s:a:3s:b:}",
89 "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}",
90 '^T{q:e1:B:e2:}',
91 '^T{Zf:cflt:Zd:cdbl:}'
Dean Moldovan665e8802016-08-12 22:28:31 +020092 ]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020093
94
Ivan Smirnovc5466552016-10-31 13:54:43 +000095def test_dtype(simple_dtype):
Dean Moldovan76e993a2016-12-13 00:59:28 +010096 from pybind11_tests import (print_dtypes, test_dtype_ctors, test_dtype_methods,
97 trailing_padding_dtype, buffer_to_dtype)
Jason Rhinelander0861be02017-02-25 16:43:01 -050098 from sys import byteorder
99 e = '<' if byteorder == 'little' else '>'
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200100
Dean Moldovan665e8802016-08-12 22:28:31 +0200101 assert print_dtypes() == [
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500102 simple_dtype_fmt(),
103 packed_dtype_fmt(),
104 "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
105 partial_dtype_fmt(),
106 partial_nested_fmt(),
Ivan Smirnov2f3f3682016-10-20 12:28:47 +0100107 "[('a', 'S3'), ('b', 'S3')]",
Bruce Merry8e0d8322017-05-10 10:21:01 +0200108 ("{{'names':['a','b','c','d'], " +
109 "'formats':[('S4', (3,)),('<i4', (2,)),('u1', (3,)),('<f4', (4, 2))], " +
110 "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e),
Jason Rhinelander0861be02017-02-25 16:43:01 -0500111 "[('e1', '" + e + "i8'), ('e2', 'u1')]",
Bruce Merryb82c0f02017-05-10 11:36:24 +0200112 "[('x', 'i1'), ('y', '" + e + "u8')]",
113 "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]"
Dean Moldovan665e8802016-08-12 22:28:31 +0200114 ]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200115
116 d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
117 'offsets': [1, 10], 'itemsize': 20})
118 d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
119 assert test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
120 np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
121
122 assert test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
123 np.dtype('int32').itemsize, simple_dtype.itemsize]
124
Patrick Stewart52715762016-11-22 14:56:52 +0000125 assert trailing_padding_dtype() == buffer_to_dtype(np.zeros(1, trailing_padding_dtype()))
126
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200127
Ivan Smirnovc5466552016-10-31 13:54:43 +0000128def test_recarray(simple_dtype, packed_dtype):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200129 from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
130 print_rec_simple, print_rec_packed, print_rec_nested,
131 create_rec_partial, create_rec_partial_nested)
132
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500133 elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200134
135 for func, dtype in [(create_rec_simple, simple_dtype), (create_rec_packed, packed_dtype)]:
136 arr = func(0)
137 assert arr.dtype == dtype
138 assert_equal(arr, [], simple_dtype)
139 assert_equal(arr, [], packed_dtype)
140
141 arr = func(3)
142 assert arr.dtype == dtype
143 assert_equal(arr, elements, simple_dtype)
144 assert_equal(arr, elements, packed_dtype)
145
146 if dtype == simple_dtype:
Dean Moldovan665e8802016-08-12 22:28:31 +0200147 assert print_rec_simple(arr) == [
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500148 "s:0,0,0,-0",
149 "s:1,1,1.5,-2.5",
150 "s:0,2,3,-5"
Dean Moldovan665e8802016-08-12 22:28:31 +0200151 ]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200152 else:
Dean Moldovan665e8802016-08-12 22:28:31 +0200153 assert print_rec_packed(arr) == [
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500154 "p:0,0,0,-0",
155 "p:1,1,1.5,-2.5",
156 "p:0,2,3,-5"
Dean Moldovan665e8802016-08-12 22:28:31 +0200157 ]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200158
159 nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
160
161 arr = create_rec_nested(0)
162 assert arr.dtype == nested_dtype
163 assert_equal(arr, [], nested_dtype)
164
165 arr = create_rec_nested(3)
166 assert arr.dtype == nested_dtype
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500167 assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
168 ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
169 ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype)
Dean Moldovan665e8802016-08-12 22:28:31 +0200170 assert print_rec_nested(arr) == [
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500171 "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
172 "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
173 "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5"
Dean Moldovan665e8802016-08-12 22:28:31 +0200174 ]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200175
176 arr = create_rec_partial(3)
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500177 assert str(arr.dtype) == partial_dtype_fmt()
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200178 partial_dtype = arr.dtype
179 assert '' not in arr.dtype.fields
180 assert partial_dtype.itemsize > simple_dtype.itemsize
181 assert_equal(arr, elements, simple_dtype)
182 assert_equal(arr, elements, packed_dtype)
183
184 arr = create_rec_partial_nested(3)
Jason Rhinelanderf7f5bc82017-01-31 11:00:15 -0500185 assert str(arr.dtype) == partial_nested_fmt()
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200186 assert '' not in arr.dtype.fields
187 assert '' not in arr.dtype.fields['a'][0].fields
188 assert arr.dtype.itemsize > partial_dtype.itemsize
189 np.testing.assert_equal(arr['a'], create_rec_partial(3))
190
191
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200192def test_array_constructors():
193 from pybind11_tests import test_array_ctors
194
195 data = np.arange(1, 7, dtype='int32')
196 for i in range(8):
197 np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2)))
198 np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2)))
199 for i in range(5):
200 np.testing.assert_array_equal(test_array_ctors(30 + i), data)
201 np.testing.assert_array_equal(test_array_ctors(40 + i), data)
202
203
Dean Moldovan665e8802016-08-12 22:28:31 +0200204def test_string_array():
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200205 from pybind11_tests import create_string_array, print_string_array
206
207 arr = create_string_array(True)
208 assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
Dean Moldovan665e8802016-08-12 22:28:31 +0200209 assert print_string_array(arr) == [
210 "a='',b=''",
211 "a='a',b='a'",
212 "a='ab',b='ab'",
213 "a='abc',b='abc'"
214 ]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200215 dtype = arr.dtype
216 assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
217 assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
218 arr = create_string_array(False)
219 assert dtype == arr.dtype
220
221
Bruce Merry8e0d8322017-05-10 10:21:01 +0200222def test_array_array():
223 from pybind11_tests import create_array_array, print_array_array
224 from sys import byteorder
225 e = '<' if byteorder == 'little' else '>'
226
227 arr = create_array_array(3)
228 assert str(arr.dtype) == (
229 "{{'names':['a','b','c','d'], " +
230 "'formats':[('S4', (3,)),('<i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +
231 "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e)
232 assert print_array_array(arr) == [
233 "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +
234 "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
235 "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +
236 "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
237 "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," +
238 "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
239 ]
240 assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'],
241 [b'WXYZ', b'GHIJ', b'QRST'],
242 [b'STUV', b'CDEF', b'MNOP']]
243 assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
244 assert create_array_array(0).dtype == arr.dtype
245
246
Ivan Smirnov2f3f3682016-10-20 12:28:47 +0100247def test_enum_array():
248 from pybind11_tests import create_enum_array, print_enum_array
Jason Rhinelander0861be02017-02-25 16:43:01 -0500249 from sys import byteorder
250 e = '<' if byteorder == 'little' else '>'
Ivan Smirnov2f3f3682016-10-20 12:28:47 +0100251
252 arr = create_enum_array(3)
253 dtype = arr.dtype
Jason Rhinelander0861be02017-02-25 16:43:01 -0500254 assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')])
Ivan Smirnov2f3f3682016-10-20 12:28:47 +0100255 assert print_enum_array(arr) == [
256 "e1=A,e2=X",
257 "e1=B,e2=Y",
258 "e1=A,e2=X"
259 ]
260 assert arr['e1'].tolist() == [-1, 1, -1]
261 assert arr['e2'].tolist() == [1, 2, 1]
262 assert create_enum_array(0).dtype == dtype
263
264
Bruce Merryb82c0f02017-05-10 11:36:24 +0200265def test_complex_array():
266 from pybind11_tests import create_complex_array, print_complex_array
267 from sys import byteorder
268 e = '<' if byteorder == 'little' else '>'
269
270 arr = create_complex_array(3)
271 dtype = arr.dtype
272 assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')])
273 assert print_complex_array(arr) == [
274 "c:(0,0.25),(0.5,0.75)",
275 "c:(1,1.25),(1.5,1.75)",
276 "c:(2,2.25),(2.5,2.75)"
277 ]
278 assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
279 assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
280 assert create_complex_array(0).dtype == dtype
281
282
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200283def test_signature(doc):
284 from pybind11_tests import create_rec_nested
285
286 assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
Ivan Smirnovcbbb7832016-10-20 16:47:29 +0100287
288
Ivan Smirnovcbbb7832016-10-20 16:47:29 +0100289def test_scalar_conversion():
290 from pybind11_tests import (create_rec_simple, f_simple,
291 create_rec_packed, f_packed,
292 create_rec_nested, f_nested,
293 create_enum_array)
294
295 n = 3
296 arrays = [create_rec_simple(n), create_rec_packed(n),
297 create_rec_nested(n), create_enum_array(n)]
298 funcs = [f_simple, f_packed, f_nested]
299
300 for i, func in enumerate(funcs):
301 for j, arr in enumerate(arrays):
Ivan Smirnova6e6a8b2016-10-23 15:27:13 +0100302 if i == j and i < 2:
Ivan Smirnovcbbb7832016-10-20 16:47:29 +0100303 assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)]
304 else:
305 with pytest.raises(TypeError) as excinfo:
306 func(arr[0])
307 assert 'incompatible function arguments' in str(excinfo.value)
Ivan Smirnov7edd72d2016-10-20 16:57:12 +0100308
309
Ivan Smirnov7edd72d2016-10-20 16:57:12 +0100310def test_register_dtype():
311 from pybind11_tests import register_dtype
312
313 with pytest.raises(RuntimeError) as excinfo:
314 register_dtype()
315 assert 'dtype is already registered' in str(excinfo.value)
Patrick Stewart0b6d08a2016-11-21 17:40:43 +0000316
317
318@pytest.requires_numpy
319def test_compare_buffer_info():
320 from pybind11_tests import compare_buffer_info
321 assert all(compare_buffer_info())