Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: test_factory_constructors.py failure triggered by test_register_duplicate_class #2564

Merged
merged 7 commits into from
Oct 16, 2020
40 changes: 40 additions & 0 deletions include/pybind11/detail/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,44 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
return self;
}

/// Cleanup the type-info for a pybind11-registered type.
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
auto *type = (PyTypeObject *) obj;
auto &internals = get_internals();

// A pybind11-registered type will:
// 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() &&
found_type->second.size() == 1 &&
found_type->second[0]->type == type) {

auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype);
internals.direct_conversions.erase(tindex);

if (tinfo->module_local)
registered_local_types_cpp().erase(tindex);
else
internals.registered_types_cpp.erase(tindex);
internals.registered_types_py.erase(tinfo->type);

// Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last; ) {
if (it->first == (PyObject *) tinfo->type)
it = cache.erase(it);
else
++it;
}

delete tinfo;
}

PyType_Type.tp_dealloc(obj);
}

/** This metaclass is assigned by default to all pybind11 types and is required in order
for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */
Expand Down Expand Up @@ -225,6 +263,8 @@ inline PyTypeObject* make_default_metaclass() {
type->tp_getattro = pybind11_meta_getattro;
#endif

type->tp_dealloc = pybind11_meta_dealloc;

if (PyType_Ready(type) < 0)
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");

Expand Down
1 change: 0 additions & 1 deletion tests/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,6 @@ def test_base_and_derived_nested_scope():
assert m.DerivedWithNested.Nested.get_name() == "DerivedWithNested::Nested"


@pytest.mark.skip("See https://github.com/pybind/pybind11/pull/2564")
def test_register_duplicate_class():
import types
module_scope = types.ModuleType("module_scope")
Expand Down