mirror of
https://github.com/pybind/pybind11.git
synced 2026-03-14 20:27:47 +00:00
Make all classes with the same instance size derive from a common base
In order to fully satisfy Python's inheritance type layout requirements, all types should have a common 'solid' base. A solid base is one which has the same instance size as the derived type (not counting the space required for the optional `dict_ptr` and `weakrefs_ptr`). Thus, `object` does not qualify as a solid base for pybind11 types and this can lead to issues with multiple inheritance. To get around this, new base types are created: one per unique instance size. There is going to be very few of these bases. They ensure Python's MRO checks will pass when multiple bases are involved.
This commit is contained in:
committed by
Wenzel Jakob
parent
c91f8bd627
commit
08cbe8dfed
@@ -1,3 +1,6 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_multiple_inheritance_cpp():
|
||||
from pybind11_tests import MIType
|
||||
|
||||
@@ -49,6 +52,17 @@ def test_multiple_inheritance_mix2():
|
||||
assert mt.bar() == 4
|
||||
|
||||
|
||||
def test_multiple_inheritance_error():
|
||||
"""Inheriting from multiple C++ bases in Python is not supported"""
|
||||
from pybind11_tests import Base1, Base2
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
# noinspection PyUnusedLocal
|
||||
class MI(Base1, Base2):
|
||||
pass
|
||||
assert "Can't inherit from multiple C++ classes in Python" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_multiple_inheritance_virtbase():
|
||||
from pybind11_tests import Base12a, bar_base2a, bar_base2a_sharedptr
|
||||
|
||||
@@ -60,3 +74,38 @@ def test_multiple_inheritance_virtbase():
|
||||
assert mt.bar() == 4
|
||||
assert bar_base2a(mt) == 4
|
||||
assert bar_base2a_sharedptr(mt) == 4
|
||||
|
||||
|
||||
def test_mi_static_properties():
|
||||
"""Mixing bases with and without static properties should be possible
|
||||
and the result should be independent of base definition order"""
|
||||
from pybind11_tests import mi
|
||||
|
||||
for d in (mi.VanillaStaticMix1(), mi.VanillaStaticMix2()):
|
||||
assert d.vanilla() == "Vanilla"
|
||||
assert d.static_func1() == "WithStatic1"
|
||||
assert d.static_func2() == "WithStatic2"
|
||||
assert d.static_func() == d.__class__.__name__
|
||||
|
||||
mi.WithStatic1.static_value1 = 1
|
||||
mi.WithStatic2.static_value2 = 2
|
||||
assert d.static_value1 == 1
|
||||
assert d.static_value2 == 2
|
||||
assert d.static_value == 12
|
||||
|
||||
d.static_value1 = 0
|
||||
assert d.static_value1 == 0
|
||||
d.static_value2 = 0
|
||||
assert d.static_value2 == 0
|
||||
d.static_value = 0
|
||||
assert d.static_value == 0
|
||||
|
||||
|
||||
@pytest.unsupported_on_pypy
|
||||
def test_mi_dynamic_attributes():
|
||||
"""Mixing bases with and without dynamic attribute support"""
|
||||
from pybind11_tests import mi
|
||||
|
||||
for d in (mi.VanillaDictMix1(), mi.VanillaDictMix2()):
|
||||
d.dynamic = 1
|
||||
assert d.dynamic == 1
|
||||
|
||||
Reference in New Issue
Block a user