1# -*- coding: utf-8 -*- 2import pytest 3 4import env # noqa: F401 5 6from pybind11_tests import class_ as m 7from pybind11_tests import UserType, ConstructorStats 8 9 10def test_repr(): 11 # In Python 3.3+, repr() accesses __qualname__ 12 assert "pybind11_type" in repr(type(UserType)) 13 assert "UserType" in repr(UserType) 14 15 16def test_instance(msg): 17 with pytest.raises(TypeError) as excinfo: 18 m.NoConstructor() 19 assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!" 20 21 instance = m.NoConstructor.new_instance() 22 23 cstats = ConstructorStats.get(m.NoConstructor) 24 assert cstats.alive() == 1 25 del instance 26 assert cstats.alive() == 0 27 28 29def test_type(): 30 assert m.check_type(1) == m.DerivedClass1 31 with pytest.raises(RuntimeError) as execinfo: 32 m.check_type(0) 33 34 assert "pybind11::detail::get_type_info: unable to find type info" in str( 35 execinfo.value 36 ) 37 assert "Invalid" in str(execinfo.value) 38 39 # Currently not supported 40 # See https://github.com/pybind/pybind11/issues/2486 41 # assert m.check_type(2) == int 42 43 44def test_type_of_py(): 45 assert m.get_type_of(1) == int 46 assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1 47 assert m.get_type_of(int) == type 48 49 50def test_type_of_classic(): 51 assert m.get_type_classic(1) == int 52 assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1 53 assert m.get_type_classic(int) == type 54 55 56def test_type_of_py_nodelete(): 57 # If the above test deleted the class, this will segfault 58 assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1 59 60 61def test_as_type_py(): 62 assert m.as_type(int) == int 63 64 with pytest.raises(TypeError): 65 assert m.as_type(1) == int 66 67 with pytest.raises(TypeError): 68 assert m.as_type(m.DerivedClass1()) == m.DerivedClass1 69 70 71def test_docstrings(doc): 72 assert doc(UserType) == "A `py::class_` type for testing" 73 assert UserType.__name__ == "UserType" 74 assert UserType.__module__ == "pybind11_tests" 75 assert UserType.get_value.__name__ == "get_value" 76 assert UserType.get_value.__module__ == "pybind11_tests" 77 78 assert ( 79 doc(UserType.get_value) 80 == """ 81 get_value(self: m.UserType) -> int 82 83 Get value using a method 84 """ 85 ) 86 assert doc(UserType.value) == "Get/set value using a property" 87 88 assert ( 89 doc(m.NoConstructor.new_instance) 90 == """ 91 new_instance() -> m.class_.NoConstructor 92 93 Return an instance 94 """ 95 ) 96 97 98def test_qualname(doc): 99 """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we 100 backport the attribute) and that generated docstrings properly use it and the module name""" 101 assert m.NestBase.__qualname__ == "NestBase" 102 assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" 103 104 assert ( 105 doc(m.NestBase.__init__) 106 == """ 107 __init__(self: m.class_.NestBase) -> None 108 """ 109 ) 110 assert ( 111 doc(m.NestBase.g) 112 == """ 113 g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None 114 """ 115 ) 116 assert ( 117 doc(m.NestBase.Nested.__init__) 118 == """ 119 __init__(self: m.class_.NestBase.Nested) -> None 120 """ 121 ) 122 assert ( 123 doc(m.NestBase.Nested.fn) 124 == """ 125 fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None 126 """ # noqa: E501 line too long 127 ) 128 assert ( 129 doc(m.NestBase.Nested.fa) 130 == """ 131 fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None 132 """ # noqa: E501 line too long 133 ) 134 assert m.NestBase.__module__ == "pybind11_tests.class_" 135 assert m.NestBase.Nested.__module__ == "pybind11_tests.class_" 136 137 138def test_inheritance(msg): 139 roger = m.Rabbit("Rabbit") 140 assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" 141 assert m.pet_name_species(roger) == "Rabbit is a parrot" 142 143 polly = m.Pet("Polly", "parrot") 144 assert polly.name() + " is a " + polly.species() == "Polly is a parrot" 145 assert m.pet_name_species(polly) == "Polly is a parrot" 146 147 molly = m.Dog("Molly") 148 assert molly.name() + " is a " + molly.species() == "Molly is a dog" 149 assert m.pet_name_species(molly) == "Molly is a dog" 150 151 fred = m.Hamster("Fred") 152 assert fred.name() + " is a " + fred.species() == "Fred is a rodent" 153 154 assert m.dog_bark(molly) == "Woof!" 155 156 with pytest.raises(TypeError) as excinfo: 157 m.dog_bark(polly) 158 assert ( 159 msg(excinfo.value) 160 == """ 161 dog_bark(): incompatible function arguments. The following argument types are supported: 162 1. (arg0: m.class_.Dog) -> str 163 164 Invoked with: <m.class_.Pet object at 0> 165 """ 166 ) 167 168 with pytest.raises(TypeError) as excinfo: 169 m.Chimera("lion", "goat") 170 assert "No constructor defined!" in str(excinfo.value) 171 172 173def test_inheritance_init(msg): 174 175 # Single base 176 class Python(m.Pet): 177 def __init__(self): 178 pass 179 180 with pytest.raises(TypeError) as exc_info: 181 Python() 182 expected = "m.class_.Pet.__init__() must be called when overriding __init__" 183 assert msg(exc_info.value) == expected 184 185 # Multiple bases 186 class RabbitHamster(m.Rabbit, m.Hamster): 187 def __init__(self): 188 m.Rabbit.__init__(self, "RabbitHamster") 189 190 with pytest.raises(TypeError) as exc_info: 191 RabbitHamster() 192 expected = "m.class_.Hamster.__init__() must be called when overriding __init__" 193 assert msg(exc_info.value) == expected 194 195 196def test_automatic_upcasting(): 197 assert type(m.return_class_1()).__name__ == "DerivedClass1" 198 assert type(m.return_class_2()).__name__ == "DerivedClass2" 199 assert type(m.return_none()).__name__ == "NoneType" 200 # Repeat these a few times in a random order to ensure no invalid caching is applied 201 assert type(m.return_class_n(1)).__name__ == "DerivedClass1" 202 assert type(m.return_class_n(2)).__name__ == "DerivedClass2" 203 assert type(m.return_class_n(0)).__name__ == "BaseClass" 204 assert type(m.return_class_n(2)).__name__ == "DerivedClass2" 205 assert type(m.return_class_n(2)).__name__ == "DerivedClass2" 206 assert type(m.return_class_n(0)).__name__ == "BaseClass" 207 assert type(m.return_class_n(1)).__name__ == "DerivedClass1" 208 209 210def test_isinstance(): 211 objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4 212 expected = (True, True, True, True, True, False, False) 213 assert m.check_instances(objects) == expected 214 215 216def test_mismatched_holder(): 217 import re 218 219 with pytest.raises(RuntimeError) as excinfo: 220 m.mismatched_holder_1() 221 assert re.match( 222 'generic_type: type ".*MismatchDerived1" does not have a non-default ' 223 'holder type while its base ".*MismatchBase1" does', 224 str(excinfo.value), 225 ) 226 227 with pytest.raises(RuntimeError) as excinfo: 228 m.mismatched_holder_2() 229 assert re.match( 230 'generic_type: type ".*MismatchDerived2" has a non-default holder type ' 231 'while its base ".*MismatchBase2" does not', 232 str(excinfo.value), 233 ) 234 235 236def test_override_static(): 237 """#511: problem with inheritance + overwritten def_static""" 238 b = m.MyBase.make() 239 d1 = m.MyDerived.make2() 240 d2 = m.MyDerived.make() 241 242 assert isinstance(b, m.MyBase) 243 assert isinstance(d1, m.MyDerived) 244 assert isinstance(d2, m.MyDerived) 245 246 247def test_implicit_conversion_life_support(): 248 """Ensure the lifetime of temporary objects created for implicit conversions""" 249 assert m.implicitly_convert_argument(UserType(5)) == 5 250 assert m.implicitly_convert_variable(UserType(5)) == 5 251 252 assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5)) 253 254 255def test_operator_new_delete(capture): 256 """Tests that class-specific operator new/delete functions are invoked""" 257 258 class SubAliased(m.AliasedHasOpNewDelSize): 259 pass 260 261 with capture: 262 a = m.HasOpNewDel() 263 b = m.HasOpNewDelSize() 264 d = m.HasOpNewDelBoth() 265 assert ( 266 capture 267 == """ 268 A new 8 269 B new 4 270 D new 32 271 """ 272 ) 273 sz_alias = str(m.AliasedHasOpNewDelSize.size_alias) 274 sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias) 275 with capture: 276 c = m.AliasedHasOpNewDelSize() 277 c2 = SubAliased() 278 assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n") 279 280 with capture: 281 del a 282 pytest.gc_collect() 283 del b 284 pytest.gc_collect() 285 del d 286 pytest.gc_collect() 287 assert ( 288 capture 289 == """ 290 A delete 291 B delete 4 292 D delete 293 """ 294 ) 295 296 with capture: 297 del c 298 pytest.gc_collect() 299 del c2 300 pytest.gc_collect() 301 assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n") 302 303 304def test_bind_protected_functions(): 305 """Expose protected member functions to Python using a helper class""" 306 a = m.ProtectedA() 307 assert a.foo() == 42 308 309 b = m.ProtectedB() 310 assert b.foo() == 42 311 312 class C(m.ProtectedB): 313 def __init__(self): 314 m.ProtectedB.__init__(self) 315 316 def foo(self): 317 return 0 318 319 c = C() 320 assert c.foo() == 0 321 322 323def test_brace_initialization(): 324 """ Tests that simple POD classes can be constructed using C++11 brace initialization """ 325 a = m.BraceInitialization(123, "test") 326 assert a.field1 == 123 327 assert a.field2 == "test" 328 329 # Tests that a non-simple class doesn't get brace initialization (if the 330 # class defines an initializer_list constructor, in particular, it would 331 # win over the expected constructor). 332 b = m.NoBraceInitialization([123, 456]) 333 assert b.vec == [123, 456] 334 335 336@pytest.mark.xfail("env.PYPY") 337def test_class_refcount(): 338 """Instances must correctly increase/decrease the reference count of their types (#1029)""" 339 from sys import getrefcount 340 341 class PyDog(m.Dog): 342 pass 343 344 for cls in m.Dog, PyDog: 345 refcount_1 = getrefcount(cls) 346 molly = [cls("Molly") for _ in range(10)] 347 refcount_2 = getrefcount(cls) 348 349 del molly 350 pytest.gc_collect() 351 refcount_3 = getrefcount(cls) 352 353 assert refcount_1 == refcount_3 354 assert refcount_2 > refcount_1 355 356 357def test_reentrant_implicit_conversion_failure(msg): 358 # ensure that there is no runaway reentrant implicit conversion (#1035) 359 with pytest.raises(TypeError) as excinfo: 360 m.BogusImplicitConversion(0) 361 assert ( 362 msg(excinfo.value) 363 == """ 364 __init__(): incompatible constructor arguments. The following argument types are supported: 365 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion) 366 367 Invoked with: 0 368 """ 369 ) 370 371 372def test_error_after_conversions(): 373 with pytest.raises(TypeError) as exc_info: 374 m.test_error_after_conversions("hello") 375 assert str(exc_info.value).startswith( 376 "Unable to convert function return value to a Python type!" 377 ) 378 379 380def test_aligned(): 381 if hasattr(m, "Aligned"): 382 p = m.Aligned().ptr() 383 assert p % 1024 == 0 384 385 386# https://foss.heptapod.net/pypy/pypy/-/issues/2742 387@pytest.mark.xfail("env.PYPY") 388def test_final(): 389 with pytest.raises(TypeError) as exc_info: 390 391 class PyFinalChild(m.IsFinal): 392 pass 393 394 assert str(exc_info.value).endswith("is not an acceptable base type") 395 396 397# https://foss.heptapod.net/pypy/pypy/-/issues/2742 398@pytest.mark.xfail("env.PYPY") 399def test_non_final_final(): 400 with pytest.raises(TypeError) as exc_info: 401 402 class PyNonFinalFinalChild(m.IsNonFinalFinal): 403 pass 404 405 assert str(exc_info.value).endswith("is not an acceptable base type") 406 407 408# https://github.com/pybind/pybind11/issues/1878 409def test_exception_rvalue_abort(): 410 with pytest.raises(RuntimeError): 411 m.PyPrintDestructor().throw_something() 412 413 414# https://github.com/pybind/pybind11/issues/1568 415def test_multiple_instances_with_same_pointer(capture): 416 n = 100 417 instances = [m.SamePointer() for _ in range(n)] 418 for i in range(n): 419 # We need to reuse the same allocated memory for with a different type, 420 # to ensure the bug in `deregister_instance_impl` is detected. Otherwise 421 # `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though 422 # the `instance` is already deleted. 423 instances[i] = m.Empty() 424 # No assert: if this does not trigger the error 425 # pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); 426 # and just completes without crashing, we're good. 427 428 429# https://github.com/pybind/pybind11/issues/1624 430def test_base_and_derived_nested_scope(): 431 assert issubclass(m.DerivedWithNested, m.BaseWithNested) 432 assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested 433 assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested" 434 assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested" 435 436 437def test_register_duplicate_class(): 438 import types 439 440 module_scope = types.ModuleType("module_scope") 441 with pytest.raises(RuntimeError) as exc_info: 442 m.register_duplicate_class_name(module_scope) 443 expected = ( 444 'generic_type: cannot initialize type "Duplicate": ' 445 "an object with that name is already defined" 446 ) 447 assert str(exc_info.value) == expected 448 with pytest.raises(RuntimeError) as exc_info: 449 m.register_duplicate_class_type(module_scope) 450 expected = 'generic_type: type "YetAnotherDuplicate" is already registered!' 451 assert str(exc_info.value) == expected 452 453 class ClassScope: 454 pass 455 456 with pytest.raises(RuntimeError) as exc_info: 457 m.register_duplicate_nested_class_name(ClassScope) 458 expected = ( 459 'generic_type: cannot initialize type "DuplicateNested": ' 460 "an object with that name is already defined" 461 ) 462 assert str(exc_info.value) == expected 463 with pytest.raises(RuntimeError) as exc_info: 464 m.register_duplicate_nested_class_type(ClassScope) 465 expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!' 466 assert str(exc_info.value) == expected 467