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