test_class.py revision 14299:2fbea9df56d2
1import pytest 2 3from pybind11_tests import class_ as m 4from pybind11_tests import UserType, ConstructorStats 5 6 7def test_repr(): 8 # In Python 3.3+, repr() accesses __qualname__ 9 assert "pybind11_type" in repr(type(UserType)) 10 assert "UserType" in repr(UserType) 11 12 13def test_instance(msg): 14 with pytest.raises(TypeError) as excinfo: 15 m.NoConstructor() 16 assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!" 17 18 instance = m.NoConstructor.new_instance() 19 20 cstats = ConstructorStats.get(m.NoConstructor) 21 assert cstats.alive() == 1 22 del instance 23 assert cstats.alive() == 0 24 25 26def test_docstrings(doc): 27 assert doc(UserType) == "A `py::class_` type for testing" 28 assert UserType.__name__ == "UserType" 29 assert UserType.__module__ == "pybind11_tests" 30 assert UserType.get_value.__name__ == "get_value" 31 assert UserType.get_value.__module__ == "pybind11_tests" 32 33 assert doc(UserType.get_value) == """ 34 get_value(self: m.UserType) -> int 35 36 Get value using a method 37 """ 38 assert doc(UserType.value) == "Get/set value using a property" 39 40 assert doc(m.NoConstructor.new_instance) == """ 41 new_instance() -> m.class_.NoConstructor 42 43 Return an instance 44 """ 45 46 47def test_qualname(doc): 48 """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we 49 backport the attribute) and that generated docstrings properly use it and the module name""" 50 assert m.NestBase.__qualname__ == "NestBase" 51 assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" 52 53 assert doc(m.NestBase.__init__) == """ 54 __init__(self: m.class_.NestBase) -> None 55 """ 56 assert doc(m.NestBase.g) == """ 57 g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None 58 """ 59 assert doc(m.NestBase.Nested.__init__) == """ 60 __init__(self: m.class_.NestBase.Nested) -> None 61 """ 62 assert doc(m.NestBase.Nested.fn) == """ 63 fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None 64 """ # noqa: E501 line too long 65 assert doc(m.NestBase.Nested.fa) == """ 66 fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None 67 """ # noqa: E501 line too long 68 assert m.NestBase.__module__ == "pybind11_tests.class_" 69 assert m.NestBase.Nested.__module__ == "pybind11_tests.class_" 70 71 72def test_inheritance(msg): 73 roger = m.Rabbit('Rabbit') 74 assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" 75 assert m.pet_name_species(roger) == "Rabbit is a parrot" 76 77 polly = m.Pet('Polly', 'parrot') 78 assert polly.name() + " is a " + polly.species() == "Polly is a parrot" 79 assert m.pet_name_species(polly) == "Polly is a parrot" 80 81 molly = m.Dog('Molly') 82 assert molly.name() + " is a " + molly.species() == "Molly is a dog" 83 assert m.pet_name_species(molly) == "Molly is a dog" 84 85 fred = m.Hamster('Fred') 86 assert fred.name() + " is a " + fred.species() == "Fred is a rodent" 87 88 assert m.dog_bark(molly) == "Woof!" 89 90 with pytest.raises(TypeError) as excinfo: 91 m.dog_bark(polly) 92 assert msg(excinfo.value) == """ 93 dog_bark(): incompatible function arguments. The following argument types are supported: 94 1. (arg0: m.class_.Dog) -> str 95 96 Invoked with: <m.class_.Pet object at 0> 97 """ 98 99 with pytest.raises(TypeError) as excinfo: 100 m.Chimera("lion", "goat") 101 assert "No constructor defined!" in str(excinfo.value) 102 103 104def test_automatic_upcasting(): 105 assert type(m.return_class_1()).__name__ == "DerivedClass1" 106 assert type(m.return_class_2()).__name__ == "DerivedClass2" 107 assert type(m.return_none()).__name__ == "NoneType" 108 # Repeat these a few times in a random order to ensure no invalid caching is applied 109 assert type(m.return_class_n(1)).__name__ == "DerivedClass1" 110 assert type(m.return_class_n(2)).__name__ == "DerivedClass2" 111 assert type(m.return_class_n(0)).__name__ == "BaseClass" 112 assert type(m.return_class_n(2)).__name__ == "DerivedClass2" 113 assert type(m.return_class_n(2)).__name__ == "DerivedClass2" 114 assert type(m.return_class_n(0)).__name__ == "BaseClass" 115 assert type(m.return_class_n(1)).__name__ == "DerivedClass1" 116 117 118def test_isinstance(): 119 objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4 120 expected = (True, True, True, True, True, False, False) 121 assert m.check_instances(objects) == expected 122 123 124def test_mismatched_holder(): 125 import re 126 127 with pytest.raises(RuntimeError) as excinfo: 128 m.mismatched_holder_1() 129 assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default ' 130 'holder type while its base ".*MismatchBase1" does', str(excinfo.value)) 131 132 with pytest.raises(RuntimeError) as excinfo: 133 m.mismatched_holder_2() 134 assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type ' 135 'while its base ".*MismatchBase2" does not', str(excinfo.value)) 136 137 138def test_override_static(): 139 """#511: problem with inheritance + overwritten def_static""" 140 b = m.MyBase.make() 141 d1 = m.MyDerived.make2() 142 d2 = m.MyDerived.make() 143 144 assert isinstance(b, m.MyBase) 145 assert isinstance(d1, m.MyDerived) 146 assert isinstance(d2, m.MyDerived) 147 148 149def test_implicit_conversion_life_support(): 150 """Ensure the lifetime of temporary objects created for implicit conversions""" 151 assert m.implicitly_convert_argument(UserType(5)) == 5 152 assert m.implicitly_convert_variable(UserType(5)) == 5 153 154 assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5)) 155 156 157def test_operator_new_delete(capture): 158 """Tests that class-specific operator new/delete functions are invoked""" 159 160 class SubAliased(m.AliasedHasOpNewDelSize): 161 pass 162 163 with capture: 164 a = m.HasOpNewDel() 165 b = m.HasOpNewDelSize() 166 d = m.HasOpNewDelBoth() 167 assert capture == """ 168 A new 8 169 B new 4 170 D new 32 171 """ 172 sz_alias = str(m.AliasedHasOpNewDelSize.size_alias) 173 sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias) 174 with capture: 175 c = m.AliasedHasOpNewDelSize() 176 c2 = SubAliased() 177 assert capture == ( 178 "C new " + sz_noalias + "\n" + 179 "C new " + sz_alias + "\n" 180 ) 181 182 with capture: 183 del a 184 pytest.gc_collect() 185 del b 186 pytest.gc_collect() 187 del d 188 pytest.gc_collect() 189 assert capture == """ 190 A delete 191 B delete 4 192 D delete 193 """ 194 195 with capture: 196 del c 197 pytest.gc_collect() 198 del c2 199 pytest.gc_collect() 200 assert capture == ( 201 "C delete " + sz_noalias + "\n" + 202 "C delete " + sz_alias + "\n" 203 ) 204 205 206def test_bind_protected_functions(): 207 """Expose protected member functions to Python using a helper class""" 208 a = m.ProtectedA() 209 assert a.foo() == 42 210 211 b = m.ProtectedB() 212 assert b.foo() == 42 213 214 class C(m.ProtectedB): 215 def __init__(self): 216 m.ProtectedB.__init__(self) 217 218 def foo(self): 219 return 0 220 221 c = C() 222 assert c.foo() == 0 223 224 225def test_brace_initialization(): 226 """ Tests that simple POD classes can be constructed using C++11 brace initialization """ 227 a = m.BraceInitialization(123, "test") 228 assert a.field1 == 123 229 assert a.field2 == "test" 230 231 # Tests that a non-simple class doesn't get brace initialization (if the 232 # class defines an initializer_list constructor, in particular, it would 233 # win over the expected constructor). 234 b = m.NoBraceInitialization([123, 456]) 235 assert b.vec == [123, 456] 236 237 238@pytest.unsupported_on_pypy 239def test_class_refcount(): 240 """Instances must correctly increase/decrease the reference count of their types (#1029)""" 241 from sys import getrefcount 242 243 class PyDog(m.Dog): 244 pass 245 246 for cls in m.Dog, PyDog: 247 refcount_1 = getrefcount(cls) 248 molly = [cls("Molly") for _ in range(10)] 249 refcount_2 = getrefcount(cls) 250 251 del molly 252 pytest.gc_collect() 253 refcount_3 = getrefcount(cls) 254 255 assert refcount_1 == refcount_3 256 assert refcount_2 > refcount_1 257 258 259def test_reentrant_implicit_conversion_failure(msg): 260 # ensure that there is no runaway reentrant implicit conversion (#1035) 261 with pytest.raises(TypeError) as excinfo: 262 m.BogusImplicitConversion(0) 263 assert msg(excinfo.value) == ''' 264 __init__(): incompatible constructor arguments. The following argument types are supported: 265 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion) 266 267 Invoked with: 0 268 ''' 269 270 271def test_error_after_conversions(): 272 with pytest.raises(TypeError) as exc_info: 273 m.test_error_after_conversions("hello") 274 assert str(exc_info.value).startswith( 275 "Unable to convert function return value to a Python type!") 276 277 278def test_aligned(): 279 if hasattr(m, "Aligned"): 280 p = m.Aligned().ptr() 281 assert p % 1024 == 0 282