Handle result from PyObject_VisitManagedDict (#6032)

* Handle result from PyObject_VisitManagedDict

* add unit test

* style: pre-commit fixes

* use different variable name

This avoids a warning on msvc about Py_Visit shadowing the vret variable.

* skip test_get_referrers on unsupported runtimes

The managed-dict referrer check is only known to work on CPython 3.13.13+ and 3.14.4+, while earlier releases and non-CPython interpreters can report different traversal behavior.

Made-with: Cursor

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
This commit is contained in:
Max Bachmann
2026-04-12 05:02:27 +02:00
committed by GitHub
parent 4158dcfe7d
commit 0db7f72dc2
3 changed files with 28 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import gc
import sys
from unittest import mock
@@ -18,6 +19,13 @@ def refcount_immortal(ob: object) -> int:
return sys.getrefcount(ob)
MANAGED_DICT_GET_REFERRERS_SUPPORTED = (
env.CPYTHON
and sys.version_info >= (3, 13, 13)
and (sys.version_info < (3, 14) or sys.version_info >= (3, 14, 4))
)
def test_obj_class_name():
expected_name = "UserType" if env.PYPY else "pybind11_tests.UserType"
assert m.obj_class_name(UserType(1)) == expected_name
@@ -45,6 +53,16 @@ def test_instance(msg):
assert cstats.alive() == 0
@pytest.mark.skipif(
not MANAGED_DICT_GET_REFERRERS_SUPPORTED,
reason="Requires CPython 3.13.13+ or 3.14.4+ managed dict traversal support",
)
def test_get_referrers():
instance = m.DynamicAttr()
instance.a = "test"
assert instance in gc.get_referrers(instance.__dict__)
def test_instance_new():
instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)