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