@@ -2213,3 +2213,40 @@ def requires_venv_with_pip():
22132213# True if Python is built with the Py_DEBUG macro defined: if
22142214# Python is built in debug mode (./configure --with-pydebug).
22152215Py_DEBUG = hasattr (sys , 'gettotalrefcount' )
2216+
2217+
2218+ def late_deletion (obj ):
2219+ """
2220+ Keep a Python alive as long as possible.
2221+
2222+ Create a reference cycle and store the cycle in an object deleted late in
2223+ Python finalization. Try to keep the object alive until the very last
2224+ garbage collection.
2225+
2226+ The function keeps a strong reference by design. It should be called in a
2227+ subprocess to not mark a test as "leaking a reference".
2228+ """
2229+
2230+ # Late CPython finalization:
2231+ # - finalize_interp_clear()
2232+ # - _PyInterpreterState_Clear(): Clear PyInterpreterState members
2233+ # (ex: codec_search_path, before_forkers)
2234+ # - clear os.register_at_fork() callbacks
2235+ # - clear codecs.register() callbacks
2236+
2237+ ref_cycle = [obj ]
2238+ ref_cycle .append (ref_cycle )
2239+
2240+ # Store a reference in PyInterpreterState.codec_search_path
2241+ import codecs
2242+ def search_func (encoding ):
2243+ return None
2244+ search_func .reference = ref_cycle
2245+ codecs .register (search_func )
2246+
2247+ if hasattr (os , 'register_at_fork' ):
2248+ # Store a reference in PyInterpreterState.before_forkers
2249+ def atfork_func ():
2250+ pass
2251+ atfork_func .reference = ref_cycle
2252+ os .register_at_fork (before = atfork_func )
0 commit comments