Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion include/pybind11/detail/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,10 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject_VisitManagedDict(self, visit, arg);
int vret = PyObject_VisitManagedDict(self, visit, arg);
if (vret) {
return vret;
}
#else
PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_VISIT(dict);
Expand Down
6 changes: 6 additions & 0 deletions tests/test_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ TEST_SUBMODULE(class_, m) {
~NoConstructorNew() { print_destroyed(this); }
};

struct DynamicAttr {
DynamicAttr() = default;
};

py::class_<NoConstructor>(m, "NoConstructor")
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");

Expand All @@ -112,6 +116,8 @@ TEST_SUBMODULE(class_, m) {
.def_static("__new__",
[](const py::object &) { return NoConstructorNew::new_instance(); });

py::class_<DynamicAttr>(m, "DynamicAttr", py::dynamic_attr()).def(py::init<>());

// test_pass_unique_ptr
struct ToBeHeldByUniquePtr {};
py::class_<ToBeHeldByUniquePtr, std::unique_ptr<ToBeHeldByUniquePtr>>(m, "ToBeHeldByUniquePtr")
Expand Down
7 changes: 7 additions & 0 deletions tests/test_class.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import gc
import sys
from unittest import mock

Expand Down Expand Up @@ -45,6 +46,12 @@
assert cstats.alive() == 0


def test_get_referrers():
instance = m.DynamicAttr()
instance.a = "test"
assert instance in gc.get_referrers(instance.__dict__)

Check failure on line 52 in tests/test_class.py

View workflow job for this annotation

GitHub Actions / 🐍 (ubuntu-latest, graalpy-24.2, -DCMAKE_CXX_STANDARD=20) / 🧪

test_get_referrers AssertionError: assert <pybind11_tests.class_.DynamicAttr object at 0xe46960d> in [] + where [] = <built-in function get_referrers>({'a': 'test'}) + where <built-in function get_referrers> = gc.get_referrers + and {'a': 'test'} = <pybind11_tests.class_.DynamicAttr object at 0xe46960d>.__dict__

Check failure on line 52 in tests/test_class.py

View workflow job for this annotation

GitHub Actions / 🐍 (ubuntu-latest, 3.14, -DCMAKE_CXX_STANDARD=14) / 🧪

test_get_referrers AssertionError: assert <pybind11_tests.class_.DynamicAttr object at 0x7f8af02d5190> in [] + where [] = <built-in function get_referrers>({'a': 'test'}) + where <built-in function get_referrers> = gc.get_referrers + and {'a': 'test'} = <pybind11_tests.class_.DynamicAttr object at 0x7f8af02d5190>.__dict__

Check failure on line 52 in tests/test_class.py

View workflow job for this annotation

GitHub Actions / 🐍 (ubuntu-latest, graalpy-24.1) / 🧪

test_get_referrers AssertionError: assert <pybind11_tests.class_.DynamicAttr object at 0x766a0505> in [] + where [] = <built-in function get_referrers>({'a': 'test'}) + where <built-in function get_referrers> = gc.get_referrers + and {'a': 'test'} = <pybind11_tests.class_.DynamicAttr object at 0x766a0505>.__dict__


def test_instance_new():
instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)

Expand Down
Loading