File indexing completed on 2025-01-18 10:17:57
0001 import pytest
0002
0003 from pybind11_tests import ConstructorStats, UserType
0004 from pybind11_tests import stl as m
0005
0006
0007 def test_vector(doc):
0008 """std::vector <-> list"""
0009 lst = m.cast_vector()
0010 assert lst == [1]
0011 lst.append(2)
0012 assert m.load_vector(lst)
0013 assert m.load_vector(tuple(lst))
0014
0015 assert m.cast_bool_vector() == [True, False]
0016 assert m.load_bool_vector([True, False])
0017 assert m.load_bool_vector(tuple([True, False]))
0018
0019 assert doc(m.cast_vector) == "cast_vector() -> List[int]"
0020 assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool"
0021
0022
0023 assert m.cast_ptr_vector() == ["lvalue", "lvalue"]
0024
0025
0026 def test_deque(doc):
0027 """std::deque <-> list"""
0028 lst = m.cast_deque()
0029 assert lst == [1]
0030 lst.append(2)
0031 assert m.load_deque(lst)
0032 assert m.load_deque(tuple(lst))
0033
0034
0035 def test_array(doc):
0036 """std::array <-> list"""
0037 lst = m.cast_array()
0038 assert lst == [1, 2]
0039 assert m.load_array(lst)
0040 assert m.load_array(tuple(lst))
0041
0042 assert doc(m.cast_array) == "cast_array() -> List[int[2]]"
0043 assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool"
0044
0045
0046 def test_valarray(doc):
0047 """std::valarray <-> list"""
0048 lst = m.cast_valarray()
0049 assert lst == [1, 4, 9]
0050 assert m.load_valarray(lst)
0051 assert m.load_valarray(tuple(lst))
0052
0053 assert doc(m.cast_valarray) == "cast_valarray() -> List[int]"
0054 assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool"
0055
0056
0057 def test_map(doc):
0058 """std::map <-> dict"""
0059 d = m.cast_map()
0060 assert d == {"key": "value"}
0061 assert "key" in d
0062 d["key2"] = "value2"
0063 assert "key2" in d
0064 assert m.load_map(d)
0065
0066 assert doc(m.cast_map) == "cast_map() -> Dict[str, str]"
0067 assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool"
0068
0069
0070 def test_set(doc):
0071 """std::set <-> set"""
0072 s = m.cast_set()
0073 assert s == {"key1", "key2"}
0074 s.add("key3")
0075 assert m.load_set(s)
0076 assert m.load_set(frozenset(s))
0077
0078 assert doc(m.cast_set) == "cast_set() -> Set[str]"
0079 assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool"
0080
0081
0082 def test_recursive_casting():
0083 """Tests that stl casters preserve lvalue/rvalue context for container values"""
0084 assert m.cast_rv_vector() == ["rvalue", "rvalue"]
0085 assert m.cast_lv_vector() == ["lvalue", "lvalue"]
0086 assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"]
0087 assert m.cast_lv_array() == ["lvalue", "lvalue"]
0088 assert m.cast_rv_map() == {"a": "rvalue"}
0089 assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"}
0090 assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]]
0091 assert m.cast_lv_nested() == {
0092 "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]],
0093 "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]],
0094 }
0095
0096
0097 z = m.cast_unique_ptr_vector()
0098 assert z[0].value == 7 and z[1].value == 42
0099
0100
0101 def test_move_out_container():
0102 """Properties use the `reference_internal` policy by default. If the underlying function
0103 returns an rvalue, the policy is automatically changed to `move` to avoid referencing
0104 a temporary. In case the return value is a container of user-defined types, the policy
0105 also needs to be applied to the elements, not just the container."""
0106 c = m.MoveOutContainer()
0107 moved_out_list = c.move_list
0108 assert [x.value for x in moved_out_list] == [0, 1, 2]
0109
0110
0111 @pytest.mark.skipif(not hasattr(m, "has_optional"), reason="no <optional>")
0112 def test_optional():
0113 assert m.double_or_zero(None) == 0
0114 assert m.double_or_zero(42) == 84
0115 pytest.raises(TypeError, m.double_or_zero, "foo")
0116
0117 assert m.half_or_none(0) is None
0118 assert m.half_or_none(42) == 21
0119 pytest.raises(TypeError, m.half_or_none, "foo")
0120
0121 assert m.test_nullopt() == 42
0122 assert m.test_nullopt(None) == 42
0123 assert m.test_nullopt(42) == 42
0124 assert m.test_nullopt(43) == 43
0125
0126 assert m.test_no_assign() == 42
0127 assert m.test_no_assign(None) == 42
0128 assert m.test_no_assign(m.NoAssign(43)) == 43
0129 pytest.raises(TypeError, m.test_no_assign, 43)
0130
0131 assert m.nodefer_none_optional(None)
0132
0133 holder = m.OptionalHolder()
0134 mvalue = holder.member
0135 assert mvalue.initialized
0136 assert holder.member_initialized()
0137
0138 props = m.OptionalProperties()
0139 assert int(props.access_by_ref) == 42
0140 assert int(props.access_by_copy) == 42
0141
0142
0143 @pytest.mark.skipif(
0144 not hasattr(m, "has_exp_optional"), reason="no <experimental/optional>"
0145 )
0146 def test_exp_optional():
0147 assert m.double_or_zero_exp(None) == 0
0148 assert m.double_or_zero_exp(42) == 84
0149 pytest.raises(TypeError, m.double_or_zero_exp, "foo")
0150
0151 assert m.half_or_none_exp(0) is None
0152 assert m.half_or_none_exp(42) == 21
0153 pytest.raises(TypeError, m.half_or_none_exp, "foo")
0154
0155 assert m.test_nullopt_exp() == 42
0156 assert m.test_nullopt_exp(None) == 42
0157 assert m.test_nullopt_exp(42) == 42
0158 assert m.test_nullopt_exp(43) == 43
0159
0160 assert m.test_no_assign_exp() == 42
0161 assert m.test_no_assign_exp(None) == 42
0162 assert m.test_no_assign_exp(m.NoAssign(43)) == 43
0163 pytest.raises(TypeError, m.test_no_assign_exp, 43)
0164
0165 holder = m.OptionalExpHolder()
0166 mvalue = holder.member
0167 assert mvalue.initialized
0168 assert holder.member_initialized()
0169
0170 props = m.OptionalExpProperties()
0171 assert int(props.access_by_ref) == 42
0172 assert int(props.access_by_copy) == 42
0173
0174
0175 @pytest.mark.skipif(not hasattr(m, "has_boost_optional"), reason="no <boost/optional>")
0176 def test_boost_optional():
0177 assert m.double_or_zero_boost(None) == 0
0178 assert m.double_or_zero_boost(42) == 84
0179 pytest.raises(TypeError, m.double_or_zero_boost, "foo")
0180
0181 assert m.half_or_none_boost(0) is None
0182 assert m.half_or_none_boost(42) == 21
0183 pytest.raises(TypeError, m.half_or_none_boost, "foo")
0184
0185 assert m.test_nullopt_boost() == 42
0186 assert m.test_nullopt_boost(None) == 42
0187 assert m.test_nullopt_boost(42) == 42
0188 assert m.test_nullopt_boost(43) == 43
0189
0190 assert m.test_no_assign_boost() == 42
0191 assert m.test_no_assign_boost(None) == 42
0192 assert m.test_no_assign_boost(m.NoAssign(43)) == 43
0193 pytest.raises(TypeError, m.test_no_assign_boost, 43)
0194
0195 holder = m.OptionalBoostHolder()
0196 mvalue = holder.member
0197 assert mvalue.initialized
0198 assert holder.member_initialized()
0199
0200 props = m.OptionalBoostProperties()
0201 assert int(props.access_by_ref) == 42
0202 assert int(props.access_by_copy) == 42
0203
0204
0205 def test_reference_sensitive_optional():
0206 assert m.double_or_zero_refsensitive(None) == 0
0207 assert m.double_or_zero_refsensitive(42) == 84
0208 pytest.raises(TypeError, m.double_or_zero_refsensitive, "foo")
0209
0210 assert m.half_or_none_refsensitive(0) is None
0211 assert m.half_or_none_refsensitive(42) == 21
0212 pytest.raises(TypeError, m.half_or_none_refsensitive, "foo")
0213
0214 assert m.test_nullopt_refsensitive() == 42
0215 assert m.test_nullopt_refsensitive(None) == 42
0216 assert m.test_nullopt_refsensitive(42) == 42
0217 assert m.test_nullopt_refsensitive(43) == 43
0218
0219 assert m.test_no_assign_refsensitive() == 42
0220 assert m.test_no_assign_refsensitive(None) == 42
0221 assert m.test_no_assign_refsensitive(m.NoAssign(43)) == 43
0222 pytest.raises(TypeError, m.test_no_assign_refsensitive, 43)
0223
0224 holder = m.OptionalRefSensitiveHolder()
0225 mvalue = holder.member
0226 assert mvalue.initialized
0227 assert holder.member_initialized()
0228
0229 props = m.OptionalRefSensitiveProperties()
0230 assert int(props.access_by_ref) == 42
0231 assert int(props.access_by_copy) == 42
0232
0233
0234 @pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no <filesystem>")
0235 def test_fs_path():
0236 from pathlib import Path
0237
0238 class PseudoStrPath:
0239 def __fspath__(self):
0240 return "foo/bar"
0241
0242 class PseudoBytesPath:
0243 def __fspath__(self):
0244 return b"foo/bar"
0245
0246 assert m.parent_path(Path("foo/bar")) == Path("foo")
0247 assert m.parent_path("foo/bar") == Path("foo")
0248 assert m.parent_path(b"foo/bar") == Path("foo")
0249 assert m.parent_path(PseudoStrPath()) == Path("foo")
0250 assert m.parent_path(PseudoBytesPath()) == Path("foo")
0251
0252
0253 @pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no <variant>")
0254 def test_variant(doc):
0255 assert m.load_variant(1) == "int"
0256 assert m.load_variant("1") == "std::string"
0257 assert m.load_variant(1.0) == "double"
0258 assert m.load_variant(None) == "std::nullptr_t"
0259
0260 assert m.load_variant_2pass(1) == "int"
0261 assert m.load_variant_2pass(1.0) == "double"
0262
0263 assert m.cast_variant() == (5, "Hello")
0264
0265 assert (
0266 doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str"
0267 )
0268
0269
0270 @pytest.mark.skipif(
0271 not hasattr(m, "load_monostate_variant"), reason="no std::monostate"
0272 )
0273 def test_variant_monostate(doc):
0274 assert m.load_monostate_variant(None) == "std::monostate"
0275 assert m.load_monostate_variant(1) == "int"
0276 assert m.load_monostate_variant("1") == "std::string"
0277
0278 assert m.cast_monostate_variant() == (None, 5, "Hello")
0279
0280 assert (
0281 doc(m.load_monostate_variant)
0282 == "load_monostate_variant(arg0: Union[None, int, str]) -> str"
0283 )
0284
0285
0286 def test_vec_of_reference_wrapper():
0287 """#171: Can't return reference wrappers (or STL structures containing them)"""
0288 assert (
0289 str(m.return_vec_of_reference_wrapper(UserType(4)))
0290 == "[UserType(1), UserType(2), UserType(3), UserType(4)]"
0291 )
0292
0293
0294 def test_stl_pass_by_pointer(msg):
0295 """Passing nullptr or None to an STL container pointer is not expected to work"""
0296 with pytest.raises(TypeError) as excinfo:
0297 m.stl_pass_by_pointer()
0298 assert (
0299 msg(excinfo.value)
0300 == """
0301 stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
0302 1. (v: List[int] = None) -> List[int]
0303
0304 Invoked with:
0305 """
0306 )
0307
0308 with pytest.raises(TypeError) as excinfo:
0309 m.stl_pass_by_pointer(None)
0310 assert (
0311 msg(excinfo.value)
0312 == """
0313 stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
0314 1. (v: List[int] = None) -> List[int]
0315
0316 Invoked with: None
0317 """
0318 )
0319
0320 assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3]
0321
0322
0323 def test_missing_header_message():
0324 """Trying convert `list` to a `std::vector`, or vice versa, without including
0325 <pybind11/stl.h> should result in a helpful suggestion in the error message"""
0326 import pybind11_cross_module_tests as cm
0327
0328 expected_message = (
0329 "Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n"
0330 "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n"
0331 "conversions are optional and require extra headers to be included\n"
0332 "when compiling your pybind11 module."
0333 )
0334
0335 with pytest.raises(TypeError) as excinfo:
0336 cm.missing_header_arg([1.0, 2.0, 3.0])
0337 assert expected_message in str(excinfo.value)
0338
0339 with pytest.raises(TypeError) as excinfo:
0340 cm.missing_header_return()
0341 assert expected_message in str(excinfo.value)
0342
0343
0344 def test_function_with_string_and_vector_string_arg():
0345 """Check if a string is NOT implicitly converted to a list, which was the
0346 behavior before fix of issue #1258"""
0347 assert m.func_with_string_or_vector_string_arg_overload(("A", "B")) == 2
0348 assert m.func_with_string_or_vector_string_arg_overload(["A", "B"]) == 2
0349 assert m.func_with_string_or_vector_string_arg_overload("A") == 3
0350
0351
0352 def test_stl_ownership():
0353 cstats = ConstructorStats.get(m.Placeholder)
0354 assert cstats.alive() == 0
0355 r = m.test_stl_ownership()
0356 assert len(r) == 1
0357 del r
0358 assert cstats.alive() == 0
0359
0360
0361 def test_array_cast_sequence():
0362 assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3]
0363
0364
0365 def test_issue_1561():
0366 """check fix for issue #1561"""
0367 bar = m.Issue1561Outer()
0368 bar.list = [m.Issue1561Inner("bar")]
0369 bar.list
0370 assert bar.list[0].data == "bar"
0371
0372
0373 def test_return_vector_bool_raw_ptr():
0374
0375 v = m.return_vector_bool_raw_ptr()
0376 assert isinstance(v, list)
0377 assert len(v) == 4513