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


gtsam
Author(s):
autogenerated on Thu Jul 4 2024 03:06:01