https://github.com/python/cpython/commit/25518f51dc9fd3ffe4f8ae5d53baa3728936be2b commit: 25518f51dc9fd3ffe4f8ae5d53baa3728936be2b branch: main author: Sergey Miryanov <sergey.mirya...@gmail.com> committer: nascheme <nas-git...@arctrix.com> date: 2025-08-07T17:45:33-07:00 summary:
GH-135552: Add tests to check weakref clearing (GH-136304) These are tests to ensure behaviour introduced by GH-136189 is working as expected. Co-authored-by: Mikhail Borisov <43937008+fxeqxmu...@users.noreply.github.com> Co-authored-by: Kumar Aditya <kumaradi...@python.org> Co-authored-by: Neil Schemenauer <nas-git...@arctrix.com> files: M Lib/test/test_gc.py M Lib/test/test_weakref.py diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index 3ec211531c4c70..7c9adf3049a131 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1155,6 +1155,37 @@ def test_something(self): """) assert_python_ok("-c", source) + def test_do_not_cleanup_type_subclasses_before_finalization(self): + # See https://github.com/python/cpython/issues/135552 + # If we cleanup weakrefs for tp_subclasses before calling + # the finalizer (__del__) then the line `fail = BaseNode.next.next` + # should fail because we are trying to access a subclass + # attribute. But subclass type cache was not properly invalidated. + code = """ + class BaseNode: + def __del__(self): + BaseNode.next = BaseNode.next.next + fail = BaseNode.next.next + + class Node(BaseNode): + pass + + BaseNode.next = Node() + BaseNode.next.next = Node() + """ + # this test checks garbage collection while interp + # finalization + assert_python_ok("-c", textwrap.dedent(code)) + + code_inside_function = textwrap.dedent(F""" + def test(): + {textwrap.indent(code, ' ')} + + test() + """) + # this test checks regular garbage collection + assert_python_ok("-c", code_inside_function) + class IncrementalGCTests(unittest.TestCase): @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 4c7c900eb56ae1..47f6b46061ac30 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1044,6 +1044,32 @@ def callback(obj): stderr = res.err.decode("ascii", "backslashreplace") self.assertNotRegex(stderr, "_Py_Dealloc: Deallocator of type 'TestObj'") + def test_clearing_weakrefs_in_gc(self): + # This test checks that when finalizers are called: + # 1. weakrefs with callbacks have been cleared + # 2. weakrefs without callbacks have not been cleared + errors = [] + def test(): + class Class: + def __init__(self): + self._self = self + self.wr1 = weakref.ref(Class, lambda x: None) + self.wr2 = weakref.ref(Class) + + def __del__(self): + # we can't use assert* here, because gc will swallow + # exceptions + if self.wr1() is not None: + errors.append("weakref with callback as cleared") + if self.wr2() is not Class: + errors.append("weakref without callback was cleared") + + Class() + + test() + gc.collect() + self.assertEqual(errors, []) + class SubclassableWeakrefTestCase(TestBase): _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: arch...@mail-archive.com