From 6253f04966bd41767718498f5f195ddc1089a3de Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 19 Jul 2026 10:45:51 +0200 Subject: [PATCH] Fixed issue #2396 (support weak refs in Python) --- src/pya/pya/pyaCallables.cc | 5 +++++ src/pya/pya/pyaModule.cc | 5 +++++ testdata/python/basic.py | 15 +++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/pya/pya/pyaCallables.cc b/src/pya/pya/pyaCallables.cc index 6cf02316b..8e8108ca9 100644 --- a/src/pya/pya/pyaCallables.cc +++ b/src/pya/pya/pyaCallables.cc @@ -43,6 +43,11 @@ namespace pya void pya_object_deallocate (PyObject *self) { + // Clear weak refs - needed for signal binding and other purposes +#if PY_VERSION_HEX > 0x03020000 + PyObject_ClearWeakRefs (self); +#endif + // This avoids an assertion in debug builds (Python, gcmodule.c - update_refs). // In short, the GC expects not to see objects with refcount 0 and asserts. // However, due to triggering of signals or similar, the destructor call below diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index b895f6a01..14a275c58 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -337,6 +337,11 @@ public: #if PY_VERSION_HEX >= 0x030D0000 // crashes with this option set type->tp_flags &= ~Py_TPFLAGS_INLINE_VALUES; +#endif +#if PY_VERSION_HEX < 0x03000000 + type->tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS; + type->tp_weaklistoffset = type->tp_basicsize; + type->tp_basicsize += sizeof (PyObject *); #endif type->tp_basicsize += sizeof (PYAObjectBase); type->tp_init = &pya_object_init; diff --git a/testdata/python/basic.py b/testdata/python/basic.py index 4b13e65f2..61a0f6db7 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -22,6 +22,7 @@ import os import sys import gc import copy +import weakref # Set this to True to disable some tests involving exceptions leak_check = "TEST_LEAK_CHECK" in os.environ @@ -3352,6 +3353,20 @@ class BasicTest(unittest.TestCase): self.assertEqual(bc.str(), "xyz") self.assertEqual(bnc.str(), "xyz") + # weak refs + def test_94(self): + + b = pya.B() + b.set_str("abc") + + r = weakref.ref(b) + self.assertEqual(r() is None, False) + self.assertEqual(r().str(), "abc") + + b = None + self.assertEqual(r() is None, True) + + # run unit tests if __name__ == '__main__': suite = unittest.TestSuite()