mirror of https://github.com/python/cpython
gh-93353: Add test.support.late_deletion() (#93774)
This commit is contained in:
parent
df22eec421
commit
7b2064b4b9
|
@ -2213,3 +2213,40 @@ def requires_venv_with_pip():
|
|||
# True if Python is built with the Py_DEBUG macro defined: if
|
||||
# Python is built in debug mode (./configure --with-pydebug).
|
||||
Py_DEBUG = hasattr(sys, 'gettotalrefcount')
|
||||
|
||||
|
||||
def late_deletion(obj):
|
||||
"""
|
||||
Keep a Python alive as long as possible.
|
||||
|
||||
Create a reference cycle and store the cycle in an object deleted late in
|
||||
Python finalization. Try to keep the object alive until the very last
|
||||
garbage collection.
|
||||
|
||||
The function keeps a strong reference by design. It should be called in a
|
||||
subprocess to not mark a test as "leaking a reference".
|
||||
"""
|
||||
|
||||
# Late CPython finalization:
|
||||
# - finalize_interp_clear()
|
||||
# - _PyInterpreterState_Clear(): Clear PyInterpreterState members
|
||||
# (ex: codec_search_path, before_forkers)
|
||||
# - clear os.register_at_fork() callbacks
|
||||
# - clear codecs.register() callbacks
|
||||
|
||||
ref_cycle = [obj]
|
||||
ref_cycle.append(ref_cycle)
|
||||
|
||||
# Store a reference in PyInterpreterState.codec_search_path
|
||||
import codecs
|
||||
def search_func(encoding):
|
||||
return None
|
||||
search_func.reference = ref_cycle
|
||||
codecs.register(search_func)
|
||||
|
||||
if hasattr(os, 'register_at_fork'):
|
||||
# Store a reference in PyInterpreterState.before_forkers
|
||||
def atfork_func():
|
||||
pass
|
||||
atfork_func.reference = ref_cycle
|
||||
os.register_at_fork(before=atfork_func)
|
||||
|
|
|
@ -1440,19 +1440,13 @@ class PythonFinalizationTests(unittest.TestCase):
|
|||
code = textwrap.dedent("""
|
||||
import ast
|
||||
import codecs
|
||||
from test import support
|
||||
|
||||
# Small AST tree to keep their AST types alive
|
||||
tree = ast.parse("def f(x, y): return 2*x-y")
|
||||
x = [tree]
|
||||
x.append(x)
|
||||
|
||||
# Put the cycle somewhere to survive until the last GC collection.
|
||||
# Codec search functions are only cleared at the end of
|
||||
# interpreter_clear().
|
||||
def search_func(encoding):
|
||||
return None
|
||||
search_func.a = x
|
||||
codecs.register(search_func)
|
||||
# Store the tree somewhere to survive until the last GC collection
|
||||
support.late_deletion(tree)
|
||||
""")
|
||||
assert_python_ok("-c", code)
|
||||
|
||||
|
|
Loading…
Reference in New Issue