Skip to content
Merged
76 changes: 76 additions & 0 deletions Lib/test/test_gc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,82 @@ def test_something(self):
""")
assert_python_ok("-c", source)

def test_do_not_cleanup_type_subclasses_before_finalization(self):
# 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
# atribute. 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)

def test_type_weakref_with_callback_should_be_none(self):
# This test checks that weakrefs for types with callbacks
# are cleared before the finalizer is called
code = """
import weakref
def test():
class Class:
def __init__(self):
self._self = self
self._z = weakref.ref(Class, lambda x: None)

def __del__(self):
assert self._z() is None, "Type weakref is not None"

Class()

test()
"""
_, _, stderr = assert_python_ok("-c", code)
assert b"Type weakref is not None" not in stderr

def test_type_weakref_without_callback_should_be_not_none(self):
# This test checks that weakrefs for types without callbacks
# are cleared after the finalizer is called
code = """
import weakref
def test():
class Class:
def __init__(self):
self._self = self
self._x = weakref.ref(self)
self._z = weakref.ref(Class)

def __del__(self):
assert self._x() is None, "Instance weakref is not None"
assert self._z() is Class, "Type weakref is not Class"

Class()

test()
"""
_, _, stderr = assert_python_ok("-c", code)
assert b"Instance weakref is not None" not in stderr
assert b"Type weakref is not Class" not in stderr


class IncrementalGCTests(unittest.TestCase):
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
Expand Down
Loading