Back to home page

EIC code displayed by LXR

 
 

    


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     # These are provided only if they actually fail (they don't when 32-bit)
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  # simple ASCII
0058     assert m.ord_char_lv("b") == 0x62
0059     assert (
0060         m.ord_char("Γ©") == 0xE9
0061     )  # requires 2 bytes in utf-8, but can be stuffed in a char
0062     with pytest.raises(ValueError) as excinfo:
0063         assert m.ord_char("Δ€") == 0x100  # requires 2 bytes, doesn't fit in a char
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  # requires surrogate pair
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  # requires surrogate pair
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  # simple ASCII
0110         assert m.ord_char8_lv("b") == 0x62
0111         assert (
0112             m.ord_char8("Γ©") == 0xE9
0113         )  # requires 2 bytes in utf-8, but can be stuffed in a char
0114         with pytest.raises(ValueError) as excinfo:
0115             assert m.ord_char8("Δ€") == 0x100  # requires 2 bytes, doesn't fit in a char
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     # Issue #816
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  # C-string limitation
0131 
0132     # passing in a utf8 encoded string should work
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     # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
0297     # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
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     # Before Python 3.8, `PyLong_AsLong` does not pick up on `obj.__index__`,
0308     # but pybind11 "backports" this behavior.
0309     assert convert(Index()) == 42
0310     assert noconvert(Index()) == 42
0311     assert convert(IntAndIndex()) == 0  # Fishy; `int(DoubleThought)` == 42
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     # `np.intc` is an alias that corresponds to a C++ `int`
0328     assert convert(np.intc(42)) == 42
0329     assert noconvert(np.intc(42)) == 42
0330 
0331     # The implicit conversion from np.float32 is undesirable but currently accepted.
0332     # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
0333     # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
0334     # https://github.com/pybind/pybind11/issues/3408
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     # Any sequence can be cast to a std::pair or std::tuple
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     # straight up bool
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     # None requires implicit conversion
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     # Arbitrary objects are not accepted
0476     cant_convert(object())
0477     cant_convert(B())
0478 
0479     # Objects with __nonzero__ / __bool__ defined can be converted
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     # np.bool_ is not considered implicit
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