test_methods_and_attributes.py revision 11986:c12e4625ab56
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_const(3, 3.0) == "(int, float) const" 37 assert instance1.overloaded_const(4.0, 4) == "(float, int) const" 38 39 assert instance1.value == 320 40 instance1.value = 100 41 assert str(instance1) == "ExampleMandA[value=100]" 42 43 cstats = ConstructorStats.get(ExampleMandA) 44 assert cstats.alive() == 2 45 del instance1, instance2 46 assert cstats.alive() == 0 47 assert cstats.values() == ["32"] 48 assert cstats.default_constructions == 1 49 assert cstats.copy_constructions == 3 50 assert cstats.move_constructions >= 1 51 assert cstats.copy_assignments == 0 52 assert cstats.move_assignments == 0 53 54 55def test_properties(): 56 from pybind11_tests import TestProperties 57 58 instance = TestProperties() 59 60 assert instance.def_readonly == 1 61 with pytest.raises(AttributeError): 62 instance.def_readonly = 2 63 64 instance.def_readwrite = 2 65 assert instance.def_readwrite == 2 66 67 assert instance.def_property_readonly == 2 68 with pytest.raises(AttributeError): 69 instance.def_property_readonly = 3 70 71 instance.def_property = 3 72 assert instance.def_property == 3 73 74 75def test_static_properties(): 76 from pybind11_tests import TestProperties as Type 77 78 assert Type.def_readonly_static == 1 79 with pytest.raises(AttributeError): 80 Type.def_readonly_static = 2 81 82 Type.def_readwrite_static = 2 83 assert Type.def_readwrite_static == 2 84 85 assert Type.def_property_readonly_static == 2 86 with pytest.raises(AttributeError): 87 Type.def_property_readonly_static = 3 88 89 Type.def_property_static = 3 90 assert Type.def_property_static == 3 91 92 93@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) 94def test_property_return_value_policies(access): 95 from pybind11_tests import TestPropRVP 96 97 if not access.startswith("static"): 98 obj = TestPropRVP() 99 else: 100 obj = TestPropRVP 101 102 ref = getattr(obj, access + "_ref") 103 assert ref.value == 1 104 ref.value = 2 105 assert getattr(obj, access + "_ref").value == 2 106 ref.value = 1 # restore original value for static properties 107 108 copy = getattr(obj, access + "_copy") 109 assert copy.value == 1 110 copy.value = 2 111 assert getattr(obj, access + "_copy").value == 1 112 113 copy = getattr(obj, access + "_func") 114 assert copy.value == 1 115 copy.value = 2 116 assert getattr(obj, access + "_func").value == 1 117 118 119def test_property_rvalue_policy(): 120 """When returning an rvalue, the return value policy is automatically changed from 121 `reference(_internal)` to `move`. The following would not work otherwise. 122 """ 123 from pybind11_tests import TestPropRVP 124 125 instance = TestPropRVP() 126 o = instance.rvalue 127 assert o.value == 1 128 o = TestPropRVP.static_rvalue 129 assert o.value == 1 130 131 132def test_dynamic_attributes(): 133 from pybind11_tests import DynamicClass, CppDerivedDynamicClass 134 135 instance = DynamicClass() 136 assert not hasattr(instance, "foo") 137 assert "foo" not in dir(instance) 138 139 # Dynamically add attribute 140 instance.foo = 42 141 assert hasattr(instance, "foo") 142 assert instance.foo == 42 143 assert "foo" in dir(instance) 144 145 # __dict__ should be accessible and replaceable 146 assert "foo" in instance.__dict__ 147 instance.__dict__ = {"bar": True} 148 assert not hasattr(instance, "foo") 149 assert hasattr(instance, "bar") 150 151 with pytest.raises(TypeError) as excinfo: 152 instance.__dict__ = [] 153 assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" 154 155 cstats = ConstructorStats.get(DynamicClass) 156 assert cstats.alive() == 1 157 del instance 158 assert cstats.alive() == 0 159 160 # Derived classes should work as well 161 class PythonDerivedDynamicClass(DynamicClass): 162 pass 163 164 for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass: 165 derived = cls() 166 derived.foobar = 100 167 assert derived.foobar == 100 168 169 assert cstats.alive() == 1 170 del derived 171 assert cstats.alive() == 0 172 173 174def test_cyclic_gc(): 175 from pybind11_tests import DynamicClass 176 177 # One object references itself 178 instance = DynamicClass() 179 instance.circular_reference = instance 180 181 cstats = ConstructorStats.get(DynamicClass) 182 assert cstats.alive() == 1 183 del instance 184 assert cstats.alive() == 0 185 186 # Two object reference each other 187 i1 = DynamicClass() 188 i2 = DynamicClass() 189 i1.cycle = i2 190 i2.cycle = i1 191 192 assert cstats.alive() == 2 193 del i1, i2 194 assert cstats.alive() == 0 195