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