cppyabm  1.0.17
An agent-based library to integrate C++ and Python
test_numpy_dtypes.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 import re
3 
4 import pytest
5 
6 import env # noqa: F401
7 
8 from pybind11_tests import numpy_dtypes as m
9 
10 np = pytest.importorskip("numpy")
11 
12 
13 @pytest.fixture(scope="module")
15  ld = np.dtype("longdouble")
16  return np.dtype(
17  {
18  "names": ["bool_", "uint_", "float_", "ldbl_"],
19  "formats": ["?", "u4", "f4", "f{}".format(ld.itemsize)],
20  "offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)],
21  }
22  )
23 
24 
25 @pytest.fixture(scope="module")
27  return np.dtype([("bool_", "?"), ("uint_", "u4"), ("float_", "f4"), ("ldbl_", "g")])
28 
29 
30 def dt_fmt():
31  from sys import byteorder
32 
33  e = "<" if byteorder == "little" else ">"
34  return (
35  "{{'names':['bool_','uint_','float_','ldbl_'],"
36  " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}'],"
37  " 'offsets':[0,4,8,{}], 'itemsize':{}}}"
38  )
39 
40 
42  ld = np.dtype("longdouble")
43  simple_ld_off = 12 + 4 * (ld.alignment > 4)
44  return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize)
45 
46 
48  from sys import byteorder
49 
50  return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format(
51  np.dtype("longdouble").itemsize, e="<" if byteorder == "little" else ">"
52  )
53 
54 
56  return (
57  12
58  + 4 * (np.dtype("uint64").alignment > 4)
59  + 8
60  + 8 * (np.dtype("longdouble").alignment > 8)
61  )
62 
63 
65  ld = np.dtype("longdouble")
66  partial_ld_off = partial_ld_offset()
67  return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize)
68 
69 
71  ld = np.dtype("longdouble")
72  partial_nested_off = 8 + 8 * (ld.alignment > 8)
73  partial_ld_off = partial_ld_offset()
74  partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize
75  return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format(
76  partial_dtype_fmt(), partial_nested_off, partial_nested_size
77  )
78 
79 
80 def assert_equal(actual, expected_data, expected_dtype):
81  np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype))
82 
83 
85  with pytest.raises(RuntimeError) as excinfo:
86  m.get_format_unbound()
87  assert re.match(
88  "^NumPy type info missing for .*UnboundStruct.*$", str(excinfo.value)
89  )
90 
91  ld = np.dtype("longdouble")
92  ldbl_fmt = ("4x" if ld.alignment > 4 else "") + ld.char
93  ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
94  dbl = np.dtype("double")
95  partial_fmt = (
96  "^T{?:bool_:3xI:uint_:f:float_:"
97  + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8))
98  + "xg:ldbl_:}"
99  )
100  nested_extra = str(max(8, ld.alignment))
101  assert m.print_format_descriptors() == [
102  ss_fmt,
103  "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
104  "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
105  partial_fmt,
106  "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
107  "^T{3s:a:3s:b:}",
108  "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}",
109  "^T{q:e1:B:e2:}",
110  "^T{Zf:cflt:Zd:cdbl:}",
111  ]
112 
113 
114 def test_dtype(simple_dtype):
115  from sys import byteorder
116 
117  e = "<" if byteorder == "little" else ">"
118 
119  assert m.print_dtypes() == [
122  "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
125  "[('a', 'S3'), ('b', 'S3')]",
126  (
127  "{{'names':['a','b','c','d'], "
128  + "'formats':[('S4', (3,)),('"
129  + e
130  + "i4', (2,)),('u1', (3,)),('"
131  + e
132  + "f4', (4, 2))], "
133  + "'offsets':[0,12,20,24], 'itemsize':56}}"
134  ).format(e=e),
135  "[('e1', '" + e + "i8'), ('e2', 'u1')]",
136  "[('x', 'i1'), ('y', '" + e + "u8')]",
137  "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]",
138  ]
139 
140  d1 = np.dtype(
141  {
142  "names": ["a", "b"],
143  "formats": ["int32", "float64"],
144  "offsets": [1, 10],
145  "itemsize": 20,
146  }
147  )
148  d2 = np.dtype([("a", "i4"), ("b", "f4")])
149  assert m.test_dtype_ctors() == [
150  np.dtype("int32"),
151  np.dtype("float64"),
152  np.dtype("bool"),
153  d1,
154  d1,
155  np.dtype("uint32"),
156  d2,
157  ]
158 
159  assert m.test_dtype_methods() == [
160  np.dtype("int32"),
161  simple_dtype,
162  False,
163  True,
164  np.dtype("int32").itemsize,
165  simple_dtype.itemsize,
166  ]
167 
168  assert m.trailing_padding_dtype() == m.buffer_to_dtype(
169  np.zeros(1, m.trailing_padding_dtype())
170  )
171 
172 
173 def test_recarray(simple_dtype, packed_dtype):
174  elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
175 
176  for func, dtype in [
177  (m.create_rec_simple, simple_dtype),
178  (m.create_rec_packed, packed_dtype),
179  ]:
180  arr = func(0)
181  assert arr.dtype == dtype
182  assert_equal(arr, [], simple_dtype)
183  assert_equal(arr, [], packed_dtype)
184 
185  arr = func(3)
186  assert arr.dtype == dtype
187  assert_equal(arr, elements, simple_dtype)
188  assert_equal(arr, elements, packed_dtype)
189 
190  # Show what recarray's look like in NumPy.
191  assert type(arr[0]) == np.void
192  assert type(arr[0].item()) == tuple
193 
194  if dtype == simple_dtype:
195  assert m.print_rec_simple(arr) == [
196  "s:0,0,0,-0",
197  "s:1,1,1.5,-2.5",
198  "s:0,2,3,-5",
199  ]
200  else:
201  assert m.print_rec_packed(arr) == [
202  "p:0,0,0,-0",
203  "p:1,1,1.5,-2.5",
204  "p:0,2,3,-5",
205  ]
206 
207  nested_dtype = np.dtype([("a", simple_dtype), ("b", packed_dtype)])
208 
209  arr = m.create_rec_nested(0)
210  assert arr.dtype == nested_dtype
211  assert_equal(arr, [], nested_dtype)
212 
213  arr = m.create_rec_nested(3)
214  assert arr.dtype == nested_dtype
215  assert_equal(
216  arr,
217  [
218  ((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
219  ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
220  ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5)),
221  ],
222  nested_dtype,
223  )
224  assert m.print_rec_nested(arr) == [
225  "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
226  "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
227  "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5",
228  ]
229 
230  arr = m.create_rec_partial(3)
231  assert str(arr.dtype) == partial_dtype_fmt()
232  partial_dtype = arr.dtype
233  assert "" not in arr.dtype.fields
234  assert partial_dtype.itemsize > simple_dtype.itemsize
235  assert_equal(arr, elements, simple_dtype)
236  assert_equal(arr, elements, packed_dtype)
237 
238  arr = m.create_rec_partial_nested(3)
239  assert str(arr.dtype) == partial_nested_fmt()
240  assert "" not in arr.dtype.fields
241  assert "" not in arr.dtype.fields["a"][0].fields
242  assert arr.dtype.itemsize > partial_dtype.itemsize
243  np.testing.assert_equal(arr["a"], m.create_rec_partial(3))
244 
245 
247  data = np.arange(1, 7, dtype="int32")
248  for i in range(8):
249  np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))
250  np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2)))
251  for i in range(5):
252  np.testing.assert_array_equal(m.test_array_ctors(30 + i), data)
253  np.testing.assert_array_equal(m.test_array_ctors(40 + i), data)
254 
255 
257  arr = m.create_string_array(True)
258  assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
259  assert m.print_string_array(arr) == [
260  "a='',b=''",
261  "a='a',b='a'",
262  "a='ab',b='ab'",
263  "a='abc',b='abc'",
264  ]
265  dtype = arr.dtype
266  assert arr["a"].tolist() == [b"", b"a", b"ab", b"abc"]
267  assert arr["b"].tolist() == [b"", b"a", b"ab", b"abc"]
268  arr = m.create_string_array(False)
269  assert dtype == arr.dtype
270 
271 
273  from sys import byteorder
274 
275  e = "<" if byteorder == "little" else ">"
276 
277  arr = m.create_array_array(3)
278  assert str(arr.dtype) == (
279  "{{'names':['a','b','c','d'], "
280  + "'formats':[('S4', (3,)),('"
281  + e
282  + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], "
283  + "'offsets':[0,12,20,24], 'itemsize':56}}"
284  ).format(e=e)
285  assert m.print_array_array(arr) == [
286  "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1},"
287  + "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
288  "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001},"
289  + "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
290  "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001},"
291  + "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
292  ]
293  assert arr["a"].tolist() == [
294  [b"ABCD", b"KLMN", b"UVWX"],
295  [b"WXYZ", b"GHIJ", b"QRST"],
296  [b"STUV", b"CDEF", b"MNOP"],
297  ]
298  assert arr["b"].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
299  assert m.create_array_array(0).dtype == arr.dtype
300 
301 
303  from sys import byteorder
304 
305  e = "<" if byteorder == "little" else ">"
306 
307  arr = m.create_enum_array(3)
308  dtype = arr.dtype
309  assert dtype == np.dtype([("e1", e + "i8"), ("e2", "u1")])
310  assert m.print_enum_array(arr) == ["e1=A,e2=X", "e1=B,e2=Y", "e1=A,e2=X"]
311  assert arr["e1"].tolist() == [-1, 1, -1]
312  assert arr["e2"].tolist() == [1, 2, 1]
313  assert m.create_enum_array(0).dtype == dtype
314 
315 
317  from sys import byteorder
318 
319  e = "<" if byteorder == "little" else ">"
320 
321  arr = m.create_complex_array(3)
322  dtype = arr.dtype
323  assert dtype == np.dtype([("cflt", e + "c8"), ("cdbl", e + "c16")])
324  assert m.print_complex_array(arr) == [
325  "c:(0,0.25),(0.5,0.75)",
326  "c:(1,1.25),(1.5,1.75)",
327  "c:(2,2.25),(2.5,2.75)",
328  ]
329  assert arr["cflt"].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
330  assert arr["cdbl"].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
331  assert m.create_complex_array(0).dtype == dtype
332 
333 
334 def test_signature(doc):
335  assert (
336  doc(m.create_rec_nested)
337  == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
338  )
339 
340 
342  n = 3
343  arrays = [
344  m.create_rec_simple(n),
345  m.create_rec_packed(n),
346  m.create_rec_nested(n),
347  m.create_enum_array(n),
348  ]
349  funcs = [m.f_simple, m.f_packed, m.f_nested]
350 
351  for i, func in enumerate(funcs):
352  for j, arr in enumerate(arrays):
353  if i == j and i < 2:
354  assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)]
355  else:
356  with pytest.raises(TypeError) as excinfo:
357  func(arr[0])
358  assert "incompatible function arguments" in str(excinfo.value)
359 
360 
362  n = 3
363  array = m.create_rec_simple(n)
364  values = m.f_simple_vectorized(array)
365  np.testing.assert_array_equal(values, [0, 10, 20])
366  array_2 = m.f_simple_pass_thru_vectorized(array)
367  np.testing.assert_array_equal(array, array_2)
368 
369 
371  s = m.SimpleStruct()
372  assert s.astuple() == (False, 0, 0.0, 0.0)
373  assert m.SimpleStruct.fromtuple(s.astuple()).astuple() == s.astuple()
374 
375  s.uint_ = 2
376  assert m.f_simple(s) == 20
377 
378  # Try as recarray of shape==(1,).
379  s_recarray = np.array([(False, 2, 0.0, 0.0)], dtype=simple_dtype)
380  # Show that this will work for vectorized case.
381  np.testing.assert_array_equal(m.f_simple_vectorized(s_recarray), [20])
382 
383  # Show as a scalar that inherits from np.generic.
384  s_scalar = s_recarray[0]
385  assert isinstance(s_scalar, np.void)
386  assert m.f_simple(s_scalar) == 20
387 
388  # Show that an *array* scalar (np.ndarray.shape == ()) does not convert.
389  # More specifically, conversion to SimpleStruct is not implicit.
390  s_recarray_scalar = s_recarray.reshape(())
391  assert isinstance(s_recarray_scalar, np.ndarray)
392  assert s_recarray_scalar.dtype == simple_dtype
393  with pytest.raises(TypeError) as excinfo:
394  m.f_simple(s_recarray_scalar)
395  assert "incompatible function arguments" in str(excinfo.value)
396  # Explicitly convert to m.SimpleStruct.
397  assert m.f_simple(m.SimpleStruct.fromtuple(s_recarray_scalar.item())) == 20
398 
399  # Show that an array of dtype=object does *not* convert.
400  s_array_object = np.array([s])
401  assert s_array_object.dtype == object
402  with pytest.raises(TypeError) as excinfo:
403  m.f_simple_vectorized(s_array_object)
404  assert "incompatible function arguments" in str(excinfo.value)
405  # Explicitly convert to `np.array(..., dtype=simple_dtype)`
406  s_array = np.array([s.astuple()], dtype=simple_dtype)
407  np.testing.assert_array_equal(m.f_simple_vectorized(s_array), [20])
408 
409 
411  with pytest.raises(RuntimeError) as excinfo:
412  m.register_dtype()
413  assert "dtype is already registered" in str(excinfo.value)
414 
415 
416 @pytest.mark.xfail("env.PYPY")
418  from sys import getrefcount
419 
420  fmt = "f4"
421  pytest.gc_collect()
422  start = getrefcount(fmt)
423  d = m.dtype_wrapper(fmt)
424  assert d is np.dtype("f4")
425  del d
426  pytest.gc_collect()
427  assert getrefcount(fmt) == start
428 
429 
431  assert all(m.compare_buffer_info())
test_numpy_dtypes.test_complex_array
def test_complex_array()
Definition: test_numpy_dtypes.py:316
test_numpy_dtypes.test_recarray
def test_recarray(simple_dtype, packed_dtype)
Definition: test_numpy_dtypes.py:173
test_numpy_dtypes.test_vectorize
def test_vectorize()
Definition: test_numpy_dtypes.py:361
test_numpy_dtypes.simple_dtype_fmt
def simple_dtype_fmt()
Definition: test_numpy_dtypes.py:41
test_numpy_dtypes.packed_dtype
def packed_dtype()
Definition: test_numpy_dtypes.py:26
test_numpy_dtypes.simple_dtype
def simple_dtype()
Definition: test_numpy_dtypes.py:14
test_numpy_dtypes.test_array_array
def test_array_array()
Definition: test_numpy_dtypes.py:272
test_numpy_dtypes.test_cls_and_dtype_conversion
def test_cls_and_dtype_conversion(simple_dtype)
Definition: test_numpy_dtypes.py:370
type
Definition: pytypes.h:915
test_numpy_dtypes.partial_nested_fmt
def partial_nested_fmt()
Definition: test_numpy_dtypes.py:70
test_numpy_dtypes.test_register_dtype
def test_register_dtype()
Definition: test_numpy_dtypes.py:410
test_numpy_dtypes.partial_dtype_fmt
def partial_dtype_fmt()
Definition: test_numpy_dtypes.py:64
test_numpy_dtypes.dt_fmt
def dt_fmt()
Definition: test_numpy_dtypes.py:30
test_numpy_dtypes.test_str_leak
def test_str_leak()
Definition: test_numpy_dtypes.py:417
doc
Annotation for documentation.
Definition: attr.h:33
isinstance
bool isinstance(handle obj)
Definition: pytypes.h:386
test_numpy_dtypes.test_signature
def test_signature(doc)
Definition: test_numpy_dtypes.py:334
test_numpy_dtypes.test_dtype
def test_dtype(simple_dtype)
Definition: test_numpy_dtypes.py:114
test_numpy_dtypes.test_array_constructors
def test_array_constructors()
Definition: test_numpy_dtypes.py:246
test_numpy_dtypes.test_string_array
def test_string_array()
Definition: test_numpy_dtypes.py:256
test_numpy_dtypes.test_enum_array
def test_enum_array()
Definition: test_numpy_dtypes.py:302
test_numpy_dtypes.test_format_descriptors
def test_format_descriptors()
Definition: test_numpy_dtypes.py:84
str
Definition: pytypes.h:946
test_numpy_dtypes.assert_equal
def assert_equal(actual, expected_data, expected_dtype)
Definition: test_numpy_dtypes.py:80
test_numpy_dtypes.partial_ld_offset
def partial_ld_offset()
Definition: test_numpy_dtypes.py:55
test_numpy_dtypes.test_scalar_conversion
def test_scalar_conversion()
Definition: test_numpy_dtypes.py:341
test_numpy_dtypes.packed_dtype_fmt
def packed_dtype_fmt()
Definition: test_numpy_dtypes.py:47
test_numpy_dtypes.test_compare_buffer_info
def test_compare_buffer_info()
Definition: test_numpy_dtypes.py:430