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
|
# True if Python is built with the Py_DEBUG macro defined: if
|
||||||
# Python is built in debug mode (./configure --with-pydebug).
|
# Python is built in debug mode (./configure --with-pydebug).
|
||||||
Py_DEBUG = hasattr(sys, 'gettotalrefcount')
|
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("""
|
code = textwrap.dedent("""
|
||||||
import ast
|
import ast
|
||||||
import codecs
|
import codecs
|
||||||
|
from test import support
|
||||||
|
|
||||||
# Small AST tree to keep their AST types alive
|
# Small AST tree to keep their AST types alive
|
||||||
tree = ast.parse("def f(x, y): return 2*x-y")
|
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.
|
# Store the tree somewhere to survive until the last GC collection
|
||||||
# Codec search functions are only cleared at the end of
|
support.late_deletion(tree)
|
||||||
# interpreter_clear().
|
|
||||||
def search_func(encoding):
|
|
||||||
return None
|
|
||||||
search_func.a = x
|
|
||||||
codecs.register(search_func)
|
|
||||||
""")
|
""")
|
||||||
assert_python_ok("-c", code)
|
assert_python_ok("-c", code)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue