test_builtin_casters.py
Go to the documentation of this file.
1 from __future__ import annotations
2 
3 import sys
4 
5 import pytest
6 
7 import env
8 from pybind11_tests import IncType, UserType
9 from pybind11_tests import builtin_casters as m
10 
11 
12 def test_simple_string():
13  assert m.string_roundtrip("const char *") == "const char *"
14 
15 
17  """Tests unicode conversion and error reporting."""
18  assert m.good_utf8_string() == "Say utf8β€½ πŸŽ‚ 𝐀"
19  assert m.good_utf16_string() == "bβ€½πŸŽ‚π€z"
20  assert m.good_utf32_string() == "aπ€πŸŽ‚β€½z"
21  assert m.good_wchar_string() == "aβΈ˜π€z"
22  if hasattr(m, "has_u8string"):
23  assert m.good_utf8_u8string() == "Say utf8β€½ πŸŽ‚ 𝐀"
24 
25  with pytest.raises(UnicodeDecodeError):
26  m.bad_utf8_string()
27 
28  with pytest.raises(UnicodeDecodeError):
29  m.bad_utf16_string()
30 
31  # These are provided only if they actually fail (they don't when 32-bit)
32  if hasattr(m, "bad_utf32_string"):
33  with pytest.raises(UnicodeDecodeError):
34  m.bad_utf32_string()
35  if hasattr(m, "bad_wchar_string"):
36  with pytest.raises(UnicodeDecodeError):
37  m.bad_wchar_string()
38  if hasattr(m, "has_u8string"):
39  with pytest.raises(UnicodeDecodeError):
40  m.bad_utf8_u8string()
41 
42  assert m.u8_Z() == "Z"
43  assert m.u8_eacute() == "Γ©"
44  assert m.u16_ibang() == "β€½"
45  assert m.u32_mathbfA() == "𝐀"
46  assert m.wchar_heart() == "β™₯"
47  if hasattr(m, "has_u8string"):
48  assert m.u8_char8_Z() == "Z"
49 
50 
52  """Tests failures for passing invalid inputs to char-accepting functions"""
53 
54  def toobig_message(r):
55  return f"Character code point not in range({r:#x})"
56 
57  toolong_message = "Expected a character, but multi-character string found"
58 
59  assert m.ord_char("a") == 0x61 # simple ASCII
60  assert m.ord_char_lv("b") == 0x62
61  assert (
62  m.ord_char("Γ©") == 0xE9
63  ) # requires 2 bytes in utf-8, but can be stuffed in a char
64  with pytest.raises(ValueError) as excinfo:
65  assert m.ord_char("Δ€") == 0x100 # requires 2 bytes, doesn't fit in a char
66  assert str(excinfo.value) == toobig_message(0x100)
67  with pytest.raises(ValueError) as excinfo:
68  assert m.ord_char("ab")
69  assert str(excinfo.value) == toolong_message
70 
71  assert m.ord_char16("a") == 0x61
72  assert m.ord_char16("Γ©") == 0xE9
73  assert m.ord_char16_lv("Γͺ") == 0xEA
74  assert m.ord_char16("Δ€") == 0x100
75  assert m.ord_char16("β€½") == 0x203D
76  assert m.ord_char16("β™₯") == 0x2665
77  assert m.ord_char16_lv("β™‘") == 0x2661
78  with pytest.raises(ValueError) as excinfo:
79  assert m.ord_char16("πŸŽ‚") == 0x1F382 # requires surrogate pair
80  assert str(excinfo.value) == toobig_message(0x10000)
81  with pytest.raises(ValueError) as excinfo:
82  assert m.ord_char16("aa")
83  assert str(excinfo.value) == toolong_message
84 
85  assert m.ord_char32("a") == 0x61
86  assert m.ord_char32("Γ©") == 0xE9
87  assert m.ord_char32("Δ€") == 0x100
88  assert m.ord_char32("β€½") == 0x203D
89  assert m.ord_char32("β™₯") == 0x2665
90  assert m.ord_char32("πŸŽ‚") == 0x1F382
91  with pytest.raises(ValueError) as excinfo:
92  assert m.ord_char32("aa")
93  assert str(excinfo.value) == toolong_message
94 
95  assert m.ord_wchar("a") == 0x61
96  assert m.ord_wchar("Γ©") == 0xE9
97  assert m.ord_wchar("Δ€") == 0x100
98  assert m.ord_wchar("β€½") == 0x203D
99  assert m.ord_wchar("β™₯") == 0x2665
100  if m.wchar_size == 2:
101  with pytest.raises(ValueError) as excinfo:
102  assert m.ord_wchar("πŸŽ‚") == 0x1F382 # requires surrogate pair
103  assert str(excinfo.value) == toobig_message(0x10000)
104  else:
105  assert m.ord_wchar("πŸŽ‚") == 0x1F382
106  with pytest.raises(ValueError) as excinfo:
107  assert m.ord_wchar("aa")
108  assert str(excinfo.value) == toolong_message
109 
110  if hasattr(m, "has_u8string"):
111  assert m.ord_char8("a") == 0x61 # simple ASCII
112  assert m.ord_char8_lv("b") == 0x62
113  assert (
114  m.ord_char8("Γ©") == 0xE9
115  ) # requires 2 bytes in utf-8, but can be stuffed in a char
116  with pytest.raises(ValueError) as excinfo:
117  assert m.ord_char8("Δ€") == 0x100 # requires 2 bytes, doesn't fit in a char
118  assert str(excinfo.value) == toobig_message(0x100)
119  with pytest.raises(ValueError) as excinfo:
120  assert m.ord_char8("ab")
121  assert str(excinfo.value) == toolong_message
122 
123 
125  """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
126  one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
127  # Issue #816
128 
129  assert m.strlen(b"hi") == 2
130  assert m.string_length(b"world") == 5
131  assert m.string_length(b"a\x00b") == 3
132  assert m.strlen(b"a\x00b") == 1 # C-string limitation
133 
134  # passing in a utf8 encoded string should work
135  assert m.string_length("πŸ’©".encode()) == 4
136 
137 
139  """Tests the ability to pass bytearray to C++ string-accepting functions"""
140  assert m.string_length(bytearray(b"Hi")) == 2
141  assert m.strlen(bytearray(b"bytearray")) == 9
142  assert m.string_length(bytearray()) == 0
143  assert m.string_length(bytearray("🦜", "utf-8", "strict")) == 4
144  assert m.string_length(bytearray(b"\x80")) == 1
145 
146 
147 @pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
148 def test_string_view(capture):
149  """Tests support for C++17 string_view arguments and return values"""
150  assert m.string_view_chars("Hi") == [72, 105]
151  assert m.string_view_chars("Hi πŸŽ‚") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
152  assert m.string_view16_chars("Hi πŸŽ‚") == [72, 105, 32, 0xD83C, 0xDF82]
153  assert m.string_view32_chars("Hi πŸŽ‚") == [72, 105, 32, 127874]
154  if hasattr(m, "has_u8string"):
155  assert m.string_view8_chars("Hi") == [72, 105]
156  assert m.string_view8_chars("Hi πŸŽ‚") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
157 
158  assert m.string_view_return() == "utf8 secret πŸŽ‚"
159  assert m.string_view16_return() == "utf16 secret πŸŽ‚"
160  assert m.string_view32_return() == "utf32 secret πŸŽ‚"
161  if hasattr(m, "has_u8string"):
162  assert m.string_view8_return() == "utf8 secret πŸŽ‚"
163 
164  with capture:
165  m.string_view_print("Hi")
166  m.string_view_print("utf8 πŸŽ‚")
167  m.string_view16_print("utf16 πŸŽ‚")
168  m.string_view32_print("utf32 πŸŽ‚")
169  assert (
170  capture
171  == """
172  Hi 2
173  utf8 πŸŽ‚ 9
174  utf16 πŸŽ‚ 8
175  utf32 πŸŽ‚ 7
176  """
177  )
178  if hasattr(m, "has_u8string"):
179  with capture:
180  m.string_view8_print("Hi")
181  m.string_view8_print("utf8 πŸŽ‚")
182  assert (
183  capture
184  == """
185  Hi 2
186  utf8 πŸŽ‚ 9
187  """
188  )
189 
190  with capture:
191  m.string_view_print("Hi, ascii")
192  m.string_view_print("Hi, utf8 πŸŽ‚")
193  m.string_view16_print("Hi, utf16 πŸŽ‚")
194  m.string_view32_print("Hi, utf32 πŸŽ‚")
195  assert (
196  capture
197  == """
198  Hi, ascii 9
199  Hi, utf8 πŸŽ‚ 13
200  Hi, utf16 πŸŽ‚ 12
201  Hi, utf32 πŸŽ‚ 11
202  """
203  )
204  if hasattr(m, "has_u8string"):
205  with capture:
206  m.string_view8_print("Hi, ascii")
207  m.string_view8_print("Hi, utf8 πŸŽ‚")
208  assert (
209  capture
210  == """
211  Hi, ascii 9
212  Hi, utf8 πŸŽ‚ 13
213  """
214  )
215 
216  assert m.string_view_bytes() == b"abc \x80\x80 def"
217  assert m.string_view_str() == "abc β€½ def"
218  assert m.string_view_from_bytes("abc β€½ def".encode()) == "abc β€½ def"
219  if hasattr(m, "has_u8string"):
220  assert m.string_view8_str() == "abc β€½ def"
221  assert m.string_view_memoryview() == "Have some πŸŽ‚".encode()
222 
223  assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
224  assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
225 
226 
228  """Issue #929 - out-of-range integer values shouldn't be accepted"""
229  assert m.i32_str(-1) == "-1"
230  assert m.i64_str(-1) == "-1"
231  assert m.i32_str(2000000000) == "2000000000"
232  assert m.u32_str(2000000000) == "2000000000"
233  assert m.i64_str(-999999999999) == "-999999999999"
234  assert m.u64_str(999999999999) == "999999999999"
235 
236  with pytest.raises(TypeError) as excinfo:
237  m.u32_str(-1)
238  assert "incompatible function arguments" in str(excinfo.value)
239  with pytest.raises(TypeError) as excinfo:
240  m.u64_str(-1)
241  assert "incompatible function arguments" in str(excinfo.value)
242  with pytest.raises(TypeError) as excinfo:
243  m.i32_str(-3000000000)
244  assert "incompatible function arguments" in str(excinfo.value)
245  with pytest.raises(TypeError) as excinfo:
246  m.i32_str(3000000000)
247  assert "incompatible function arguments" in str(excinfo.value)
248 
249 
251  class Int:
252  def __int__(self):
253  return 42
254 
255  class NotInt:
256  pass
257 
258  class Float:
259  def __float__(self):
260  return 41.99999
261 
262  class Index:
263  def __index__(self):
264  return 42
265 
266  class IntAndIndex:
267  def __int__(self):
268  return 42
269 
270  def __index__(self):
271  return 0
272 
273  class RaisingTypeErrorOnIndex:
274  def __index__(self):
275  raise TypeError
276 
277  def __int__(self):
278  return 42
279 
280  class RaisingValueErrorOnIndex:
281  def __index__(self):
282  raise ValueError
283 
284  def __int__(self):
285  return 42
286 
287  convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
288 
289  def requires_conversion(v):
290  pytest.raises(TypeError, noconvert, v)
291 
292  def cant_convert(v):
293  pytest.raises(TypeError, convert, v)
294 
295  assert convert(7) == 7
296  assert noconvert(7) == 7
297  cant_convert(3.14159)
298  # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
299  # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
300  if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
301  with env.deprecated_call():
302  assert convert(Int()) == 42
303  else:
304  assert convert(Int()) == 42
305  requires_conversion(Int())
306  cant_convert(NotInt())
307  cant_convert(Float())
308 
309  # Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`,
310  # but pybind11 "backports" this behavior.
311  assert convert(Index()) == 42
312  assert noconvert(Index()) == 42
313  assert convert(IntAndIndex()) == 0 # Fishy; `int(DoubleThought)` == 42
314  assert noconvert(IntAndIndex()) == 0
315  assert convert(RaisingTypeErrorOnIndex()) == 42
316  requires_conversion(RaisingTypeErrorOnIndex())
317  assert convert(RaisingValueErrorOnIndex()) == 42
318  requires_conversion(RaisingValueErrorOnIndex())
319 
320 
322  np = pytest.importorskip("numpy")
323 
324  convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
325 
326  def require_implicit(v):
327  pytest.raises(TypeError, noconvert, v)
328 
329  # `np.intc` is an alias that corresponds to a C++ `int`
330  assert convert(np.intc(42)) == 42
331  assert noconvert(np.intc(42)) == 42
332 
333  # The implicit conversion from np.float32 is undesirable but currently accepted.
334  # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
335  # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
336  # https://github.com/pybind/pybind11/issues/3408
337  if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
338  with env.deprecated_call():
339  assert convert(np.float32(3.14159)) == 3
340  else:
341  assert convert(np.float32(3.14159)) == 3
342  require_implicit(np.float32(3.14159))
343 
344 
345 def test_tuple(doc):
346  """std::pair <-> tuple & std::tuple <-> tuple"""
347  assert m.pair_passthrough((True, "test")) == ("test", True)
348  assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
349  # Any sequence can be cast to a std::pair or std::tuple
350  assert m.pair_passthrough([True, "test"]) == ("test", True)
351  assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
352  assert m.empty_tuple() == ()
353 
354  assert (
355  doc(m.pair_passthrough)
356  == """
357  pair_passthrough(arg0: tuple[bool, str]) -> tuple[str, bool]
358 
359  Return a pair in reversed order
360  """
361  )
362  assert (
363  doc(m.tuple_passthrough)
364  == """
365  tuple_passthrough(arg0: tuple[bool, str, int]) -> tuple[int, str, bool]
366 
367  Return a triple in reversed order
368  """
369  )
370 
371  assert m.rvalue_pair() == ("rvalue", "rvalue")
372  assert m.lvalue_pair() == ("lvalue", "lvalue")
373  assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
374  assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
375  assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
376  assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
377 
378  assert m.int_string_pair() == (2, "items")
379 
380 
382  """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
383  assert m.return_none_string() is None
384  assert m.return_none_char() is None
385  assert m.return_none_bool() is None
386  assert m.return_none_int() is None
387  assert m.return_none_float() is None
388  assert m.return_none_pair() is None
389 
390 
392  """None passed as various argument types should defer to other overloads"""
393  assert not m.defer_none_cstring("abc")
394  assert m.defer_none_cstring(None)
395  assert not m.defer_none_custom(UserType())
396  assert m.defer_none_custom(None)
397  assert m.nodefer_none_void(None)
398 
399 
401  assert m.load_nullptr_t(None) is None
402  assert m.cast_nullptr_t() is None
403 
404 
406  """std::reference_wrapper for builtin and user types"""
407  assert m.refwrap_builtin(42) == 420
408  assert m.refwrap_usertype(UserType(42)) == 42
409  assert m.refwrap_usertype_const(UserType(42)) == 42
410 
411  with pytest.raises(TypeError) as excinfo:
412  m.refwrap_builtin(None)
413  assert "incompatible function arguments" in str(excinfo.value)
414 
415  with pytest.raises(TypeError) as excinfo:
416  m.refwrap_usertype(None)
417  assert "incompatible function arguments" in str(excinfo.value)
418 
419  assert m.refwrap_lvalue().value == 1
420  assert m.refwrap_lvalue_const().value == 1
421 
422  a1 = m.refwrap_list(copy=True)
423  a2 = m.refwrap_list(copy=True)
424  assert [x.value for x in a1] == [2, 3]
425  assert [x.value for x in a2] == [2, 3]
426  assert a1[0] is not a2[0]
427  assert a1[1] is not a2[1]
428 
429  b1 = m.refwrap_list(copy=False)
430  b2 = m.refwrap_list(copy=False)
431  assert [x.value for x in b1] == [1, 2]
432  assert [x.value for x in b2] == [1, 2]
433  assert b1[0] is b2[0]
434  assert b1[1] is b2[1]
435 
436  assert m.refwrap_iiw(IncType(5)) == 5
437  assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
438 
439 
441  """std::complex casts"""
442  assert m.complex_cast(1) == "1.0"
443  assert m.complex_cast(2j) == "(0.0, 2.0)"
444 
445 
447  """Test bool caster implicit conversions."""
448  convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
449 
450  def require_implicit(v):
451  pytest.raises(TypeError, noconvert, v)
452 
453  def cant_convert(v):
454  pytest.raises(TypeError, convert, v)
455 
456  # straight up bool
457  assert convert(True) is True
458  assert convert(False) is False
459  assert noconvert(True) is True
460  assert noconvert(False) is False
461 
462  # None requires implicit conversion
463  require_implicit(None)
464  assert convert(None) is False
465 
466  class A:
467  def __init__(self, x):
468  self.x = x
469 
470  def __nonzero__(self):
471  return self.x
472 
473  def __bool__(self):
474  return self.x
475 
476  class B:
477  pass
478 
479  # Arbitrary objects are not accepted
480  cant_convert(object())
481  cant_convert(B())
482 
483  # Objects with __nonzero__ / __bool__ defined can be converted
484  require_implicit(A(True))
485  assert convert(A(True)) is True
486  assert convert(A(False)) is False
487 
488 
490  np = pytest.importorskip("numpy")
491 
492  convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
493 
494  def cant_convert(v):
495  pytest.raises(TypeError, convert, v)
496 
497  # np.bool_ is not considered implicit
498  assert convert(np.bool_(True)) is True
499  assert convert(np.bool_(False)) is False
500  assert noconvert(np.bool_(True)) is True
501  assert noconvert(np.bool_(False)) is False
502  cant_convert(np.zeros(2, dtype="int"))
503 
504 
506  assert isinstance(m.int_cast(), int)
507  assert isinstance(m.long_cast(), int)
508  assert isinstance(m.longlong_cast(), int)
509 
510 
512  assert m.test_void_caster()
513 
514 
516  """Verifies that const-ref is propagated through type_caster cast_op.
517  The returned ConstRefCasted type is a minimal type that is constructed to
518  reference the casting mode used.
519  """
520  x = False
521  assert m.takes(x) == 1
522  assert m.takes_move(x) == 1
523 
524  assert m.takes_ptr(x) == 3
525  assert m.takes_ref(x) == 2
526  assert m.takes_ref_wrap(x) == 2
527 
528  assert m.takes_const_ptr(x) == 5
529  assert m.takes_const_ref(x) == 4
530  assert m.takes_const_ref_wrap(x) == 4
test_builtin_casters.test_none_deferred
def test_none_deferred()
Definition: test_builtin_casters.py:391
encode
int encode(Index i, Index j)
Definition: indexed_view.cpp:45
env.deprecated_call
def deprecated_call()
Definition: env.py:18
Int
#define Int
Definition: ccolamd.c:636
B
Definition: test_numpy_dtypes.cpp:299
test_builtin_casters.test_unicode_conversion
def test_unicode_conversion()
Definition: test_builtin_casters.py:16
test_builtin_casters.test_void_caster_2
def test_void_caster_2()
Definition: test_builtin_casters.py:511
hasattr
bool hasattr(handle obj, handle name)
Definition: pytypes.h:870
test_builtin_casters.test_integer_casting
def test_integer_casting()
Definition: test_builtin_casters.py:227
test_builtin_casters.test_complex_cast
def test_complex_cast()
Definition: test_builtin_casters.py:440
object
Definition: pytypes.h:364
doc
Annotation for documentation.
Definition: attr.h:45
test_builtin_casters.test_void_caster
def test_void_caster()
Definition: test_builtin_casters.py:400
test_builtin_casters.test_numpy_int_convert
def test_numpy_int_convert()
Definition: test_builtin_casters.py:321
A
Definition: test_numpy_dtypes.cpp:298
isinstance
bool isinstance(handle obj)
Definition: pytypes.h:842
test_builtin_casters.test_bytearray_to_string
def test_bytearray_to_string()
Definition: test_builtin_casters.py:138
bytearray
Definition: pytypes.h:1756
gtwrap.interface_parser.function.__init__
def __init__(self, Union[Type, TemplatedType] ctype, str name, ParseResults default=None)
Definition: interface_parser/function.py:41
test_builtin_casters.test_bytes_to_string
def test_bytes_to_string()
Definition: test_builtin_casters.py:124
test_builtin_casters.test_const_ref_caster
def test_const_ref_caster()
Definition: test_builtin_casters.py:515
str
Definition: pytypes.h:1558
test_builtin_casters.test_numpy_bool
def test_numpy_bool()
Definition: test_builtin_casters.py:489
test_builtin_casters.test_string_view
def test_string_view(capture)
Definition: test_builtin_casters.py:148
test_builtin_casters.test_int_convert
def test_int_convert()
Definition: test_builtin_casters.py:250
test_builtin_casters.test_tuple
def test_tuple(doc)
Definition: test_builtin_casters.py:345
test_builtin_casters.test_reference_wrapper
def test_reference_wrapper()
Definition: test_builtin_casters.py:405
gtsam::convert
static BinaryMeasurement< Rot3 > convert(const BetweenFactor< Pose3 >::shared_ptr &f)
Definition: ShonanAveraging.cpp:998
test_builtin_casters.test_int_long
def test_int_long()
Definition: test_builtin_casters.py:505
test_builtin_casters.test_single_char_arguments
def test_single_char_arguments()
Definition: test_builtin_casters.py:51
test_builtin_casters.test_bool_caster
def test_bool_caster()
Definition: test_builtin_casters.py:446
test_builtin_casters.test_builtins_cast_return_none
def test_builtins_cast_return_none()
Definition: test_builtin_casters.py:381
Eigen::Index
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:74


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