mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-18 06:30:54 +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);
|
||||
}
|
||||
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
|
||||
// This must be a pybind11 instance
|
||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
||||
|
||||
// Ensure that the base __init__ function(s) were called
|
||||
for (const auto &vh : values_and_holders(instance)) {
|
||||
if (!vh.holder_constructed()) {
|
||||
const auto &bases = all_type_info((PyTypeObject *) type);
|
||||
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,
|
||||
"%.200s.__init__() must be called when overriding __init__",
|
||||
get_fully_qualified_tp_name(vh.type->type).c_str());
|
||||
Py_DECREF(self);
|
||||
return nullptr;
|
||||
}
|
||||
ix_base++;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -102,6 +102,7 @@ public:
|
||||
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
|
||||
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,
|
||||
type_info *addl_base) {
|
||||
for (auto it = bases.begin(); it != bases.end(); it++) {
|
||||
|
@ -8,10 +8,8 @@ class PC(m.CppBase):
|
||||
pass
|
||||
|
||||
|
||||
class PPCCInit(PC, m.CppDrvd):
|
||||
def __init__(self, value):
|
||||
PC.__init__(self, value)
|
||||
m.CppDrvd.__init__(self, value + 1)
|
||||
class PPCC(PC, m.CppDrvd):
|
||||
pass
|
||||
|
||||
|
||||
def test_PC():
|
||||
@ -21,14 +19,14 @@ def test_PC():
|
||||
assert d.get_base_value() == 13
|
||||
|
||||
|
||||
def test_PPCCInit():
|
||||
d = PPCCInit(11)
|
||||
assert d.get_drvd_value() == 36
|
||||
def test_PPCC():
|
||||
d = PPCC(11)
|
||||
assert d.get_drvd_value() == 33
|
||||
d.reset_drvd_value(55)
|
||||
assert d.get_drvd_value() == 55
|
||||
|
||||
assert d.get_base_value() == 12
|
||||
assert d.get_base_value_from_drvd() == 12
|
||||
assert d.get_base_value() == 11
|
||||
assert d.get_base_value_from_drvd() == 11
|
||||
d.reset_base_value(20)
|
||||
assert d.get_base_value() == 20
|
||||
assert d.get_base_value_from_drvd() == 20
|
||||
|
Loading…
Reference in New Issue
Block a user