File indexing completed on 2025-01-18 10:17:52
0001 import sys
0002
0003 import pytest
0004
0005 import env
0006 from pybind11_tests import IncType, UserType
0007 from pybind11_tests import builtin_casters as m
0008
0009
0010 def test_simple_string():
0011 assert m.string_roundtrip("const char *") == "const char *"
0012
0013
0014 def test_unicode_conversion():
0015 """Tests unicode conversion and error reporting."""
0016 assert m.good_utf8_string() == "Say utf8β½ π π"
0017 assert m.good_utf16_string() == "bβ½ππz"
0018 assert m.good_utf32_string() == "aππβ½z"
0019 assert m.good_wchar_string() == "aβΈπz"
0020 if hasattr(m, "has_u8string"):
0021 assert m.good_utf8_u8string() == "Say utf8β½ π π"
0022
0023 with pytest.raises(UnicodeDecodeError):
0024 m.bad_utf8_string()
0025
0026 with pytest.raises(UnicodeDecodeError):
0027 m.bad_utf16_string()
0028
0029
0030 if hasattr(m, "bad_utf32_string"):
0031 with pytest.raises(UnicodeDecodeError):
0032 m.bad_utf32_string()
0033 if hasattr(m, "bad_wchar_string"):
0034 with pytest.raises(UnicodeDecodeError):
0035 m.bad_wchar_string()
0036 if hasattr(m, "has_u8string"):
0037 with pytest.raises(UnicodeDecodeError):
0038 m.bad_utf8_u8string()
0039
0040 assert m.u8_Z() == "Z"
0041 assert m.u8_eacute() == "Γ©"
0042 assert m.u16_ibang() == "β½"
0043 assert m.u32_mathbfA() == "π"
0044 assert m.wchar_heart() == "β₯"
0045 if hasattr(m, "has_u8string"):
0046 assert m.u8_char8_Z() == "Z"
0047
0048
0049 def test_single_char_arguments():
0050 """Tests failures for passing invalid inputs to char-accepting functions"""
0051
0052 def toobig_message(r):
0053 return f"Character code point not in range({r:#x})"
0054
0055 toolong_message = "Expected a character, but multi-character string found"
0056
0057 assert m.ord_char("a") == 0x61
0058 assert m.ord_char_lv("b") == 0x62
0059 assert (
0060 m.ord_char("Γ©") == 0xE9
0061 )
0062 with pytest.raises(ValueError) as excinfo:
0063 assert m.ord_char("Δ") == 0x100
0064 assert str(excinfo.value) == toobig_message(0x100)
0065 with pytest.raises(ValueError) as excinfo:
0066 assert m.ord_char("ab")
0067 assert str(excinfo.value) == toolong_message
0068
0069 assert m.ord_char16("a") == 0x61
0070 assert m.ord_char16("Γ©") == 0xE9
0071 assert m.ord_char16_lv("Γͺ") == 0xEA
0072 assert m.ord_char16("Δ") == 0x100
0073 assert m.ord_char16("β½") == 0x203D
0074 assert m.ord_char16("β₯") == 0x2665
0075 assert m.ord_char16_lv("β‘") == 0x2661
0076 with pytest.raises(ValueError) as excinfo:
0077 assert m.ord_char16("π") == 0x1F382
0078 assert str(excinfo.value) == toobig_message(0x10000)
0079 with pytest.raises(ValueError) as excinfo:
0080 assert m.ord_char16("aa")
0081 assert str(excinfo.value) == toolong_message
0082
0083 assert m.ord_char32("a") == 0x61
0084 assert m.ord_char32("Γ©") == 0xE9
0085 assert m.ord_char32("Δ") == 0x100
0086 assert m.ord_char32("β½") == 0x203D
0087 assert m.ord_char32("β₯") == 0x2665
0088 assert m.ord_char32("π") == 0x1F382
0089 with pytest.raises(ValueError) as excinfo:
0090 assert m.ord_char32("aa")
0091 assert str(excinfo.value) == toolong_message
0092
0093 assert m.ord_wchar("a") == 0x61
0094 assert m.ord_wchar("Γ©") == 0xE9
0095 assert m.ord_wchar("Δ") == 0x100
0096 assert m.ord_wchar("β½") == 0x203D
0097 assert m.ord_wchar("β₯") == 0x2665
0098 if m.wchar_size == 2:
0099 with pytest.raises(ValueError) as excinfo:
0100 assert m.ord_wchar("π") == 0x1F382
0101 assert str(excinfo.value) == toobig_message(0x10000)
0102 else:
0103 assert m.ord_wchar("π") == 0x1F382
0104 with pytest.raises(ValueError) as excinfo:
0105 assert m.ord_wchar("aa")
0106 assert str(excinfo.value) == toolong_message
0107
0108 if hasattr(m, "has_u8string"):
0109 assert m.ord_char8("a") == 0x61
0110 assert m.ord_char8_lv("b") == 0x62
0111 assert (
0112 m.ord_char8("Γ©") == 0xE9
0113 )
0114 with pytest.raises(ValueError) as excinfo:
0115 assert m.ord_char8("Δ") == 0x100
0116 assert str(excinfo.value) == toobig_message(0x100)
0117 with pytest.raises(ValueError) as excinfo:
0118 assert m.ord_char8("ab")
0119 assert str(excinfo.value) == toolong_message
0120
0121
0122 def test_bytes_to_string():
0123 """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
0124 one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
0125
0126
0127 assert m.strlen(b"hi") == 2
0128 assert m.string_length(b"world") == 5
0129 assert m.string_length("a\x00b".encode()) == 3
0130 assert m.strlen("a\x00b".encode()) == 1
0131
0132
0133 assert m.string_length("π©".encode()) == 4
0134
0135
0136 def test_bytearray_to_string():
0137 """Tests the ability to pass bytearray to C++ string-accepting functions"""
0138 assert m.string_length(bytearray(b"Hi")) == 2
0139 assert m.strlen(bytearray(b"bytearray")) == 9
0140 assert m.string_length(bytearray()) == 0
0141 assert m.string_length(bytearray("π¦", "utf-8", "strict")) == 4
0142 assert m.string_length(bytearray(b"\x80")) == 1
0143
0144
0145 @pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
0146 def test_string_view(capture):
0147 """Tests support for C++17 string_view arguments and return values"""
0148 assert m.string_view_chars("Hi") == [72, 105]
0149 assert m.string_view_chars("Hi π") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
0150 assert m.string_view16_chars("Hi π") == [72, 105, 32, 0xD83C, 0xDF82]
0151 assert m.string_view32_chars("Hi π") == [72, 105, 32, 127874]
0152 if hasattr(m, "has_u8string"):
0153 assert m.string_view8_chars("Hi") == [72, 105]
0154 assert m.string_view8_chars("Hi π") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
0155
0156 assert m.string_view_return() == "utf8 secret π"
0157 assert m.string_view16_return() == "utf16 secret π"
0158 assert m.string_view32_return() == "utf32 secret π"
0159 if hasattr(m, "has_u8string"):
0160 assert m.string_view8_return() == "utf8 secret π"
0161
0162 with capture:
0163 m.string_view_print("Hi")
0164 m.string_view_print("utf8 π")
0165 m.string_view16_print("utf16 π")
0166 m.string_view32_print("utf32 π")
0167 assert (
0168 capture
0169 == """
0170 Hi 2
0171 utf8 π 9
0172 utf16 π 8
0173 utf32 π 7
0174 """
0175 )
0176 if hasattr(m, "has_u8string"):
0177 with capture:
0178 m.string_view8_print("Hi")
0179 m.string_view8_print("utf8 π")
0180 assert (
0181 capture
0182 == """
0183 Hi 2
0184 utf8 π 9
0185 """
0186 )
0187
0188 with capture:
0189 m.string_view_print("Hi, ascii")
0190 m.string_view_print("Hi, utf8 π")
0191 m.string_view16_print("Hi, utf16 π")
0192 m.string_view32_print("Hi, utf32 π")
0193 assert (
0194 capture
0195 == """
0196 Hi, ascii 9
0197 Hi, utf8 π 13
0198 Hi, utf16 π 12
0199 Hi, utf32 π 11
0200 """
0201 )
0202 if hasattr(m, "has_u8string"):
0203 with capture:
0204 m.string_view8_print("Hi, ascii")
0205 m.string_view8_print("Hi, utf8 π")
0206 assert (
0207 capture
0208 == """
0209 Hi, ascii 9
0210 Hi, utf8 π 13
0211 """
0212 )
0213
0214 assert m.string_view_bytes() == b"abc \x80\x80 def"
0215 assert m.string_view_str() == "abc β½ def"
0216 assert m.string_view_from_bytes("abc β½ def".encode()) == "abc β½ def"
0217 if hasattr(m, "has_u8string"):
0218 assert m.string_view8_str() == "abc β½ def"
0219 assert m.string_view_memoryview() == "Have some π".encode()
0220
0221 assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
0222 assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
0223
0224
0225 def test_integer_casting():
0226 """Issue #929 - out-of-range integer values shouldn't be accepted"""
0227 assert m.i32_str(-1) == "-1"
0228 assert m.i64_str(-1) == "-1"
0229 assert m.i32_str(2000000000) == "2000000000"
0230 assert m.u32_str(2000000000) == "2000000000"
0231 assert m.i64_str(-999999999999) == "-999999999999"
0232 assert m.u64_str(999999999999) == "999999999999"
0233
0234 with pytest.raises(TypeError) as excinfo:
0235 m.u32_str(-1)
0236 assert "incompatible function arguments" in str(excinfo.value)
0237 with pytest.raises(TypeError) as excinfo:
0238 m.u64_str(-1)
0239 assert "incompatible function arguments" in str(excinfo.value)
0240 with pytest.raises(TypeError) as excinfo:
0241 m.i32_str(-3000000000)
0242 assert "incompatible function arguments" in str(excinfo.value)
0243 with pytest.raises(TypeError) as excinfo:
0244 m.i32_str(3000000000)
0245 assert "incompatible function arguments" in str(excinfo.value)
0246
0247
0248 def test_int_convert():
0249 class Int:
0250 def __int__(self):
0251 return 42
0252
0253 class NotInt:
0254 pass
0255
0256 class Float:
0257 def __float__(self):
0258 return 41.99999
0259
0260 class Index:
0261 def __index__(self):
0262 return 42
0263
0264 class IntAndIndex:
0265 def __int__(self):
0266 return 42
0267
0268 def __index__(self):
0269 return 0
0270
0271 class RaisingTypeErrorOnIndex:
0272 def __index__(self):
0273 raise TypeError
0274
0275 def __int__(self):
0276 return 42
0277
0278 class RaisingValueErrorOnIndex:
0279 def __index__(self):
0280 raise ValueError
0281
0282 def __int__(self):
0283 return 42
0284
0285 convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
0286
0287 def requires_conversion(v):
0288 pytest.raises(TypeError, noconvert, v)
0289
0290 def cant_convert(v):
0291 pytest.raises(TypeError, convert, v)
0292
0293 assert convert(7) == 7
0294 assert noconvert(7) == 7
0295 cant_convert(3.14159)
0296
0297
0298 if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
0299 with env.deprecated_call():
0300 assert convert(Int()) == 42
0301 else:
0302 assert convert(Int()) == 42
0303 requires_conversion(Int())
0304 cant_convert(NotInt())
0305 cant_convert(Float())
0306
0307
0308
0309 assert convert(Index()) == 42
0310 assert noconvert(Index()) == 42
0311 assert convert(IntAndIndex()) == 0
0312 assert noconvert(IntAndIndex()) == 0
0313 assert convert(RaisingTypeErrorOnIndex()) == 42
0314 requires_conversion(RaisingTypeErrorOnIndex())
0315 assert convert(RaisingValueErrorOnIndex()) == 42
0316 requires_conversion(RaisingValueErrorOnIndex())
0317
0318
0319 def test_numpy_int_convert():
0320 np = pytest.importorskip("numpy")
0321
0322 convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
0323
0324 def require_implicit(v):
0325 pytest.raises(TypeError, noconvert, v)
0326
0327
0328 assert convert(np.intc(42)) == 42
0329 assert noconvert(np.intc(42)) == 42
0330
0331
0332
0333
0334
0335 if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
0336 with env.deprecated_call():
0337 assert convert(np.float32(3.14159)) == 3
0338 else:
0339 assert convert(np.float32(3.14159)) == 3
0340 require_implicit(np.float32(3.14159))
0341
0342
0343 def test_tuple(doc):
0344 """std::pair <-> tuple & std::tuple <-> tuple"""
0345 assert m.pair_passthrough((True, "test")) == ("test", True)
0346 assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True)
0347
0348 assert m.pair_passthrough([True, "test"]) == ("test", True)
0349 assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True)
0350 assert m.empty_tuple() == ()
0351
0352 assert (
0353 doc(m.pair_passthrough)
0354 == """
0355 pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]
0356
0357 Return a pair in reversed order
0358 """
0359 )
0360 assert (
0361 doc(m.tuple_passthrough)
0362 == """
0363 tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
0364
0365 Return a triple in reversed order
0366 """
0367 )
0368
0369 assert m.rvalue_pair() == ("rvalue", "rvalue")
0370 assert m.lvalue_pair() == ("lvalue", "lvalue")
0371 assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
0372 assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue")
0373 assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue")))
0374 assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue")))
0375
0376 assert m.int_string_pair() == (2, "items")
0377
0378
0379 def test_builtins_cast_return_none():
0380 """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
0381 assert m.return_none_string() is None
0382 assert m.return_none_char() is None
0383 assert m.return_none_bool() is None
0384 assert m.return_none_int() is None
0385 assert m.return_none_float() is None
0386 assert m.return_none_pair() is None
0387
0388
0389 def test_none_deferred():
0390 """None passed as various argument types should defer to other overloads"""
0391 assert not m.defer_none_cstring("abc")
0392 assert m.defer_none_cstring(None)
0393 assert not m.defer_none_custom(UserType())
0394 assert m.defer_none_custom(None)
0395 assert m.nodefer_none_void(None)
0396
0397
0398 def test_void_caster():
0399 assert m.load_nullptr_t(None) is None
0400 assert m.cast_nullptr_t() is None
0401
0402
0403 def test_reference_wrapper():
0404 """std::reference_wrapper for builtin and user types"""
0405 assert m.refwrap_builtin(42) == 420
0406 assert m.refwrap_usertype(UserType(42)) == 42
0407 assert m.refwrap_usertype_const(UserType(42)) == 42
0408
0409 with pytest.raises(TypeError) as excinfo:
0410 m.refwrap_builtin(None)
0411 assert "incompatible function arguments" in str(excinfo.value)
0412
0413 with pytest.raises(TypeError) as excinfo:
0414 m.refwrap_usertype(None)
0415 assert "incompatible function arguments" in str(excinfo.value)
0416
0417 assert m.refwrap_lvalue().value == 1
0418 assert m.refwrap_lvalue_const().value == 1
0419
0420 a1 = m.refwrap_list(copy=True)
0421 a2 = m.refwrap_list(copy=True)
0422 assert [x.value for x in a1] == [2, 3]
0423 assert [x.value for x in a2] == [2, 3]
0424 assert not a1[0] is a2[0] and not a1[1] is a2[1]
0425
0426 b1 = m.refwrap_list(copy=False)
0427 b2 = m.refwrap_list(copy=False)
0428 assert [x.value for x in b1] == [1, 2]
0429 assert [x.value for x in b2] == [1, 2]
0430 assert b1[0] is b2[0] and b1[1] is b2[1]
0431
0432 assert m.refwrap_iiw(IncType(5)) == 5
0433 assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
0434
0435
0436 def test_complex_cast():
0437 """std::complex casts"""
0438 assert m.complex_cast(1) == "1.0"
0439 assert m.complex_cast(2j) == "(0.0, 2.0)"
0440
0441
0442 def test_bool_caster():
0443 """Test bool caster implicit conversions."""
0444 convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
0445
0446 def require_implicit(v):
0447 pytest.raises(TypeError, noconvert, v)
0448
0449 def cant_convert(v):
0450 pytest.raises(TypeError, convert, v)
0451
0452
0453 assert convert(True) is True
0454 assert convert(False) is False
0455 assert noconvert(True) is True
0456 assert noconvert(False) is False
0457
0458
0459 require_implicit(None)
0460 assert convert(None) is False
0461
0462 class A:
0463 def __init__(self, x):
0464 self.x = x
0465
0466 def __nonzero__(self):
0467 return self.x
0468
0469 def __bool__(self):
0470 return self.x
0471
0472 class B:
0473 pass
0474
0475
0476 cant_convert(object())
0477 cant_convert(B())
0478
0479
0480 require_implicit(A(True))
0481 assert convert(A(True)) is True
0482 assert convert(A(False)) is False
0483
0484
0485 def test_numpy_bool():
0486 np = pytest.importorskip("numpy")
0487
0488 convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert
0489
0490 def cant_convert(v):
0491 pytest.raises(TypeError, convert, v)
0492
0493
0494 assert convert(np.bool_(True)) is True
0495 assert convert(np.bool_(False)) is False
0496 assert noconvert(np.bool_(True)) is True
0497 assert noconvert(np.bool_(False)) is False
0498 cant_convert(np.zeros(2, dtype="int"))
0499
0500
0501 def test_int_long():
0502 assert isinstance(m.int_cast(), int)
0503 assert isinstance(m.long_cast(), int)
0504 assert isinstance(m.longlong_cast(), int)
0505
0506
0507 def test_void_caster_2():
0508 assert m.test_void_caster()
0509
0510
0511 def test_const_ref_caster():
0512 """Verifies that const-ref is propagated through type_caster cast_op.
0513 The returned ConstRefCasted type is a minimal type that is constructed to
0514 reference the casting mode used.
0515 """
0516 x = False
0517 assert m.takes(x) == 1
0518 assert m.takes_move(x) == 1
0519
0520 assert m.takes_ptr(x) == 3
0521 assert m.takes_ref(x) == 2
0522 assert m.takes_ref_wrap(x) == 2
0523
0524 assert m.takes_const_ptr(x) == 5
0525 assert m.takes_const_ref(x) == 4
0526 assert m.takes_const_ref_wrap(x) == 4