mirror of
https://github.com/python/cpython.git
synced 2026-02-13 19:04:37 +00:00
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+fxeqxmulfx@users.noreply.github.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org> Co-authored-by: Neil Schemenauer <nas-github@arctrix.com>
This commit is contained in:
parent
37b5a0d671
commit
25518f51dc
2 changed files with 57 additions and 0 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue