mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-21 16:09:22 +00:00
Add is_redundant_value_and_holder()
and use to avoid forcing __init__
overrides when they are not needed.
This commit is contained in:
parent
7c7d78d87f
commit
d7088364f9
@ -180,6 +180,17 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
|
|||||||
return PyType_Type.tp_getattro(obj, name);
|
return PyType_Type.tp_getattro(obj, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
||||||
|
inline bool is_redundant_value_and_holder(const std::vector<type_info *> &bases,
|
||||||
|
std::size_t ix_base) {
|
||||||
|
for (std::size_t i = 0; i < ix_base; i++) {
|
||||||
|
if (PyType_IsSubtype(bases[i]->type, bases[ix_base]->type) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
||||||
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
||||||
|
|
||||||
@ -189,18 +200,20 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This must be a pybind11 instance
|
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
|
||||||
|
|
||||||
// Ensure that the base __init__ function(s) were called
|
// Ensure that the base __init__ function(s) were called
|
||||||
for (const auto &vh : values_and_holders(instance)) {
|
const auto &bases = all_type_info((PyTypeObject *) type);
|
||||||
if (!vh.holder_constructed()) {
|
values_and_holders vhs(reinterpret_cast<detail::instance *>(self));
|
||||||
|
assert(bases.size() == vhs.size());
|
||||||
|
std::size_t ix_base = 0;
|
||||||
|
for (const auto &vh : vhs) {
|
||||||
|
if (!vh.holder_constructed() && !is_redundant_value_and_holder(bases, ix_base)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s.__init__() must be called when overriding __init__",
|
"%.200s.__init__() must be called when overriding __init__",
|
||||||
get_fully_qualified_tp_name(vh.type->type).c_str());
|
get_fully_qualified_tp_name(vh.type->type).c_str());
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
ix_base++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -102,6 +102,7 @@ public:
|
|||||||
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
||||||
all_type_info_get_cache(PyTypeObject *type);
|
all_type_info_get_cache(PyTypeObject *type);
|
||||||
|
|
||||||
|
// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
|
||||||
inline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases,
|
inline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases,
|
||||||
type_info *addl_base) {
|
type_info *addl_base) {
|
||||||
for (auto it = bases.begin(); it != bases.end(); it++) {
|
for (auto it = bases.begin(); it != bases.end(); it++) {
|
||||||
|
@ -8,10 +8,8 @@ class PC(m.CppBase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PPCCInit(PC, m.CppDrvd):
|
class PPCC(PC, m.CppDrvd):
|
||||||
def __init__(self, value):
|
pass
|
||||||
PC.__init__(self, value)
|
|
||||||
m.CppDrvd.__init__(self, value + 1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_PC():
|
def test_PC():
|
||||||
@ -21,14 +19,14 @@ def test_PC():
|
|||||||
assert d.get_base_value() == 13
|
assert d.get_base_value() == 13
|
||||||
|
|
||||||
|
|
||||||
def test_PPCCInit():
|
def test_PPCC():
|
||||||
d = PPCCInit(11)
|
d = PPCC(11)
|
||||||
assert d.get_drvd_value() == 36
|
assert d.get_drvd_value() == 33
|
||||||
d.reset_drvd_value(55)
|
d.reset_drvd_value(55)
|
||||||
assert d.get_drvd_value() == 55
|
assert d.get_drvd_value() == 55
|
||||||
|
|
||||||
assert d.get_base_value() == 12
|
assert d.get_base_value() == 11
|
||||||
assert d.get_base_value_from_drvd() == 12
|
assert d.get_base_value_from_drvd() == 11
|
||||||
d.reset_base_value(20)
|
d.reset_base_value(20)
|
||||||
assert d.get_base_value() == 20
|
assert d.get_base_value() == 20
|
||||||
assert d.get_base_value_from_drvd() == 20
|
assert d.get_base_value_from_drvd() == 20
|
||||||
|
Loading…
Reference in New Issue
Block a user