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({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 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 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 319def test_numpy_int_convert(): 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 assert convert(np.float32(3.14159)) == 3 333 require_implicit(np.float32(3.14159)) 334 335 336def test_tuple(doc): 337 """std::pair <-> tuple & std::tuple <-> tuple""" 338 assert m.pair_passthrough((True, "test")) == ("test", True) 339 assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True) 340 # Any sequence can be cast to a std::pair or std::tuple 341 assert m.pair_passthrough([True, "test"]) == ("test", True) 342 assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True) 343 assert m.empty_tuple() == () 344 345 assert ( 346 doc(m.pair_passthrough) 347 == """ 348 pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] 349 350 Return a pair in reversed order 351 """ 352 ) 353 assert ( 354 doc(m.tuple_passthrough) 355 == """ 356 tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] 357 358 Return a triple in reversed order 359 """ 360 ) 361 362 assert m.rvalue_pair() == ("rvalue", "rvalue") 363 assert m.lvalue_pair() == ("lvalue", "lvalue") 364 assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue") 365 assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue") 366 assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue"))) 367 assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue"))) 368 369 assert m.int_string_pair() == (2, "items") 370 371 372def test_builtins_cast_return_none(): 373 """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None""" 374 assert m.return_none_string() is None 375 assert m.return_none_char() is None 376 assert m.return_none_bool() is None 377 assert m.return_none_int() is None 378 assert m.return_none_float() is None 379 assert m.return_none_pair() is None 380 381 382def test_none_deferred(): 383 """None passed as various argument types should defer to other overloads""" 384 assert not m.defer_none_cstring("abc") 385 assert m.defer_none_cstring(None) 386 assert not m.defer_none_custom(UserType()) 387 assert m.defer_none_custom(None) 388 assert m.nodefer_none_void(None) 389 390 391def test_void_caster(): 392 assert m.load_nullptr_t(None) is None 393 assert m.cast_nullptr_t() is None 394 395 396def test_reference_wrapper(): 397 """std::reference_wrapper for builtin and user types""" 398 assert m.refwrap_builtin(42) == 420 399 assert m.refwrap_usertype(UserType(42)) == 42 400 assert m.refwrap_usertype_const(UserType(42)) == 42 401 402 with pytest.raises(TypeError) as excinfo: 403 m.refwrap_builtin(None) 404 assert "incompatible function arguments" in str(excinfo.value) 405 406 with pytest.raises(TypeError) as excinfo: 407 m.refwrap_usertype(None) 408 assert "incompatible function arguments" in str(excinfo.value) 409 410 assert m.refwrap_lvalue().value == 1 411 assert m.refwrap_lvalue_const().value == 1 412 413 a1 = m.refwrap_list(copy=True) 414 a2 = m.refwrap_list(copy=True) 415 assert [x.value for x in a1] == [2, 3] 416 assert [x.value for x in a2] == [2, 3] 417 assert not a1[0] is a2[0] and not a1[1] is a2[1] 418 419 b1 = m.refwrap_list(copy=False) 420 b2 = m.refwrap_list(copy=False) 421 assert [x.value for x in b1] == [1, 2] 422 assert [x.value for x in b2] == [1, 2] 423 assert b1[0] is b2[0] and b1[1] is b2[1] 424 425 assert m.refwrap_iiw(IncType(5)) == 5 426 assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10] 427 428 429def test_complex_cast(): 430 """std::complex casts""" 431 assert m.complex_cast(1) == "1.0" 432 assert m.complex_cast(2j) == "(0.0, 2.0)" 433 434 435def test_bool_caster(): 436 """Test bool caster implicit conversions.""" 437 convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert 438 439 def require_implicit(v): 440 pytest.raises(TypeError, noconvert, v) 441 442 def cant_convert(v): 443 pytest.raises(TypeError, convert, v) 444 445 # straight up bool 446 assert convert(True) is True 447 assert convert(False) is False 448 assert noconvert(True) is True 449 assert noconvert(False) is False 450 451 # None requires implicit conversion 452 require_implicit(None) 453 assert convert(None) is False 454 455 class A(object): 456 def __init__(self, x): 457 self.x = x 458 459 def __nonzero__(self): 460 return self.x 461 462 def __bool__(self): 463 return self.x 464 465 class B(object): 466 pass 467 468 # Arbitrary objects are not accepted 469 cant_convert(object()) 470 cant_convert(B()) 471 472 # Objects with __nonzero__ / __bool__ defined can be converted 473 require_implicit(A(True)) 474 assert convert(A(True)) is True 475 assert convert(A(False)) is False 476 477 478def test_numpy_bool(): 479 np = pytest.importorskip("numpy") 480 481 convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert 482 483 def cant_convert(v): 484 pytest.raises(TypeError, convert, v) 485 486 # np.bool_ is not considered implicit 487 assert convert(np.bool_(True)) is True 488 assert convert(np.bool_(False)) is False 489 assert noconvert(np.bool_(True)) is True 490 assert noconvert(np.bool_(False)) is False 491 cant_convert(np.zeros(2, dtype="int")) 492 493 494def test_int_long(): 495 """In Python 2, a C++ int should return a Python int rather than long 496 if possible: longs are not always accepted where ints are used (such 497 as the argument to sys.exit()). A C++ long long is always a Python 498 long.""" 499 500 import sys 501 502 must_be_long = type(getattr(sys, "maxint", 1) + 1) 503 assert isinstance(m.int_cast(), int) 504 assert isinstance(m.long_cast(), int) 505 assert isinstance(m.longlong_cast(), must_be_long) 506 507 508def test_void_caster_2(): 509 assert m.test_void_caster() 510 511 512def test_const_ref_caster(): 513 """Verifies that const-ref is propagated through type_caster cast_op. 514 The returned ConstRefCasted type is a mimimal type that is constructed to 515 reference the casting mode used. 516 """ 517 x = False 518 assert m.takes(x) == 1 519 assert m.takes_move(x) == 1 520 521 assert m.takes_ptr(x) == 3 522 assert m.takes_ref(x) == 2 523 assert m.takes_ref_wrap(x) == 2 524 525 assert m.takes_const_ptr(x) == 5 526 assert m.takes_const_ref(x) == 4 527 assert m.takes_const_ref_wrap(x) == 4 528