test_methods_and_attributes.py revision 12037
1import pytest 2from pybind11_tests import ExampleMandA, ConstructorStats 3 4 5def test_methods_and_attributes(): 6 instance1 = ExampleMandA() 7 instance2 = ExampleMandA(32) 8 9 instance1.add1(instance2) 10 instance1.add2(instance2) 11 instance1.add3(instance2) 12 instance1.add4(instance2) 13 instance1.add5(instance2) 14 instance1.add6(32) 15 instance1.add7(32) 16 instance1.add8(32) 17 instance1.add9(32) 18 instance1.add10(32) 19 20 assert str(instance1) == "ExampleMandA[value=320]" 21 assert str(instance2) == "ExampleMandA[value=32]" 22 assert str(instance1.self1()) == "ExampleMandA[value=320]" 23 assert str(instance1.self2()) == "ExampleMandA[value=320]" 24 assert str(instance1.self3()) == "ExampleMandA[value=320]" 25 assert str(instance1.self4()) == "ExampleMandA[value=320]" 26 assert str(instance1.self5()) == "ExampleMandA[value=320]" 27 28 assert instance1.internal1() == 320 29 assert instance1.internal2() == 320 30 assert instance1.internal3() == 320 31 assert instance1.internal4() == 320 32 assert instance1.internal5() == 320 33 34 assert instance1.overloaded(1, 1.0) == "(int, float)" 35 assert instance1.overloaded(2.0, 2) == "(float, int)" 36 assert instance1.overloaded(3, 3) == "(int, int)" 37 assert instance1.overloaded(4., 4.) == "(float, float)" 38 assert instance1.overloaded_const(5, 5.0) == "(int, float) const" 39 assert instance1.overloaded_const(6.0, 6) == "(float, int) const" 40 assert instance1.overloaded_const(7, 7) == "(int, int) const" 41 assert instance1.overloaded_const(8., 8.) == "(float, float) const" 42 assert instance1.overloaded_float(1, 1) == "(float, float)" 43 assert instance1.overloaded_float(1, 1.) == "(float, float)" 44 assert instance1.overloaded_float(1., 1) == "(float, float)" 45 assert instance1.overloaded_float(1., 1.) == "(float, float)" 46 47 assert instance1.value == 320 48 instance1.value = 100 49 assert str(instance1) == "ExampleMandA[value=100]" 50 51 cstats = ConstructorStats.get(ExampleMandA) 52 assert cstats.alive() == 2 53 del instance1, instance2 54 assert cstats.alive() == 0 55 assert cstats.values() == ["32"] 56 assert cstats.default_constructions == 1 57 assert cstats.copy_constructions == 3 58 assert cstats.move_constructions >= 1 59 assert cstats.copy_assignments == 0 60 assert cstats.move_assignments == 0 61 62 63def test_properties(): 64 from pybind11_tests import TestProperties 65 66 instance = TestProperties() 67 68 assert instance.def_readonly == 1 69 with pytest.raises(AttributeError): 70 instance.def_readonly = 2 71 72 instance.def_readwrite = 2 73 assert instance.def_readwrite == 2 74 75 assert instance.def_property_readonly == 2 76 with pytest.raises(AttributeError): 77 instance.def_property_readonly = 3 78 79 instance.def_property = 3 80 assert instance.def_property == 3 81 82 83def test_static_properties(): 84 from pybind11_tests import TestProperties as Type 85 86 assert Type.def_readonly_static == 1 87 with pytest.raises(AttributeError) as excinfo: 88 Type.def_readonly_static = 2 89 assert "can't set attribute" in str(excinfo) 90 91 Type.def_readwrite_static = 2 92 assert Type.def_readwrite_static == 2 93 94 assert Type.def_property_readonly_static == 2 95 with pytest.raises(AttributeError) as excinfo: 96 Type.def_property_readonly_static = 3 97 assert "can't set attribute" in str(excinfo) 98 99 Type.def_property_static = 3 100 assert Type.def_property_static == 3 101 102 # Static property read and write via instance 103 instance = Type() 104 105 Type.def_readwrite_static = 0 106 assert Type.def_readwrite_static == 0 107 assert instance.def_readwrite_static == 0 108 109 instance.def_readwrite_static = 2 110 assert Type.def_readwrite_static == 2 111 assert instance.def_readwrite_static == 2 112 113 114def test_static_cls(): 115 """Static property getter and setters expect the type object as the their only argument""" 116 from pybind11_tests import TestProperties as Type 117 118 instance = Type() 119 assert Type.static_cls is Type 120 assert instance.static_cls is Type 121 122 def check_self(self): 123 assert self is Type 124 125 Type.static_cls = check_self 126 instance.static_cls = check_self 127 128 129def test_metaclass_override(): 130 """Overriding pybind11's default metaclass changes the behavior of `static_property`""" 131 from pybind11_tests import MetaclassOverride 132 133 assert type(ExampleMandA).__name__ == "pybind11_type" 134 assert type(MetaclassOverride).__name__ == "type" 135 136 assert MetaclassOverride.readonly == 1 137 assert type(MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" 138 139 # Regular `type` replaces the property instead of calling `__set__()` 140 MetaclassOverride.readonly = 2 141 assert MetaclassOverride.readonly == 2 142 assert isinstance(MetaclassOverride.__dict__["readonly"], int) 143 144 145@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) 146def test_property_return_value_policies(access): 147 from pybind11_tests import TestPropRVP 148 149 if not access.startswith("static"): 150 obj = TestPropRVP() 151 else: 152 obj = TestPropRVP 153 154 ref = getattr(obj, access + "_ref") 155 assert ref.value == 1 156 ref.value = 2 157 assert getattr(obj, access + "_ref").value == 2 158 ref.value = 1 # restore original value for static properties 159 160 copy = getattr(obj, access + "_copy") 161 assert copy.value == 1 162 copy.value = 2 163 assert getattr(obj, access + "_copy").value == 1 164 165 copy = getattr(obj, access + "_func") 166 assert copy.value == 1 167 copy.value = 2 168 assert getattr(obj, access + "_func").value == 1 169 170 171def test_property_rvalue_policy(): 172 """When returning an rvalue, the return value policy is automatically changed from 173 `reference(_internal)` to `move`. The following would not work otherwise. 174 """ 175 from pybind11_tests import TestPropRVP 176 177 instance = TestPropRVP() 178 o = instance.rvalue 179 assert o.value == 1 180 181 182def test_property_rvalue_policy_static(): 183 """When returning an rvalue, the return value policy is automatically changed from 184 `reference(_internal)` to `move`. The following would not work otherwise. 185 """ 186 from pybind11_tests import TestPropRVP 187 o = TestPropRVP.static_rvalue 188 assert o.value == 1 189 190 191# https://bitbucket.org/pypy/pypy/issues/2447 192@pytest.unsupported_on_pypy 193def test_dynamic_attributes(): 194 from pybind11_tests import DynamicClass, CppDerivedDynamicClass 195 196 instance = DynamicClass() 197 assert not hasattr(instance, "foo") 198 assert "foo" not in dir(instance) 199 200 # Dynamically add attribute 201 instance.foo = 42 202 assert hasattr(instance, "foo") 203 assert instance.foo == 42 204 assert "foo" in dir(instance) 205 206 # __dict__ should be accessible and replaceable 207 assert "foo" in instance.__dict__ 208 instance.__dict__ = {"bar": True} 209 assert not hasattr(instance, "foo") 210 assert hasattr(instance, "bar") 211 212 with pytest.raises(TypeError) as excinfo: 213 instance.__dict__ = [] 214 assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" 215 216 cstats = ConstructorStats.get(DynamicClass) 217 assert cstats.alive() == 1 218 del instance 219 assert cstats.alive() == 0 220 221 # Derived classes should work as well 222 class PythonDerivedDynamicClass(DynamicClass): 223 pass 224 225 for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass: 226 derived = cls() 227 derived.foobar = 100 228 assert derived.foobar == 100 229 230 assert cstats.alive() == 1 231 del derived 232 assert cstats.alive() == 0 233 234 235# https://bitbucket.org/pypy/pypy/issues/2447 236@pytest.unsupported_on_pypy 237def test_cyclic_gc(): 238 from pybind11_tests import DynamicClass 239 240 # One object references itself 241 instance = DynamicClass() 242 instance.circular_reference = instance 243 244 cstats = ConstructorStats.get(DynamicClass) 245 assert cstats.alive() == 1 246 del instance 247 assert cstats.alive() == 0 248 249 # Two object reference each other 250 i1 = DynamicClass() 251 i2 = DynamicClass() 252 i1.cycle = i2 253 i2.cycle = i1 254 255 assert cstats.alive() == 2 256 del i1, i2 257 assert cstats.alive() == 0 258 259 260def test_noconvert_args(msg): 261 from pybind11_tests import ArgInspector, arg_inspect_func, floats_only, floats_preferred 262 263 a = ArgInspector() 264 assert msg(a.f("hi")) == """ 265 loading ArgInspector1 argument WITH conversion allowed. Argument value = hi 266 """ 267 assert msg(a.g("this is a", "this is b")) == """ 268 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a 269 loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 270 13 271 loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) 272 """ # noqa: E501 line too long 273 assert msg(a.g("this is a", "this is b", 42)) == """ 274 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a 275 loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 276 42 277 loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) 278 """ # noqa: E501 line too long 279 assert msg(a.g("this is a", "this is b", 42, "this is d")) == """ 280 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a 281 loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b 282 42 283 loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d 284 """ 285 assert (a.h("arg 1") == 286 "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1") 287 assert msg(arg_inspect_func("A1", "A2")) == """ 288 loading ArgInspector2 argument WITH conversion allowed. Argument value = A1 289 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 290 """ 291 292 assert floats_preferred(4) == 2.0 293 assert floats_only(4.0) == 2.0 294 with pytest.raises(TypeError) as excinfo: 295 floats_only(4) 296 assert msg(excinfo.value) == """ 297 floats_only(): incompatible function arguments. The following argument types are supported: 298 1. (f: float) -> float 299 300 Invoked with: 4 301 """ 302 303 304def test_bad_arg_default(msg): 305 from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed 306 307 with pytest.raises(RuntimeError) as excinfo: 308 bad_arg_def_named() 309 assert msg(excinfo.value) == ( 310 "arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' " 311 "into a Python object (type not registered yet?)" 312 if debug_enabled else 313 "arg(): could not convert default argument into a Python object (type not registered " 314 "yet?). Compile in debug mode for more information." 315 ) 316 317 with pytest.raises(RuntimeError) as excinfo: 318 bad_arg_def_unnamed() 319 assert msg(excinfo.value) == ( 320 "arg(): could not convert default argument 'NotRegistered' in function 'should_fail' " 321 "into a Python object (type not registered yet?)" 322 if debug_enabled else 323 "arg(): could not convert default argument into a Python object (type not registered " 324 "yet?). Compile in debug mode for more information." 325 ) 326