@@ -507,6 +507,68 @@ def test_datetime_reset_strptime(self):
507507 out , err = self .run_embedded_interpreter ("test_repeated_init_exec" , code )
508508 self .assertEqual (out , '20000101\n ' * INIT_LOOPS )
509509
510+ @threading_helper .requires_working_threading ()
511+ @unittest .skipUnless (_testinternalcapi , "requires _testinternalcapi" )
512+ def test_warnings_at_shutdown (self ):
513+ import_helper .import_module ('_testcapi' )
514+ code = textwrap .dedent ('''
515+ import _testinternalcapi
516+ import _warnings
517+ import threading
518+ import warnings
519+ from test import support
520+
521+ warnings.simplefilter('ignore')
522+ local = threading.local()
523+ ready = threading.Event()
524+
525+ class WarnOnDelete:
526+ def __del__(self):
527+ warnings.warn('during shutdown', ResourceWarning)
528+ if not ready.is_set():
529+ # The finalizing thread still owns all three levels.
530+ for _ in range(3):
531+ _warnings._release_lock()
532+ try:
533+ _warnings._release_lock()
534+ except RuntimeError:
535+ pass
536+ else:
537+ raise AssertionError('unexpected recursion depth')
538+ print('finalized')
539+
540+ def worker():
541+ local.obj = WarnOnDelete()
542+ _warnings._acquire_lock()
543+ ready.set()
544+ threading.Event().wait()
545+
546+ for _ in range(3):
547+ _warnings._acquire_lock()
548+ threading.Thread(target=worker, daemon=True).start()
549+ for _ in support.sleeping_retry(4):
550+ if _testinternalcapi.warnings_lock_has_waiters():
551+ break
552+ ''' )
553+ release = textwrap .dedent ('''
554+ for _ in range(3):
555+ _warnings._release_lock()
556+ assert ready.wait(4), 'lock not acquired'
557+ ''' )
558+ subinterp = (
559+ 'from test import support\n '
560+ f'assert support.run_in_subinterp({ code + release !r} ) == 0'
561+ )
562+ # Cover Py_EndInterpreter(), then shut down with a waiter. Reuse the
563+ # main interpreter's mutex and shut down with a daemon owning it.
564+ # All three thread-local finalizers must warn.
565+ out , err = self .run_embedded_interpreter (
566+ "test_repeated_init_exec" , subinterp + '\n ' + code , code + release ,
567+ env = remove_python_envvars (),
568+ timeout = 10 )
569+ self .assertEqual (out , 'finalized\n ' * 3 )
570+ self .assertEqual (err , '--- Loop #1 ---\n --- Loop #2 ---\n ' )
571+
510572 def test_static_types_inherited_slots (self ):
511573 script = textwrap .dedent ("""
512574 import test.support
0 commit comments