mirror of
https://github.com/pybind/pybind11.git
synced 2026-04-19 22:39:09 +00:00
Revert internals destruction and add test for internals recreation (#5972)
* Bump internals version * Prevent internals destruction before all pybind11 types are destroyed * Use Py_XINCREF and Py_XDECREF * Hold GIL before decref * Use weakrefs * Remove unused code * Move code location * Move code location * Move code location * Try add tests * Fix PYTHONPATH * Fix PYTHONPATH * Skip tests for subprocess * Revert to leak internals * Revert to leak internals * Revert "Revert to leak internals" This reverts commitc5ec1cf886. This reverts commit72c2e0aa9b. * Revert internals version bump * Reapply to leak internals This reverts commit8f25a254e8. * Add re-entrancy detection for internals creation Prevent re-creation of internals after destruction during interpreter shutdown. If pybind11 code runs after internals have been destroyed, fail early with a clear error message instead of silently creating new empty internals that would cause type lookup failures. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix C++11/C++14 support * Add lock under multiple interpreters * Try fix tests * Try fix tests * Try fix tests * Update comments and assertion messages * Update comments and assertion messages * Update comments * Update lock scope * Use original pointer type for Windows * Change hard error to warning * Update lock scope * Update lock scope to resolve deadlock * Remove scope release of GIL * Update comments * Lock pp on reset * Mark content created after assignment * Update comments * Simplify implementation * Update lock scope when delete unique_ptr --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1381,11 +1381,22 @@ You can do that using ``py::custom_type_setup``:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
struct OwnsPythonObjects {
|
||||
py::object value = py::none();
|
||||
struct ContainerOwnsPythonObjects {
|
||||
std::vector<py::object> list;
|
||||
|
||||
void append(const py::object &obj) { list.emplace_back(obj); }
|
||||
py::object at(py::ssize_t index) const {
|
||||
if (index >= size() || index < 0) {
|
||||
throw py::index_error("Index out of range");
|
||||
}
|
||||
return list.at(py::size_t(index));
|
||||
}
|
||||
py::ssize_t size() const { return py::ssize_t_cast(list.size()); }
|
||||
void clear() { list.clear(); }
|
||||
};
|
||||
py::class_<OwnsPythonObjects> cls(
|
||||
m, "OwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) {
|
||||
|
||||
py::class_<ContainerOwnsPythonObjects> cls(
|
||||
m, "ContainerOwnsPythonObjects", py::custom_type_setup([](PyHeapTypeObject *heap_type) {
|
||||
auto *type = &heap_type->ht_type;
|
||||
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||
type->tp_traverse = [](PyObject *self_base, visitproc visit, void *arg) {
|
||||
@@ -1394,20 +1405,28 @@ You can do that using ``py::custom_type_setup``:
|
||||
Py_VISIT(Py_TYPE(self_base));
|
||||
#endif
|
||||
if (py::detail::is_holder_constructed(self_base)) {
|
||||
auto &self = py::cast<OwnsPythonObjects&>(py::handle(self_base));
|
||||
Py_VISIT(self.value.ptr());
|
||||
auto &self = py::cast<ContainerOwnsPythonObjects &>(py::handle(self_base));
|
||||
for (auto &item : self.list) {
|
||||
Py_VISIT(item.ptr());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
type->tp_clear = [](PyObject *self_base) {
|
||||
if (py::detail::is_holder_constructed(self_base)) {
|
||||
auto &self = py::cast<OwnsPythonObjects&>(py::handle(self_base));
|
||||
self.value = py::none();
|
||||
auto &self = py::cast<ContainerOwnsPythonObjects &>(py::handle(self_base));
|
||||
for (auto &item : self.list) {
|
||||
Py_CLEAR(item.ptr());
|
||||
}
|
||||
self.list.clear();
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}));
|
||||
cls.def(py::init<>());
|
||||
cls.def_readwrite("value", &OwnsPythonObjects::value);
|
||||
cls.def("append", &ContainerOwnsPythonObjects::append);
|
||||
cls.def("at", &ContainerOwnsPythonObjects::at);
|
||||
cls.def("size", &ContainerOwnsPythonObjects::size);
|
||||
cls.def("clear", &ContainerOwnsPythonObjects::clear);
|
||||
|
||||
.. versionadded:: 2.8
|
||||
|
||||
Reference in New Issue
Block a user