1import pytest 2 3from pybind11_tests import stl as m 4from pybind11_tests import UserType 5from pybind11_tests import ConstructorStats 6 7 8def test_vector(doc): 9 """std::vector <-> list""" 10 lst = m.cast_vector() 11 assert lst == [1] 12 lst.append(2) 13 assert m.load_vector(lst) 14 assert m.load_vector(tuple(lst)) 15 16 assert m.cast_bool_vector() == [True, False] 17 assert m.load_bool_vector([True, False]) 18 19 assert doc(m.cast_vector) == "cast_vector() -> List[int]" 20 assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" 21 22 # Test regression caused by 936: pointers to stl containers weren't castable 23 assert m.cast_ptr_vector() == ["lvalue", "lvalue"] 24 25 26def test_deque(doc): 27 """std::deque <-> list""" 28 lst = m.cast_deque() 29 assert lst == [1] 30 lst.append(2) 31 assert m.load_deque(lst) 32 assert m.load_deque(tuple(lst)) 33 34 35def test_array(doc): 36 """std::array <-> list""" 37 lst = m.cast_array() 38 assert lst == [1, 2] 39 assert m.load_array(lst) 40 41 assert doc(m.cast_array) == "cast_array() -> List[int[2]]" 42 assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool" 43 44 45def test_valarray(doc): 46 """std::valarray <-> list""" 47 lst = m.cast_valarray() 48 assert lst == [1, 4, 9] 49 assert m.load_valarray(lst) 50 51 assert doc(m.cast_valarray) == "cast_valarray() -> List[int]" 52 assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool" 53 54 55def test_map(doc): 56 """std::map <-> dict""" 57 d = m.cast_map() 58 assert d == {"key": "value"} 59 assert "key" in d 60 d["key2"] = "value2" 61 assert "key2" in d 62 assert m.load_map(d) 63 64 assert doc(m.cast_map) == "cast_map() -> Dict[str, str]" 65 assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool" 66 67 68def test_set(doc): 69 """std::set <-> set""" 70 s = m.cast_set() 71 assert s == {"key1", "key2"} 72 s.add("key3") 73 assert m.load_set(s) 74 75 assert doc(m.cast_set) == "cast_set() -> Set[str]" 76 assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool" 77 78 79def test_recursive_casting(): 80 """Tests that stl casters preserve lvalue/rvalue context for container values""" 81 assert m.cast_rv_vector() == ["rvalue", "rvalue"] 82 assert m.cast_lv_vector() == ["lvalue", "lvalue"] 83 assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"] 84 assert m.cast_lv_array() == ["lvalue", "lvalue"] 85 assert m.cast_rv_map() == {"a": "rvalue"} 86 assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"} 87 assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]] 88 assert m.cast_lv_nested() == { 89 "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]], 90 "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]] 91 } 92 93 # Issue #853 test case: 94 z = m.cast_unique_ptr_vector() 95 assert z[0].value == 7 and z[1].value == 42 96 97 98def test_move_out_container(): 99 """Properties use the `reference_internal` policy by default. If the underlying function 100 returns an rvalue, the policy is automatically changed to `move` to avoid referencing 101 a temporary. In case the return value is a container of user-defined types, the policy 102 also needs to be applied to the elements, not just the container.""" 103 c = m.MoveOutContainer() 104 moved_out_list = c.move_list 105 assert [x.value for x in moved_out_list] == [0, 1, 2] 106 107 108@pytest.mark.skipif(not hasattr(m, "has_optional"), reason='no <optional>') 109def test_optional(): 110 assert m.double_or_zero(None) == 0 111 assert m.double_or_zero(42) == 84 112 pytest.raises(TypeError, m.double_or_zero, 'foo') 113 114 assert m.half_or_none(0) is None 115 assert m.half_or_none(42) == 21 116 pytest.raises(TypeError, m.half_or_none, 'foo') 117 118 assert m.test_nullopt() == 42 119 assert m.test_nullopt(None) == 42 120 assert m.test_nullopt(42) == 42 121 assert m.test_nullopt(43) == 43 122 123 assert m.test_no_assign() == 42 124 assert m.test_no_assign(None) == 42 125 assert m.test_no_assign(m.NoAssign(43)) == 43 126 pytest.raises(TypeError, m.test_no_assign, 43) 127 128 assert m.nodefer_none_optional(None) 129 130 131@pytest.mark.skipif(not hasattr(m, "has_exp_optional"), reason='no <experimental/optional>') 132def test_exp_optional(): 133 assert m.double_or_zero_exp(None) == 0 134 assert m.double_or_zero_exp(42) == 84 135 pytest.raises(TypeError, m.double_or_zero_exp, 'foo') 136 137 assert m.half_or_none_exp(0) is None 138 assert m.half_or_none_exp(42) == 21 139 pytest.raises(TypeError, m.half_or_none_exp, 'foo') 140 141 assert m.test_nullopt_exp() == 42 142 assert m.test_nullopt_exp(None) == 42 143 assert m.test_nullopt_exp(42) == 42 144 assert m.test_nullopt_exp(43) == 43 145 146 assert m.test_no_assign_exp() == 42 147 assert m.test_no_assign_exp(None) == 42 148 assert m.test_no_assign_exp(m.NoAssign(43)) == 43 149 pytest.raises(TypeError, m.test_no_assign_exp, 43) 150 151 152@pytest.mark.skipif(not hasattr(m, "load_variant"), reason='no <variant>') 153def test_variant(doc): 154 assert m.load_variant(1) == "int" 155 assert m.load_variant("1") == "std::string" 156 assert m.load_variant(1.0) == "double" 157 assert m.load_variant(None) == "std::nullptr_t" 158 159 assert m.load_variant_2pass(1) == "int" 160 assert m.load_variant_2pass(1.0) == "double" 161 162 assert m.cast_variant() == (5, "Hello") 163 164 assert doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str" 165 166 167def test_vec_of_reference_wrapper(): 168 """#171: Can't return reference wrappers (or STL structures containing them)""" 169 assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \ 170 "[UserType(1), UserType(2), UserType(3), UserType(4)]" 171 172 173def test_stl_pass_by_pointer(msg): 174 """Passing nullptr or None to an STL container pointer is not expected to work""" 175 with pytest.raises(TypeError) as excinfo: 176 m.stl_pass_by_pointer() # default value is `nullptr` 177 assert msg(excinfo.value) == """ 178 stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: 179 1. (v: List[int] = None) -> List[int] 180 181 Invoked with: 182 """ # noqa: E501 line too long 183 184 with pytest.raises(TypeError) as excinfo: 185 m.stl_pass_by_pointer(None) 186 assert msg(excinfo.value) == """ 187 stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: 188 1. (v: List[int] = None) -> List[int] 189 190 Invoked with: None 191 """ # noqa: E501 line too long 192 193 assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3] 194 195 196def test_missing_header_message(): 197 """Trying convert `list` to a `std::vector`, or vice versa, without including 198 <pybind11/stl.h> should result in a helpful suggestion in the error message""" 199 import pybind11_cross_module_tests as cm 200 201 expected_message = ("Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\n" 202 "<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\n" 203 "conversions are optional and require extra headers to be included\n" 204 "when compiling your pybind11 module.") 205 206 with pytest.raises(TypeError) as excinfo: 207 cm.missing_header_arg([1.0, 2.0, 3.0]) 208 assert expected_message in str(excinfo.value) 209 210 with pytest.raises(TypeError) as excinfo: 211 cm.missing_header_return() 212 assert expected_message in str(excinfo.value) 213 214 215def test_function_with_string_and_vector_string_arg(): 216 """Check if a string is NOT implicitly converted to a list, which was the 217 behavior before fix of issue #1258""" 218 assert m.func_with_string_or_vector_string_arg_overload(('A', 'B', )) == 2 219 assert m.func_with_string_or_vector_string_arg_overload(['A', 'B']) == 2 220 assert m.func_with_string_or_vector_string_arg_overload('A') == 3 221 222 223def test_stl_ownership(): 224 cstats = ConstructorStats.get(m.Placeholder) 225 assert cstats.alive() == 0 226 r = m.test_stl_ownership() 227 assert len(r) == 1 228 del r 229 assert cstats.alive() == 0 230 231 232def test_array_cast_sequence(): 233 assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3] 234 235 236def test_issue_1561(): 237 """ check fix for issue #1561 """ 238 bar = m.Issue1561Outer() 239 bar.list = [m.Issue1561Inner('bar')] 240 bar.list 241 assert bar.list[0].data == 'bar' 242