1# -*- coding: utf-8 -*- 2import pytest 3 4import env # noqa: F401 5 6from pybind11_tests import builtin_casters as m 7from pybind11_tests import UserType, IncType 8 9 10def test_simple_string(): 11 assert m.string_roundtrip("const char *") == "const char *" 12 13 14def test_unicode_conversion(): 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 49def test_single_char_arguments(): 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({:#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 122def test_bytes_to_string(): 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>") 142def 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 211def test_integer_casting(): 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 254def test_int_convert(): 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 env.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 324def test_numpy_int_convert(): 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 env.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 346def 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 382def test_builtins_cast_return_none(): 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 392def test_none_deferred(): 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 401def test_void_caster(): 402 assert m.load_nullptr_t(None) is None 403 assert m.cast_nullptr_t() is None 404 405 406def test_reference_wrapper(): 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 439def test_complex_cast(): 440 """std::complex casts""" 441 assert m.complex_cast(1) == "1.0" 442 assert m.complex_cast(2j) == "(0.0, 2.0)" 443 444 445def test_bool_caster(): 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 488def test_numpy_bool(): 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 504def test_int_long(): 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 518def test_void_caster_2(): 519 assert m.test_void_caster() 520 521 522def test_const_ref_caster(): 523 """Verifies that const-ref is propagated through type_caster cast_op. 524 The returned ConstRefCasted type is a minimal 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 538