aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests/test_class.py
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/pybind11/tests/test_class.py')
-rw-r--r--3rdparty/pybind11/tests/test_class.py245
1 files changed, 215 insertions, 30 deletions
diff --git a/3rdparty/pybind11/tests/test_class.py b/3rdparty/pybind11/tests/test_class.py
index ed63ca85..bdcced96 100644
--- a/3rdparty/pybind11/tests/test_class.py
+++ b/3rdparty/pybind11/tests/test_class.py
@@ -1,5 +1,8 @@
+# -*- coding: utf-8 -*-
import pytest
+import env # noqa: F401
+
from pybind11_tests import class_ as m
from pybind11_tests import UserType, ConstructorStats
@@ -23,6 +26,48 @@ def test_instance(msg):
assert cstats.alive() == 0
+def test_type():
+ assert m.check_type(1) == m.DerivedClass1
+ with pytest.raises(RuntimeError) as execinfo:
+ m.check_type(0)
+
+ assert "pybind11::detail::get_type_info: unable to find type info" in str(
+ execinfo.value
+ )
+ assert "Invalid" in str(execinfo.value)
+
+ # Currently not supported
+ # See https://github.com/pybind/pybind11/issues/2486
+ # assert m.check_type(2) == int
+
+
+def test_type_of_py():
+ assert m.get_type_of(1) == int
+ assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
+ assert m.get_type_of(int) == type
+
+
+def test_type_of_classic():
+ assert m.get_type_classic(1) == int
+ assert m.get_type_classic(m.DerivedClass1()) == m.DerivedClass1
+ assert m.get_type_classic(int) == type
+
+
+def test_type_of_py_nodelete():
+ # If the above test deleted the class, this will segfault
+ assert m.get_type_of(m.DerivedClass1()) == m.DerivedClass1
+
+
+def test_as_type_py():
+ assert m.as_type(int) == int
+
+ with pytest.raises(TypeError):
+ assert m.as_type(1) == int
+
+ with pytest.raises(TypeError):
+ assert m.as_type(m.DerivedClass1()) == m.DerivedClass1
+
+
def test_docstrings(doc):
assert doc(UserType) == "A `py::class_` type for testing"
assert UserType.__name__ == "UserType"
@@ -30,18 +75,24 @@ def test_docstrings(doc):
assert UserType.get_value.__name__ == "get_value"
assert UserType.get_value.__module__ == "pybind11_tests"
- assert doc(UserType.get_value) == """
+ assert (
+ doc(UserType.get_value)
+ == """
get_value(self: m.UserType) -> int
Get value using a method
"""
+ )
assert doc(UserType.value) == "Get/set value using a property"
- assert doc(m.NoConstructor.new_instance) == """
+ assert (
+ doc(m.NoConstructor.new_instance)
+ == """
new_instance() -> m.class_.NoConstructor
Return an instance
"""
+ )
def test_qualname(doc):
@@ -50,57 +101,98 @@ def test_qualname(doc):
assert m.NestBase.__qualname__ == "NestBase"
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
- assert doc(m.NestBase.__init__) == """
+ assert (
+ doc(m.NestBase.__init__)
+ == """
__init__(self: m.class_.NestBase) -> None
"""
- assert doc(m.NestBase.g) == """
+ )
+ assert (
+ doc(m.NestBase.g)
+ == """
g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
"""
- assert doc(m.NestBase.Nested.__init__) == """
+ )
+ assert (
+ doc(m.NestBase.Nested.__init__)
+ == """
__init__(self: m.class_.NestBase.Nested) -> None
"""
- assert doc(m.NestBase.Nested.fn) == """
+ )
+ assert (
+ doc(m.NestBase.Nested.fn)
+ == """
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
""" # noqa: E501 line too long
- assert doc(m.NestBase.Nested.fa) == """
+ )
+ assert (
+ doc(m.NestBase.Nested.fa)
+ == """
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
""" # noqa: E501 line too long
+ )
assert m.NestBase.__module__ == "pybind11_tests.class_"
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
def test_inheritance(msg):
- roger = m.Rabbit('Rabbit')
+ roger = m.Rabbit("Rabbit")
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
assert m.pet_name_species(roger) == "Rabbit is a parrot"
- polly = m.Pet('Polly', 'parrot')
+ polly = m.Pet("Polly", "parrot")
assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
assert m.pet_name_species(polly) == "Polly is a parrot"
- molly = m.Dog('Molly')
+ molly = m.Dog("Molly")
assert molly.name() + " is a " + molly.species() == "Molly is a dog"
assert m.pet_name_species(molly) == "Molly is a dog"
- fred = m.Hamster('Fred')
+ fred = m.Hamster("Fred")
assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
assert m.dog_bark(molly) == "Woof!"
with pytest.raises(TypeError) as excinfo:
m.dog_bark(polly)
- assert msg(excinfo.value) == """
+ assert (
+ msg(excinfo.value)
+ == """
dog_bark(): incompatible function arguments. The following argument types are supported:
1. (arg0: m.class_.Dog) -> str
Invoked with: <m.class_.Pet object at 0>
"""
+ )
with pytest.raises(TypeError) as excinfo:
m.Chimera("lion", "goat")
assert "No constructor defined!" in str(excinfo.value)
+def test_inheritance_init(msg):
+
+ # Single base
+ class Python(m.Pet):
+ def __init__(self):
+ pass
+
+ with pytest.raises(TypeError) as exc_info:
+ Python()
+ expected = "m.class_.Pet.__init__() must be called when overriding __init__"
+ assert msg(exc_info.value) == expected
+
+ # Multiple bases
+ class RabbitHamster(m.Rabbit, m.Hamster):
+ def __init__(self):
+ m.Rabbit.__init__(self, "RabbitHamster")
+
+ with pytest.raises(TypeError) as exc_info:
+ RabbitHamster()
+ expected = "m.class_.Hamster.__init__() must be called when overriding __init__"
+ assert msg(exc_info.value) == expected
+
+
def test_automatic_upcasting():
assert type(m.return_class_1()).__name__ == "DerivedClass1"
assert type(m.return_class_2()).__name__ == "DerivedClass2"
@@ -126,13 +218,19 @@ def test_mismatched_holder():
with pytest.raises(RuntimeError) as excinfo:
m.mismatched_holder_1()
- assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default '
- 'holder type while its base ".*MismatchBase1" does', str(excinfo.value))
+ assert re.match(
+ 'generic_type: type ".*MismatchDerived1" does not have a non-default '
+ 'holder type while its base ".*MismatchBase1" does',
+ str(excinfo.value),
+ )
with pytest.raises(RuntimeError) as excinfo:
m.mismatched_holder_2()
- assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type '
- 'while its base ".*MismatchBase2" does not', str(excinfo.value))
+ assert re.match(
+ 'generic_type: type ".*MismatchDerived2" has a non-default holder type '
+ 'while its base ".*MismatchBase2" does not',
+ str(excinfo.value),
+ )
def test_override_static():
@@ -164,20 +262,20 @@ def test_operator_new_delete(capture):
a = m.HasOpNewDel()
b = m.HasOpNewDelSize()
d = m.HasOpNewDelBoth()
- assert capture == """
+ assert (
+ capture
+ == """
A new 8
B new 4
D new 32
"""
+ )
sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
with capture:
c = m.AliasedHasOpNewDelSize()
c2 = SubAliased()
- assert capture == (
- "C new " + sz_noalias + "\n" +
- "C new " + sz_alias + "\n"
- )
+ assert capture == ("C new " + sz_noalias + "\n" + "C new " + sz_alias + "\n")
with capture:
del a
@@ -186,21 +284,21 @@ def test_operator_new_delete(capture):
pytest.gc_collect()
del d
pytest.gc_collect()
- assert capture == """
+ assert (
+ capture
+ == """
A delete
B delete 4
D delete
"""
+ )
with capture:
del c
pytest.gc_collect()
del c2
pytest.gc_collect()
- assert capture == (
- "C delete " + sz_noalias + "\n" +
- "C delete " + sz_alias + "\n"
- )
+ assert capture == ("C delete " + sz_noalias + "\n" + "C delete " + sz_alias + "\n")
def test_bind_protected_functions():
@@ -235,7 +333,7 @@ def test_brace_initialization():
assert b.vec == [123, 456]
-@pytest.unsupported_on_pypy
+@pytest.mark.xfail("env.PYPY")
def test_class_refcount():
"""Instances must correctly increase/decrease the reference count of their types (#1029)"""
from sys import getrefcount
@@ -260,22 +358,109 @@ def test_reentrant_implicit_conversion_failure(msg):
# ensure that there is no runaway reentrant implicit conversion (#1035)
with pytest.raises(TypeError) as excinfo:
m.BogusImplicitConversion(0)
- assert msg(excinfo.value) == '''
+ assert (
+ msg(excinfo.value)
+ == """
__init__(): incompatible constructor arguments. The following argument types are supported:
1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
Invoked with: 0
- '''
+ """
+ )
def test_error_after_conversions():
with pytest.raises(TypeError) as exc_info:
m.test_error_after_conversions("hello")
assert str(exc_info.value).startswith(
- "Unable to convert function return value to a Python type!")
+ "Unable to convert function return value to a Python type!"
+ )
def test_aligned():
if hasattr(m, "Aligned"):
p = m.Aligned().ptr()
assert p % 1024 == 0
+
+
+# https://foss.heptapod.net/pypy/pypy/-/issues/2742
+@pytest.mark.xfail("env.PYPY")
+def test_final():
+ with pytest.raises(TypeError) as exc_info:
+
+ class PyFinalChild(m.IsFinal):
+ pass
+
+ assert str(exc_info.value).endswith("is not an acceptable base type")
+
+
+# https://foss.heptapod.net/pypy/pypy/-/issues/2742
+@pytest.mark.xfail("env.PYPY")
+def test_non_final_final():
+ with pytest.raises(TypeError) as exc_info:
+
+ class PyNonFinalFinalChild(m.IsNonFinalFinal):
+ pass
+
+ assert str(exc_info.value).endswith("is not an acceptable base type")
+
+
+# https://github.com/pybind/pybind11/issues/1878
+def test_exception_rvalue_abort():
+ with pytest.raises(RuntimeError):
+ m.PyPrintDestructor().throw_something()
+
+
+# https://github.com/pybind/pybind11/issues/1568
+def test_multiple_instances_with_same_pointer(capture):
+ n = 100
+ instances = [m.SamePointer() for _ in range(n)]
+ for i in range(n):
+ # We need to reuse the same allocated memory for with a different type,
+ # to ensure the bug in `deregister_instance_impl` is detected. Otherwise
+ # `Py_TYPE(self) == Py_TYPE(it->second)` will still succeed, even though
+ # the `instance` is already deleted.
+ instances[i] = m.Empty()
+ # No assert: if this does not trigger the error
+ # pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
+ # and just completes without crashing, we're good.
+
+
+# https://github.com/pybind/pybind11/issues/1624
+def test_base_and_derived_nested_scope():
+ assert issubclass(m.DerivedWithNested, m.BaseWithNested)
+ assert m.BaseWithNested.Nested != m.DerivedWithNested.Nested
+ assert m.BaseWithNested.Nested.get_name() == "BaseWithNested::Nested"
+ assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested"
+
+
+def test_register_duplicate_class():
+ import types
+
+ module_scope = types.ModuleType("module_scope")
+ with pytest.raises(RuntimeError) as exc_info:
+ m.register_duplicate_class_name(module_scope)
+ expected = (
+ 'generic_type: cannot initialize type "Duplicate": '
+ "an object with that name is already defined"
+ )
+ assert str(exc_info.value) == expected
+ with pytest.raises(RuntimeError) as exc_info:
+ m.register_duplicate_class_type(module_scope)
+ expected = 'generic_type: type "YetAnotherDuplicate" is already registered!'
+ assert str(exc_info.value) == expected
+
+ class ClassScope:
+ pass
+
+ with pytest.raises(RuntimeError) as exc_info:
+ m.register_duplicate_nested_class_name(ClassScope)
+ expected = (
+ 'generic_type: cannot initialize type "DuplicateNested": '
+ "an object with that name is already defined"
+ )
+ assert str(exc_info.value) == expected
+ with pytest.raises(RuntimeError) as exc_info:
+ m.register_duplicate_nested_class_type(ClassScope)
+ expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!'
+ assert str(exc_info.value) == expected