]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-135427: Fix DeprecationWarning for os.fork when run in threads with -Werror (GH...
authorRani Pinchuk <33353578+rani-pinchuk@users.noreply.github.com>
Tue, 26 Aug 2025 13:33:21 +0000 (15:33 +0200)
committerGitHub <noreply@github.com>
Tue, 26 Aug 2025 13:33:21 +0000 (15:33 +0200)
Don't ignore errors raised by `PyErr_WarnFormat` in `warn_about_fork_with_threads`
Instead, ignore the warnings in all test code that forks. (That's a lot of functions.)

In `test_support`, make `ignore_warnings` a context manager (as well as decorator),
and add a `message` argument to it.
Also add a `ignore_fork_in_thread_deprecation_warnings` helper for the deadlock-in-fork
warning.

27 files changed:
Lib/test/_test_multiprocessing.py
Lib/test/support/warnings_helper.py
Lib/test/test_asyncio/test_unix_events.py
Lib/test/test_builtin.py
Lib/test/test_concurrent_futures/executor.py
Lib/test/test_concurrent_futures/test_as_completed.py
Lib/test/test_concurrent_futures/test_deadlock.py
Lib/test/test_concurrent_futures/test_init.py
Lib/test/test_concurrent_futures/test_process_pool.py
Lib/test/test_concurrent_futures/test_shutdown.py
Lib/test/test_concurrent_futures/test_thread_pool.py
Lib/test/test_concurrent_futures/test_wait.py
Lib/test/test_concurrent_futures/util.py
Lib/test/test_fork1.py
Lib/test/test_kqueue.py
Lib/test/test_logging.py
Lib/test/test_mailbox.py
Lib/test/test_os.py
Lib/test/test_platform.py
Lib/test/test_pty.py
Lib/test/test_random.py
Lib/test/test_socketserver.py
Lib/test/test_support.py
Lib/test/test_tracemalloc.py
Lib/test/test_uuid.py
Misc/NEWS.d/next/Library/2025-07-19-11-53-19.gh-issue-135427.iJM_X2.rst [new file with mode: 0644]
Modules/posixmodule.c

index a1259ff1d63d18fe803d6856013262b50103a4f0..a1c30bcfd517478a4ddeffd1c3c9a9a5a9ac0c91 100644 (file)
@@ -39,7 +39,7 @@ from test.support import script_helper
 from test.support import socket_helper
 from test.support import threading_helper
 from test.support import warnings_helper
-
+from test.support.script_helper import assert_python_failure, assert_python_ok
 
 # Skip tests if _multiprocessing wasn't built.
 _multiprocessing = import_helper.import_module('_multiprocessing')
@@ -325,6 +325,7 @@ class _TestProcess(BaseTestCase):
         self.assertEqual(current.ident, os.getpid())
         self.assertEqual(current.exitcode, None)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_set_executable(self):
         if self.TYPE == 'threads':
             self.skipTest(f'test not appropriate for {self.TYPE}')
@@ -341,6 +342,7 @@ class _TestProcess(BaseTestCase):
             p.join()
             self.assertEqual(p.exitcode, 0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_resource('cpu')
     def test_args_argument(self):
         # bpo-45735: Using list or tuple as *args* in constructor could
@@ -388,6 +390,7 @@ class _TestProcess(BaseTestCase):
             q.put(bytes(current.authkey))
             q.put(current.pid)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_parent_process_attributes(self):
         if self.TYPE == "threads":
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -408,6 +411,7 @@ class _TestProcess(BaseTestCase):
         from multiprocessing.process import parent_process
         wconn.send([parent_process().pid, parent_process().name])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_parent_process(self):
         if self.TYPE == "threads":
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -446,6 +450,7 @@ class _TestProcess(BaseTestCase):
         parent_process().join(timeout=support.SHORT_TIMEOUT)
         wconn.send("alive" if parent_process().is_alive() else "not alive")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_process(self):
         q = self.Queue(1)
         e = self.Event()
@@ -486,6 +491,7 @@ class _TestProcess(BaseTestCase):
         self.assertNotIn(p, self.active_children())
         close_queue(q)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(threading._HAVE_THREAD_NATIVE_ID, "needs native_id")
     def test_process_mainthread_native_id(self):
         if self.TYPE == 'threads':
@@ -526,6 +532,7 @@ class _TestProcess(BaseTestCase):
     def _test_sleep(cls, delay):
         time.sleep(delay)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def _kill_process(self, meth, target=None):
         if self.TYPE == 'threads':
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -583,6 +590,7 @@ class _TestProcess(BaseTestCase):
 
         return p.exitcode
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipIf(os.name == 'nt', "POSIX only")
     def test_interrupt(self):
         exitcode = self._kill_process(multiprocessing.Process.interrupt)
@@ -591,15 +599,18 @@ class _TestProcess(BaseTestCase):
         # (KeyboardInterrupt in this case)
         # in multiprocessing.BaseProcess._bootstrap
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipIf(os.name == 'nt', "POSIX only")
     def test_interrupt_no_handler(self):
         exitcode = self._kill_process(multiprocessing.Process.interrupt, target=self._sleep_no_int_handler)
         self.assertEqual(exitcode, -signal.SIGINT)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_terminate(self):
         exitcode = self._kill_process(multiprocessing.Process.terminate)
         self.assertEqual(exitcode, -signal.SIGTERM)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_kill(self):
         exitcode = self._kill_process(multiprocessing.Process.kill)
         if os.name != 'nt':
@@ -615,6 +626,7 @@ class _TestProcess(BaseTestCase):
         self.assertIsInstance(cpus, int)
         self.assertGreaterEqual(cpus, 1)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_active_children(self):
         self.assertEqual(type(self.active_children()), list)
 
@@ -643,6 +655,7 @@ class _TestProcess(BaseTestCase):
                 p.start()
                 p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_recursion(self):
         rconn, wconn = self.Pipe(duplex=False)
         self._test_recursion(wconn, [])
@@ -667,6 +680,7 @@ class _TestProcess(BaseTestCase):
     def _test_sentinel(cls, event):
         event.wait(10.0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_sentinel(self):
         if self.TYPE == "threads":
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -689,6 +703,7 @@ class _TestProcess(BaseTestCase):
             q.get()
         sys.exit(rc)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_close(self):
         if self.TYPE == "threads":
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -721,6 +736,7 @@ class _TestProcess(BaseTestCase):
 
         close_queue(q)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_resource('walltime')
     def test_many_processes(self):
         if self.TYPE == 'threads':
@@ -757,6 +773,7 @@ class _TestProcess(BaseTestCase):
             for p in procs:
                 self.assertIn(p.exitcode, exitcodes)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_lose_target_ref(self):
         c = DummyCallable()
         wr = weakref.ref(c)
@@ -819,6 +836,7 @@ class _TestProcess(BaseTestCase):
         threading.Thread(target=func1).start()
         threading.Thread(target=func2, daemon=True).start()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_wait_for_threads(self):
         # A child process should wait for non-daemonic threads to end
         # before exiting
@@ -843,6 +861,7 @@ class _TestProcess(BaseTestCase):
             setattr(sys, stream_name, None)
         evt.set()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_error_on_stdio_flush_1(self):
         # Check that Process works with broken standard streams
         streams = [io.StringIO(), None]
@@ -862,6 +881,7 @@ class _TestProcess(BaseTestCase):
                 finally:
                     setattr(sys, stream_name, old_stream)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_error_on_stdio_flush_2(self):
         # Same as test_error_on_stdio_flush_1(), but standard streams are
         # broken by the child process
@@ -1012,6 +1032,7 @@ class _TestSubclassingProcess(BaseTestCase):
 
     ALLOWED_TYPES = ('processes',)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_subclassing(self):
         uppercaser = _UpperCaser()
         uppercaser.daemon = True
@@ -1021,6 +1042,7 @@ class _TestSubclassingProcess(BaseTestCase):
         uppercaser.stop()
         uppercaser.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_stderr_flush(self):
         # sys.stderr is flushed at process shutdown (issue #13812)
         if self.TYPE == "threads":
@@ -1051,6 +1073,7 @@ class _TestSubclassingProcess(BaseTestCase):
         sys.stderr = open(fd, 'w', encoding="utf-8", closefd=False)
         sys.exit(reason)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_sys_exit(self):
         # See Issue 13854
         if self.TYPE == 'threads':
@@ -1118,6 +1141,7 @@ class _TestQueue(BaseTestCase):
             queue.get()
         parent_can_continue.set()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_put(self):
         MAXSIZE = 6
         queue = self.Queue(maxsize=MAXSIZE)
@@ -1187,6 +1211,7 @@ class _TestQueue(BaseTestCase):
         queue.put(5)
         parent_can_continue.set()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_get(self):
         queue = self.Queue()
         child_can_start = self.Event()
@@ -1248,6 +1273,7 @@ class _TestQueue(BaseTestCase):
         # process cannot shutdown until the feeder thread has finished
         # pushing items onto the pipe.
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_fork(self):
         # Old versions of Queue would fail to create a new feeder
         # thread for a forked process if the original process had its
@@ -1298,6 +1324,7 @@ class _TestQueue(BaseTestCase):
             time.sleep(DELTA)
             q.task_done()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_task_done(self):
         queue = self.JoinableQueue()
 
@@ -1341,6 +1368,7 @@ class _TestQueue(BaseTestCase):
                     self.fail("Probable regression on import lock contention;"
                               " see Issue #22853")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_timeout(self):
         q = multiprocessing.Queue()
         start = time.monotonic()
@@ -1464,6 +1492,7 @@ class _TestLock(BaseTestCase):
         event.set()
         time.sleep(1.0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_repr_lock(self):
         if self.TYPE != 'processes':
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -1527,6 +1556,7 @@ class _TestLock(BaseTestCase):
         res.value = lock.locked()
         event.set()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes')
     def test_lock_locked_2processes(self):
         if self.TYPE != 'processes':
@@ -1553,6 +1583,7 @@ class _TestLock(BaseTestCase):
         for _ in range(n):
             lock.release()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_repr_rlock(self):
         if self.TYPE != 'processes':
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -1612,6 +1643,7 @@ class _TestLock(BaseTestCase):
         self.assertFalse(lock.locked())
         self.assertRaises((AssertionError, RuntimeError), lock.release)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes')
     def test_rlock_locked_2processes(self):
         if self.TYPE != 'processes':
@@ -1723,6 +1755,7 @@ class _TestCondition(BaseTestCase):
             except NotImplementedError:
                 pass
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_notify(self):
         cond = self.Condition()
         sleeping = self.Semaphore(0)
@@ -1765,6 +1798,7 @@ class _TestCondition(BaseTestCase):
         threading_helper.join_thread(t)
         join_process(p)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_notify_all(self):
         cond = self.Condition()
         sleeping = self.Semaphore(0)
@@ -1834,6 +1868,7 @@ class _TestCondition(BaseTestCase):
             # NOTE: join_process and join_thread are the same
             threading_helper.join_thread(w)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_notify_n(self):
         cond = self.Condition()
         sleeping = self.Semaphore(0)
@@ -1907,6 +1942,7 @@ class _TestCondition(BaseTestCase):
             if not result or state.value != 4:
                 sys.exit(1)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes')
     def test_waitfor(self):
         # based on test in test/lock_tests.py
@@ -1942,6 +1978,7 @@ class _TestCondition(BaseTestCase):
             if not result and (expected - CLOCK_RES) <= dt:
                 success.value = True
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes')
     def test_waitfor_timeout(self):
         # based on test in test/lock_tests.py
@@ -1974,6 +2011,7 @@ class _TestCondition(BaseTestCase):
         if pid is not None:
             os.kill(pid, signal.SIGINT)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_wait_result(self):
         if isinstance(self, ProcessesMixin) and sys.platform != 'win32':
             pid = os.getpid()
@@ -2002,6 +2040,7 @@ class _TestEvent(BaseTestCase):
         time.sleep(TIMEOUT2)
         event.set()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_event(self):
         event = self.Event()
         wait = TimingWrapper(event.wait)
@@ -2198,6 +2237,7 @@ class _TestBarrier(BaseTestCase):
             pass
         assert not barrier.broken
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_barrier(self, passes=1):
         """
         Test that a barrier is passed in lockstep
@@ -2205,6 +2245,7 @@ class _TestBarrier(BaseTestCase):
         results = [self.DummyList(), self.DummyList()]
         self.run_threads(self.multipass, (self.barrier, results, passes))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_barrier_10(self):
         """
         Test that a barrier works for 10 consecutive runs
@@ -2216,6 +2257,7 @@ class _TestBarrier(BaseTestCase):
         res = barrier.wait()
         queue.put(res)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_wait_return(self):
         """
         test the return value from barrier.wait
@@ -2232,6 +2274,7 @@ class _TestBarrier(BaseTestCase):
         if len(results) != 1:
             raise RuntimeError
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_action(self):
         """
         Test the 'action' callback
@@ -2254,6 +2297,7 @@ class _TestBarrier(BaseTestCase):
         except RuntimeError:
             barrier.abort()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_abort(self):
         """
         Test that an abort will put the barrier in a broken state
@@ -2284,6 +2328,7 @@ class _TestBarrier(BaseTestCase):
         barrier.wait()
         results3.append(True)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_reset(self):
         """
         Test that a 'reset' on a barrier frees the waiting threads
@@ -2319,6 +2364,7 @@ class _TestBarrier(BaseTestCase):
         barrier.wait()
         results3.append(True)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_abort_and_reset(self):
         """
         Test that a barrier can be reset after being broken.
@@ -2345,6 +2391,7 @@ class _TestBarrier(BaseTestCase):
         except threading.BrokenBarrierError:
             results.append(True)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_timeout(self):
         """
         Test wait(timeout)
@@ -2364,6 +2411,7 @@ class _TestBarrier(BaseTestCase):
         except threading.BrokenBarrierError:
             results.append(True)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_default_timeout(self):
         """
         Test the barrier's default timeout
@@ -2385,6 +2433,7 @@ class _TestBarrier(BaseTestCase):
             with lock:
                 conn.send(i)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_thousand(self):
         if self.TYPE == 'manager':
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -2426,7 +2475,7 @@ class _TestValue(BaseTestCase):
         for sv, cv in zip(values, cls.codes_values):
             sv.value = cv[2]
 
-
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_value(self, raw=False):
         if raw:
             values = [self.RawValue(code, value)
@@ -2490,6 +2539,7 @@ class _TestArray(BaseTestCase):
         for i in range(1, len(seq)):
             seq[i] += seq[i-1]
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipIf(c_int is None, "requires _ctypes")
     def test_array(self, raw=False):
         seq = [680, 626, 934, 821, 150, 233, 548, 982, 714, 831]
@@ -2801,8 +2851,9 @@ class _TestPool(BaseTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super().setUpClass()
-        cls.pool = cls.Pool(4)
+        with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+            super().setUpClass()
+            cls.pool = cls.Pool(4)
 
     @classmethod
     def tearDownClass(cls):
@@ -2901,6 +2952,7 @@ class _TestPool(BaseTestCase):
         self.assertEqual(get(), 49)
         self.assertTimingAlmostEqual(get.elapsed, TIMEOUT1)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_async_timeout(self):
         p = self.Pool(3)
         try:
@@ -2998,6 +3050,7 @@ class _TestPool(BaseTestCase):
                 self.assertIn(value, expected_values)
                 expected_values.remove(value)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_make_pool(self):
         expected_error = (RemoteError if self.TYPE == 'manager'
                           else ValueError)
@@ -3013,6 +3066,7 @@ class _TestPool(BaseTestCase):
                 p.close()
                 p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_terminate(self):
         # Simulate slow tasks which take "forever" to complete
         sleep_time = support.LONG_TIMEOUT
@@ -3030,6 +3084,7 @@ class _TestPool(BaseTestCase):
         p.terminate()
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_empty_iterable(self):
         # See Issue 12157
         p = self.Pool(1)
@@ -3042,6 +3097,7 @@ class _TestPool(BaseTestCase):
         p.close()
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_context(self):
         if self.TYPE == 'processes':
             L = list(range(10))
@@ -3056,6 +3112,7 @@ class _TestPool(BaseTestCase):
     def _test_traceback(cls):
         raise RuntimeError(123) # some comment
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_traceback(self):
         # We want ensure that the traceback from the child process is
         # contained in the traceback raised in the main process.
@@ -3095,9 +3152,11 @@ class _TestPool(BaseTestCase):
             p.join()
 
     @classmethod
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def _test_wrapped_exception(cls):
         raise RuntimeError('foo')
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_wrapped_exception(self):
         # Issue #20980: Should not wrap exception when using thread pool
         with self.Pool(1) as p:
@@ -3105,6 +3164,7 @@ class _TestPool(BaseTestCase):
                 p.apply(self._test_wrapped_exception)
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_no_failfast(self):
         # Issue #23992: the fail-fast behaviour when an exception is raised
         # during map() would make Pool.join() deadlock, because a worker
@@ -3140,6 +3200,7 @@ class _TestPool(BaseTestCase):
         # they were released too.
         self.assertEqual(CountedObject.n_instances, 0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_enter(self):
         if self.TYPE == 'manager':
             self.skipTest("test not applicable to manager")
@@ -3156,6 +3217,7 @@ class _TestPool(BaseTestCase):
                 pass
         pool.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_resource_warning(self):
         if self.TYPE == 'manager':
             self.skipTest("test not applicable to manager")
@@ -3181,6 +3243,7 @@ def unpickleable_result():
 class _TestPoolWorkerErrors(BaseTestCase):
     ALLOWED_TYPES = ('processes', )
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_async_error_callback(self):
         p = multiprocessing.Pool(2)
 
@@ -3196,6 +3259,7 @@ class _TestPoolWorkerErrors(BaseTestCase):
         p.close()
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_unpickleable_result(self):
         from multiprocessing.pool import MaybeEncodingError
         p = multiprocessing.Pool(2)
@@ -3221,6 +3285,7 @@ class _TestPoolWorkerErrors(BaseTestCase):
 class _TestPoolWorkerLifetime(BaseTestCase):
     ALLOWED_TYPES = ('processes', )
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_pool_worker_lifetime(self):
         p = multiprocessing.Pool(3, maxtasksperchild=10)
         self.assertEqual(3, len(p._pool))
@@ -3250,6 +3315,7 @@ class _TestPoolWorkerLifetime(BaseTestCase):
         p.close()
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_pool_worker_lifetime_early_close(self):
         # Issue #10332: closing a pool whose workers have limited lifetimes
         # before all the tasks completed would make join() hang.
@@ -3323,6 +3389,7 @@ class _TestMyManager(BaseTestCase):
 
     ALLOWED_TYPES = ('manager',)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_mymanager(self):
         manager = MyManager(shutdown_timeout=SHUTDOWN_TIMEOUT)
         manager.start()
@@ -3334,6 +3401,7 @@ class _TestMyManager(BaseTestCase):
         # which happens on slow buildbots.
         self.assertIn(manager._process.exitcode, (0, -signal.SIGTERM))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_mymanager_context(self):
         manager = MyManager(shutdown_timeout=SHUTDOWN_TIMEOUT)
         with manager:
@@ -3343,6 +3411,7 @@ class _TestMyManager(BaseTestCase):
         # which happens on slow buildbots.
         self.assertIn(manager._process.exitcode, (0, -signal.SIGTERM))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_mymanager_context_prestarted(self):
         manager = MyManager(shutdown_timeout=SHUTDOWN_TIMEOUT)
         manager.start()
@@ -3413,6 +3482,7 @@ class _TestRemoteManager(BaseTestCase):
         # Note that xmlrpclib will deserialize object as a list not a tuple
         queue.put(tuple(cls.values))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_remote(self):
         authkey = os.urandom(32)
 
@@ -3454,6 +3524,7 @@ class _TestManagerRestart(BaseTestCase):
         queue = manager.get_queue()
         queue.put('hello world')
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_rapid_restart(self):
         authkey = os.urandom(32)
         manager = QueueManager(
@@ -3506,12 +3577,14 @@ class FakeConnection:
 class TestManagerExceptions(unittest.TestCase):
     # Issue 106558: Manager exceptions avoids creating cyclic references.
     def setUp(self):
-        self.mgr = multiprocessing.Manager()
+        with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+            self.mgr = multiprocessing.Manager()
 
     def tearDown(self):
         self.mgr.shutdown()
         self.mgr.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_queue_get(self):
         queue = self.mgr.Queue()
         if gc.isenabled():
@@ -3523,6 +3596,7 @@ class TestManagerExceptions(unittest.TestCase):
             wr = weakref.ref(e)
         self.assertEqual(wr(), None)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_dispatch(self):
         if gc.isenabled():
             gc.disable()
@@ -3549,6 +3623,7 @@ class _TestConnection(BaseTestCase):
             conn.send_bytes(msg)
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_connection(self):
         conn, child_conn = self.Pipe()
 
@@ -3641,6 +3716,7 @@ class _TestConnection(BaseTestCase):
             self.assertRaises(OSError, writer.recv)
             self.assertRaises(OSError, writer.poll)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_spawn_close(self):
         # We test that a pipe connection can be closed by parent
         # process immediately after child is spawned.  On Windows this
@@ -3717,6 +3793,7 @@ class _TestConnection(BaseTestCase):
         os.write(fd, data)
         os.close(fd)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_REDUCTION, "test needs multiprocessing.reduction")
     def test_fd_transfer(self):
         if self.TYPE != 'processes':
@@ -3736,6 +3813,7 @@ class _TestConnection(BaseTestCase):
         with open(os_helper.TESTFN, "rb") as f:
             self.assertEqual(f.read(), b"foo")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_REDUCTION, "test needs multiprocessing.reduction")
     @unittest.skipIf(sys.platform == "win32",
                      "test semantics don't make sense on Windows")
@@ -3773,6 +3851,7 @@ class _TestConnection(BaseTestCase):
     def _send_data_without_fd(self, conn):
         os.write(conn.fileno(), b"\0")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(HAS_REDUCTION, "test needs multiprocessing.reduction")
     @unittest.skipIf(sys.platform == "win32", "doesn't make sense on Windows")
     def test_missing_fd_transfer(self):
@@ -3872,6 +3951,7 @@ class _TestListenerClient(BaseTestCase):
         conn.send('hello')
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_listener_client(self):
         for family in self.connection.families:
             l = self.connection.Listener(family=family)
@@ -3883,6 +3963,7 @@ class _TestListenerClient(BaseTestCase):
             p.join()
             l.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_issue14725(self):
         l = self.connection.Listener()
         p = self.Process(target=self._test, args=(l.address,))
@@ -3928,6 +4009,7 @@ class _TestPoll(BaseTestCase):
             conn.send_bytes(s)
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_strings(self):
         strings = (b'hello', b'', b'a', b'b', b'', b'bye', b'', b'lop')
         a, b = self.Pipe()
@@ -3951,6 +4033,7 @@ class _TestPoll(BaseTestCase):
         # read from it.
         r.poll(5)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_boundaries(self):
         r, w = self.Pipe(False)
         p = self.Process(target=self._child_boundaries, args=(r,))
@@ -3969,6 +4052,7 @@ class _TestPoll(BaseTestCase):
         b.send_bytes(b'b')
         b.send_bytes(b'cd')
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_dont_merge(self):
         a, b = self.Pipe()
         self.assertEqual(a.poll(0.0), False)
@@ -4037,6 +4121,7 @@ class _TestPicklingConnections(BaseTestCase):
 
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_pickling(self):
         families = self.connection.families
 
@@ -4095,6 +4180,7 @@ class _TestPicklingConnections(BaseTestCase):
 
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_access(self):
         # On Windows, if we do not specify a destination pid when
         # using DupHandle then we need to be careful to use the
@@ -4258,6 +4344,7 @@ class _TestSharedCTypes(BaseTestCase):
         for i in range(len(arr)):
             arr[i] *= 2
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_sharedctypes(self, lock=False):
         x = Value('i', 7, lock=lock)
         y = Value(c_double, 1.0/3.0, lock=lock)
@@ -4519,6 +4606,7 @@ class _TestSharedMemory(BaseTestCase):
                 with self.assertRaises(FileNotFoundError):
                     pickle.loads(pickled_sms)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_shared_memory_across_processes(self):
         # bpo-40135: don't define shared memory block's name in case of
         # the failure when we run multiprocessing tests in parallel.
@@ -4547,6 +4635,7 @@ class _TestSharedMemory(BaseTestCase):
 
         sms.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipIf(os.name != "posix", "not feasible in non-posix platforms")
     def test_shared_memory_SharedMemoryServer_ignores_sigint(self):
         # bpo-36368: protect SharedMemoryManager server process from
@@ -4592,6 +4681,7 @@ class _TestSharedMemory(BaseTestCase):
         # properly released sl.
         self.assertFalse(err)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_shared_memory_SharedMemoryManager_basics(self):
         smm1 = multiprocessing.managers.SharedMemoryManager()
         with self.assertRaises(ValueError):
@@ -4931,6 +5021,7 @@ class _TestFinalize(BaseTestCase):
         conn.close()
         os._exit(0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_finalize(self):
         conn, child_conn = self.Pipe()
 
@@ -5058,6 +5149,7 @@ class _TestLogging(BaseTestCase):
         logger = multiprocessing.get_logger()
         conn.send(logger.getEffectiveLevel())
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_level(self):
         LEVEL1 = 32
         LEVEL2 = 37
@@ -5142,6 +5234,7 @@ class _TestPollEintr(BaseTestCase):
         time.sleep(0.1)
         os.kill(pid, signal.SIGUSR1)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1')
     def test_poll_eintr(self):
         got_signal = [False]
@@ -5264,14 +5357,16 @@ def initializer(ns):
 @hashlib_helper.requires_hashdigest('sha256')
 class TestInitializers(unittest.TestCase):
     def setUp(self):
-        self.mgr = multiprocessing.Manager()
-        self.ns = self.mgr.Namespace()
-        self.ns.test = 0
+        with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+            self.mgr = multiprocessing.Manager()
+            self.ns = self.mgr.Namespace()
+            self.ns.test = 0
 
     def tearDown(self):
         self.mgr.shutdown()
         self.mgr.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_manager_initializer(self):
         m = multiprocessing.managers.SyncManager()
         self.assertRaises(TypeError, m.start, 1)
@@ -5280,6 +5375,7 @@ class TestInitializers(unittest.TestCase):
         m.shutdown()
         m.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_pool_initializer(self):
         self.assertRaises(TypeError, multiprocessing.Pool, initializer=1)
         p = multiprocessing.Pool(1, initializer, (self.ns,))
@@ -5337,16 +5433,19 @@ class _file_like(object):
 
 class TestStdinBadfiledescriptor(unittest.TestCase):
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_queue_in_process(self):
         proc = multiprocessing.Process(target=_test_process)
         proc.start()
         proc.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_pool_in_process(self):
         p = multiprocessing.Process(target=pool_in_process)
         p.start()
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_flushing(self):
         sio = io.StringIO()
         flike = _file_like(sio)
@@ -5366,6 +5465,7 @@ class TestWait(unittest.TestCase):
             w.send((i, os.getpid()))
         w.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_wait(self, slow=False):
         from multiprocessing.connection import wait
         readers = []
@@ -5406,6 +5506,7 @@ class TestWait(unittest.TestCase):
             s.sendall(('%s\n' % i).encode('ascii'))
         s.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_wait_socket(self, slow=False):
         from multiprocessing.connection import wait
         l = socket.create_server((socket_helper.HOST, 0))
@@ -5470,6 +5571,7 @@ class TestWait(unittest.TestCase):
         sem.release()
         time.sleep(period)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_resource('walltime')
     def test_wait_integer(self):
         from multiprocessing.connection import wait
@@ -5514,6 +5616,7 @@ class TestWait(unittest.TestCase):
         p.terminate()
         p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_neg_timeout(self):
         from multiprocessing.connection import wait
         a, b = multiprocessing.Pipe()
@@ -5591,6 +5694,7 @@ class TestTimeouts(unittest.TestCase):
         conn.send(456)
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_timeout(self):
         old_timeout = socket.getdefaulttimeout()
         try:
@@ -5648,6 +5752,7 @@ class TestForkAwareThreadLock(unittest.TestCase):
             conn.send(len(util._afterfork_registry))
         conn.close()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_lock(self):
         r, w = multiprocessing.Pipe(False)
         l = util.ForkAwareThreadLock()
@@ -5699,6 +5804,7 @@ class TestCloseFds(unittest.TestCase):
             s.close()
             conn.send(None)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_closefd(self):
         if not HAS_REDUCTION:
             raise unittest.SkipTest('requires fd pickling')
@@ -5744,6 +5850,7 @@ class TestIgnoreEINTR(unittest.TestCase):
         conn.send(x)
         conn.send_bytes(b'x' * cls.CONN_MAX_SIZE)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1')
     def test_ignore(self):
         conn, child_conn = multiprocessing.Pipe()
@@ -5777,6 +5884,7 @@ class TestIgnoreEINTR(unittest.TestCase):
             a = l.accept()
             a.send('welcome')
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1')
     def test_ignore_listener(self):
         conn, child_conn = multiprocessing.Pipe()
@@ -5811,6 +5919,7 @@ class TestStartMethod(unittest.TestCase):
         p.join()
         self.assertEqual(child_method, ctx.get_start_method())
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_context(self):
         for method in ('fork', 'spawn', 'forkserver'):
             try:
@@ -5831,6 +5940,7 @@ class TestStartMethod(unittest.TestCase):
         with self.assertRaisesRegex(TypeError, 'module_names must be a list of strings'):
             ctx.set_forkserver_preload([1, 2, 3])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_set_get(self):
         multiprocessing.set_forkserver_preload(PRELOAD)
         count = 0
@@ -5888,6 +5998,7 @@ class TestStartMethod(unittest.TestCase):
             print(err)
             self.fail("failed spawning forkserver or grandchild")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipIf(sys.platform == "win32",
                      "Only Spawn on windows so no risk of mixing")
     @only_run_in_spawn_testsuite("avoids redundant testing.")
@@ -5921,6 +6032,7 @@ class TestStartMethod(unittest.TestCase):
         process.start()
         process.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_nested_startmethod(self):
         # gh-108520: Regression test to ensure that child process can send its
         # arguments to another process
@@ -6076,6 +6188,7 @@ class TestResourceTracker(unittest.TestCase):
         reused &= _resource_tracker._check_alive()
         conn.send(reused)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_resource_tracker_reused(self):
         from multiprocessing.resource_tracker import _resource_tracker
         _resource_tracker.ensure_running()
@@ -6177,6 +6290,7 @@ class TestSimpleQueue(unittest.TestCase):
         with self.assertRaisesRegex(OSError, 'is closed'):
             q.empty()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_empty(self):
         queue = multiprocessing.SimpleQueue()
         child_can_start = multiprocessing.Event()
@@ -6284,7 +6398,8 @@ class TestSyncManagerTypes(unittest.TestCase):
 
     def setUp(self):
         self.manager = self.manager_class()
-        self.manager.start()
+        with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+            self.manager.start()
         self.proc = None
 
     def tearDown(self):
@@ -6333,6 +6448,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         obj.clear()
         obj.wait(0.001)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_event(self):
         o = self.manager.Event()
         o.set()
@@ -6345,6 +6461,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         obj.acquire()
         obj.locked()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_lock(self, lname="Lock"):
         o = getattr(self.manager, lname)()
         self.run_worker(self._test_lock, o)
@@ -6357,6 +6474,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         obj.release()
         obj.locked()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_rlock(self, lname="RLock"):
         o = getattr(self.manager, lname)()
         self.run_worker(self._test_rlock, o)
@@ -6365,6 +6483,7 @@ class TestSyncManagerTypes(unittest.TestCase):
     def _test_semaphore(cls, obj):
         obj.acquire()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_semaphore(self, sname="Semaphore"):
         o = getattr(self.manager, sname)()
         self.run_worker(self._test_semaphore, o)
@@ -6378,6 +6497,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         obj.acquire()
         obj.release()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_condition(self):
         o = self.manager.Condition()
         self.run_worker(self._test_condition, o)
@@ -6387,6 +6507,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         assert obj.parties == 5
         obj.reset()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_barrier(self):
         o = self.manager.Barrier(5)
         self.run_worker(self._test_barrier, o)
@@ -6397,6 +6518,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         with obj:
             pass
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_pool(self):
         o = self.manager.Pool(processes=4)
         self.run_worker(self._test_pool, o)
@@ -6411,6 +6533,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         assert obj.get() == 6
         assert obj.empty()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_queue(self, qname="Queue"):
         o = getattr(self.manager, qname)(2)
         o.put(5)
@@ -6419,6 +6542,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         assert o.empty()
         assert not o.full()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_joinable_queue(self):
         self.test_queue("JoinableQueue")
 
@@ -6453,6 +6577,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         obj.clear()
         case.assertEqual(len(obj), 0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_list(self):
         o = self.manager.list()
         o.append(5)
@@ -6494,6 +6619,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         obj.clear()
         case.assertEqual(len(obj), 0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_dict(self):
         o = self.manager.dict()
         o['foo'] = 5
@@ -6508,6 +6634,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         case.assertEqual(obj.get(), 1)
         obj.set(2)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_value(self):
         o = self.manager.Value('i', 1)
         self.run_worker(self._test_value, o)
@@ -6522,6 +6649,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         case.assertEqual(len(obj), 2)
         case.assertListEqual(list(obj), [0, 1])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_array(self):
         o = self.manager.Array('i', [0, 1])
         self.run_worker(self._test_array, o)
@@ -6532,6 +6660,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         case.assertEqual(obj.x, 0)
         case.assertEqual(obj.y, 1)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_namespace(self):
         o = self.manager.Namespace()
         o.x = 0
@@ -6651,6 +6780,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         case.assertGreater(obj, {'a'})
         case.assertGreaterEqual(obj, {'a', 'b'})
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_set(self):
         o = self.manager.set()
         self.run_worker(self._test_set_operator_symbols, o)
@@ -6668,6 +6798,7 @@ class TestSyncManagerTypes(unittest.TestCase):
         self.assertSetEqual(o, {"a", "b", "c"})
         self.assertRaises(RemoteError, self.manager.set, 1234)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_set_contain_all_method(self):
         o = self.manager.set()
         set_methods = {
@@ -6721,6 +6852,7 @@ class _TestAtExit(BaseTestCase):
                 f.write("deadbeef")
         atexit.register(exit_handler)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_atexit(self):
         # gh-83856
         with os_helper.temp_dir() as temp_dir:
@@ -6873,6 +7005,7 @@ class MiscTestCase(unittest.TestCase):
         self.assertEqual("332833500", out.decode('utf-8').strip())
         self.assertFalse(err, msg=err.decode('utf-8'))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_forked_thread_not_started(self):
         # gh-134381: Ensure that a thread that has not been started yet in
         # the parent process can be started within a forked child process.
@@ -6974,8 +7107,9 @@ class ManagerMixin(BaseMixin):
 
     @classmethod
     def setUpClass(cls):
-        super().setUpClass()
-        cls.manager = multiprocessing.Manager()
+        with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+            super().setUpClass()
+            cls.manager = multiprocessing.Manager()
 
     @classmethod
     def tearDownClass(cls):
@@ -7142,3 +7276,62 @@ class SemLockTests(unittest.TestCase):
         name = f'test_semlock_subclass-{os.getpid()}'
         s = SemLock(1, 0, 10, name, False)
         _multiprocessing.sem_unlink(name)
+
+
+@unittest.skipIf(sys.platform != "linux", "Linux only")
+class ForkInThreads(unittest.TestCase):
+
+    def test_fork(self):
+        code = """
+        import os, sys, threading, time
+
+        t = threading.Thread(target=time.sleep, args=(1,), daemon=True)
+        t.start()
+
+        assert threading.active_count() == 2
+
+        pid = os.fork()
+        if pid < 0:
+            print("Fork failed")
+        elif pid == 0:
+            print("In child")
+            sys.exit(0)
+        print("In parent")
+        """
+
+        res = assert_python_ok("-c", code, PYTHONWARNINGS='always')
+        self.assertIn(b'In child', res.out)
+        self.assertIn(b'In parent', res.out)
+        self.assertIn(b'DeprecationWarning', res.err)
+        self.assertIn(b'is multi-threaded, use of fork() may lead to deadlocks in the child', res.err)
+
+        res = assert_python_failure("-c", code, PYTHONWARNINGS='error')
+        self.assertIn(b'DeprecationWarning', res.err)
+        self.assertIn(b'is multi-threaded, use of fork() may lead to deadlocks in the child', res.err)
+
+    def test_forkpty(self):
+        code = """
+        import os, sys, threading, time
+
+        t = threading.Thread(target=time.sleep, args=(1,), daemon=True)
+        t.start()
+
+        assert threading.active_count() == 2
+
+        pid, _ = os.forkpty()
+        if pid < 0:
+            print(f"forkpty failed")
+        elif pid == 0:
+            print(f"In child")
+            sys.exit(0)
+        print(f"In parent")
+        """
+
+        res = assert_python_ok("-c", code, PYTHONWARNINGS='always')
+        self.assertIn(b'In parent', res.out)
+        self.assertIn(b'DeprecationWarning', res.err)
+        self.assertIn(b'is multi-threaded, use of forkpty() may lead to deadlocks in the child', res.err)
+
+        res = assert_python_failure("-c", code, PYTHONWARNINGS='error')
+        self.assertIn(b'DeprecationWarning', res.err)
+        self.assertIn(b'is multi-threaded, use of forkpty() may lead to deadlocks in the child', res.err)
index 5f6f14afd74a6ee9e9c415a4a83b93724fd12957..c046f39fbff511d48a932cf3c9e7fa6a43e4b8c9 100644 (file)
@@ -1,11 +1,11 @@
 import contextlib
-import functools
 import importlib
 import re
 import sys
 import warnings
 
 
+
 def import_deprecated(name):
     """Import *name* while suppressing DeprecationWarning."""
     with warnings.catch_warnings():
@@ -42,20 +42,32 @@ def check_syntax_warning(testcase, statement, errtext='',
     testcase.assertEqual(warns, [])
 
 
-def ignore_warnings(*, category):
+@contextlib.contextmanager
+def ignore_warnings(*, category, message=''):
     """Decorator to suppress warnings.
 
-    Use of context managers to hide warnings make diffs
-    more noisy and tools like 'git blame' less useful.
+    Can also be used as a context manager. This is not preferred,
+    because it makes diffs more noisy and tools like 'git blame' less useful.
+    But, it's useful for async functions.
     """
-    def decorator(test):
-        @functools.wraps(test)
-        def wrapper(self, *args, **kwargs):
-            with warnings.catch_warnings():
-                warnings.simplefilter('ignore', category=category)
-                return test(self, *args, **kwargs)
-        return wrapper
-    return decorator
+    with warnings.catch_warnings():
+        warnings.filterwarnings('ignore', category=category, message=message)
+        yield
+
+
+@contextlib.contextmanager
+def ignore_fork_in_thread_deprecation_warnings():
+    """Suppress deprecation warnings related to forking in multi-threaded code.
+
+    See gh-135427
+
+    Can be used as decorator (preferred) or context manager.
+    """
+    with ignore_warnings(
+        message=".*fork.*may lead to deadlocks in the child.*",
+        category=DeprecationWarning,
+    ):
+        yield
 
 
 class WarningsRecorder(object):
index 22982dc9d8aefef159cedc1b9d1999222a966d31..a69a5e32b1b2bd7cda655a5c08cadab24d356ddc 100644 (file)
@@ -15,7 +15,7 @@ import unittest
 from unittest import mock
 
 from test import support
-from test.support import os_helper
+from test.support import os_helper, warnings_helper
 from test.support import socket_helper
 from test.support import wait_process
 from test.support import hashlib_helper
@@ -1183,29 +1183,31 @@ class TestFunctional(unittest.TestCase):
 class TestFork(unittest.IsolatedAsyncioTestCase):
 
     async def test_fork_not_share_event_loop(self):
-        # The forked process should not share the event loop with the parent
-        loop = asyncio.get_running_loop()
-        r, w = os.pipe()
-        self.addCleanup(os.close, r)
-        self.addCleanup(os.close, w)
-        pid = os.fork()
-        if pid == 0:
-            # child
-            try:
-                loop = asyncio.get_event_loop()
-                os.write(w, b'LOOP:' + str(id(loop)).encode())
-            except RuntimeError:
-                os.write(w, b'NO LOOP')
-            except BaseException as e:
-                os.write(w, b'ERROR:' + ascii(e).encode())
-            finally:
-                os._exit(0)
-        else:
-            # parent
-            result = os.read(r, 100)
-            self.assertEqual(result, b'NO LOOP')
-            wait_process(pid, exitcode=0)
-
+        with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+            # The forked process should not share the event loop with the parent
+            loop = asyncio.get_running_loop()
+            r, w = os.pipe()
+            self.addCleanup(os.close, r)
+            self.addCleanup(os.close, w)
+            pid = os.fork()
+            if pid == 0:
+                # child
+                try:
+                    loop = asyncio.get_event_loop()
+                    os.write(w, b'LOOP:' + str(id(loop)).encode())
+                except RuntimeError:
+                    os.write(w, b'NO LOOP')
+                except BaseException as e:
+                    os.write(w, b'ERROR:' + ascii(e).encode())
+                finally:
+                    os._exit(0)
+            else:
+                # parent
+                result = os.read(r, 100)
+                self.assertEqual(result, b'NO LOOP')
+                wait_process(pid, exitcode=0)
+
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @hashlib_helper.requires_hashdigest('md5')
     @support.skip_if_sanitizer("TSAN doesn't support threads after fork", thread=True)
     def test_fork_signal_handling(self):
@@ -1253,6 +1255,7 @@ class TestFork(unittest.IsolatedAsyncioTestCase):
         self.assertFalse(parent_handled.is_set())
         self.assertTrue(child_handled.is_set())
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @hashlib_helper.requires_hashdigest('md5')
     @support.skip_if_sanitizer("TSAN doesn't support threads after fork", thread=True)
     def test_fork_asyncio_run(self):
@@ -1273,6 +1276,7 @@ class TestFork(unittest.IsolatedAsyncioTestCase):
 
         self.assertEqual(result.value, 42)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @hashlib_helper.requires_hashdigest('md5')
     @support.skip_if_sanitizer("TSAN doesn't support threads after fork", thread=True)
     def test_fork_asyncio_subprocess(self):
index 8830641f0abdc79048665f2308d7fa7a8a81d32f..85cfe5c90f48af8d9eb31e031a4a9e56f220399b 100644 (file)
@@ -31,6 +31,7 @@ from operator import neg
 from test import support
 from test.support import cpython_only, swap_attr
 from test.support import async_yield, run_yielding_async_fn
+from test.support import warnings_helper
 from test.support.import_helper import import_module
 from test.support.os_helper import (EnvironmentVarGuard, TESTFN, unlink)
 from test.support.script_helper import assert_python_ok
@@ -2545,6 +2546,7 @@ class PtyTests(unittest.TestCase):
         finally:
             signal.signal(signal.SIGHUP, old_sighup)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def _run_child(self, child, terminal_input):
         r, w = os.pipe()  # Pipe test results from child back to parent
         try:
index 95bf8fcd25bf54bd03185ea35876092e0ff183a6..a37c4d45f07b1739fbe138acf2bf63f884c5b68b 100644 (file)
@@ -5,7 +5,7 @@ import weakref
 from concurrent import futures
 from operator import add
 from test import support
-from test.support import Py_GIL_DISABLED
+from test.support import Py_GIL_DISABLED, warnings_helper
 
 
 def mul(x, y):
@@ -43,10 +43,12 @@ class ExecutorTest:
 
     # Executor.shutdown() and context manager usage is tested by
     # ExecutorShutdownTest.
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_submit(self):
         future = self.executor.submit(pow, 2, 8)
         self.assertEqual(256, future.result())
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_submit_keyword(self):
         future = self.executor.submit(mul, 2, y=8)
         self.assertEqual(16, future.result())
@@ -57,6 +59,7 @@ class ExecutorTest:
         with self.assertRaises(TypeError):
             self.executor.submit(arg=1)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map(self):
         self.assertEqual(
                 list(self.executor.map(pow, range(10), range(10))),
@@ -66,6 +69,7 @@ class ExecutorTest:
                 list(self.executor.map(pow, range(10), range(10), chunksize=3)),
                 list(map(pow, range(10), range(10))))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_exception(self):
         i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5])
         self.assertEqual(i.__next__(), (0, 1))
@@ -73,6 +77,7 @@ class ExecutorTest:
         with self.assertRaises(ZeroDivisionError):
             i.__next__()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_resource('walltime')
     def test_map_timeout(self):
         results = []
@@ -108,6 +113,7 @@ class ExecutorTest:
                 ):
                     self.executor.map(str, range(4), buffersize=buffersize)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_buffersize(self):
         ints = range(4)
         for buffersize in (1, 2, len(ints), len(ints) * 2):
@@ -115,6 +121,7 @@ class ExecutorTest:
                 res = self.executor.map(str, ints, buffersize=buffersize)
                 self.assertListEqual(list(res), ["0", "1", "2", "3"])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_buffersize_on_multiple_iterables(self):
         ints = range(4)
         for buffersize in (1, 2, len(ints), len(ints) * 2):
@@ -122,12 +129,14 @@ class ExecutorTest:
                 res = self.executor.map(add, ints, ints, buffersize=buffersize)
                 self.assertListEqual(list(res), [0, 2, 4, 6])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_buffersize_on_infinite_iterable(self):
         res = self.executor.map(str, itertools.count(), buffersize=2)
         self.assertEqual(next(res, None), "0")
         self.assertEqual(next(res, None), "1")
         self.assertEqual(next(res, None), "2")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_buffersize_on_multiple_infinite_iterables(self):
         res = self.executor.map(
             add,
@@ -147,6 +156,7 @@ class ExecutorTest:
         res = self.executor.map(str, buffersize=2)
         self.assertIsNone(next(res, None))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_buffersize_when_buffer_is_full(self):
         ints = iter(range(4))
         buffersize = 2
@@ -158,6 +168,7 @@ class ExecutorTest:
             msg="should have fetched only `buffersize` elements from `ints`.",
         )
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_shutdown_race_issue12456(self):
         # Issue #12456: race condition at shutdown where trying to post a
         # sentinel in the call queue blocks (the queue is full while processes
@@ -165,6 +176,7 @@ class ExecutorTest:
         self.executor.map(str, [2] * (self.worker_count + 1))
         self.executor.shutdown()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.cpython_only
     def test_no_stale_references(self):
         # Issue #16284: check that the executors don't unnecessarily hang onto
@@ -209,6 +221,7 @@ class ExecutorTest:
                                         "than 0"):
                 self.executor_type(max_workers=number)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_free_reference(self):
         # Issue #14406: Result iterator should not keep an internal
         # reference to result objects.
@@ -221,6 +234,7 @@ class ExecutorTest:
                 if wr() is None:
                     break
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_swallows_falsey_exceptions(self):
         # see gh-132063: Prevent exceptions that evaluate as falsey
         # from being ignored.
index c90b0021d85fc7db7a56db073fd2b58bba376ea1..31c7bb3ebd872cb61ace6746eb5f156212a4145c 100644 (file)
@@ -7,6 +7,7 @@ from concurrent.futures._base import (
     CANCELLED_AND_NOTIFIED, FINISHED, Future)
 
 from test import support
+from test.support import warnings_helper
 
 from .util import (
     PENDING_FUTURE, RUNNING_FUTURE,
@@ -19,6 +20,7 @@ def mul(x, y):
 
 
 class AsCompletedTests:
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_no_timeout(self):
         future1 = self.executor.submit(mul, 2, 21)
         future2 = self.executor.submit(mul, 7, 6)
@@ -35,6 +37,7 @@ class AsCompletedTests:
                  future1, future2]),
                 completed)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_future_times_out(self):
         """Test ``futures.as_completed`` timing out before
         completing it's final future."""
@@ -62,6 +65,7 @@ class AsCompletedTests:
                 # Check that ``future`` wasn't completed.
                 self.assertEqual(completed_futures, already_completed)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_duplicate_futures(self):
         # Issue 20367. Duplicate futures should not raise exceptions or give
         # duplicate responses.
index a465400509d41151addd8b5299c0023ef1c39289..5cd84f7e43043c6eb80b0a600d325f7abe5555a6 100644 (file)
@@ -10,6 +10,7 @@ from concurrent import futures
 from concurrent.futures.process import BrokenProcessPool, _ThreadWakeup
 
 from test import support
+from test.support import warnings_helper
 
 from .util import (
     create_executor_tests, setup_module,
@@ -111,6 +112,7 @@ class ExecutorDeadlockTest:
         print(f"\nTraceback:\n {tb}", file=sys.__stderr__)
         self.fail(f"Executor deadlock:\n\n{tb}")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def _check_error(self, error, func, *args, ignore_stderr=False):
         # test for deadlock caused by crashes or exiting in a pool
         self.executor.shutdown(wait=True)
@@ -199,6 +201,7 @@ class ExecutorDeadlockTest:
         # the result_handler thread
         self._check_error(BrokenProcessPool, _return_instance, ExitAtUnpickle)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.skip_if_sanitizer("UBSan: explicit SIGSEV not allowed", ub=True)
     def test_shutdown_deadlock(self):
         # Test that the pool calling shutdown do not cause deadlock
@@ -212,6 +215,7 @@ class ExecutorDeadlockTest:
             with self.assertRaises(BrokenProcessPool):
                 f.result()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_shutdown_deadlock_pickle(self):
         # Test that the pool calling shutdown with wait=False does not cause
         # a deadlock if a task fails at pickle after the shutdown call.
@@ -238,6 +242,7 @@ class ExecutorDeadlockTest:
         # dangling threads
         executor_manager.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.skip_if_sanitizer("UBSan: explicit SIGSEV not allowed", ub=True)
     def test_crash_big_data(self):
         # Test that there is a clean exception instead of a deadlock when a
@@ -254,6 +259,7 @@ class ExecutorDeadlockTest:
 
         executor.shutdown(wait=True)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_gh105829_should_not_deadlock_if_wakeup_pipe_full(self):
         # Issue #105829: The _ExecutorManagerThread wakeup pipe could
         # fill up and block. See: https://github.com/python/cpython/issues/105829
index 6b8484c0d5f197a94b63c83b2338c337593d7e74..5ea543bf74898214f8a4c385bb6465451b950378 100644 (file)
@@ -11,6 +11,7 @@ from concurrent.futures.process import _check_system_limits
 from logging.handlers import QueueHandler
 
 from test import support
+from test.support import warnings_helper
 
 from .util import ExecutorMixin, create_executor_tests, setup_module
 
@@ -48,6 +49,7 @@ class InitializerMixin(ExecutorMixin):
                                     initargs=('initialized',))
         super().setUp()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_initializer(self):
         futures = [self.executor.submit(get_init_status)
                    for _ in range(self.worker_count)]
@@ -74,6 +76,7 @@ class FailingInitializerMixin(ExecutorMixin):
             self.executor_kwargs = dict(initializer=init_fail)
         super().setUp()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_initializer(self):
         with self._assert_logged('ValueError: error in initializer'):
             try:
index 3f13a1900a4ca4ce36f8e9ea62c7ee3ca99af54f..9685f980119a0e8a729136a5524df2dce6015cd6 100644 (file)
@@ -9,7 +9,7 @@ from concurrent import futures
 from concurrent.futures.process import BrokenProcessPool
 
 from test import support
-from test.support import hashlib_helper
+from test.support import hashlib_helper, warnings_helper
 from test.test_importlib.metadata.fixtures import parameterize
 
 from .executor import ExecutorTest, mul
@@ -49,6 +49,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
                                     "max_workers must be <= 61"):
             futures.ProcessPoolExecutor(max_workers=62)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_killed_child(self):
         # When a child process is abruptly terminated, the whole pool gets
         # "broken".
@@ -61,6 +62,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
         # Submitting other jobs fails as well.
         self.assertRaises(BrokenProcessPool, self.executor.submit, pow, 2, 8)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_map_chunksize(self):
         def bad_map():
             list(self.executor.map(pow, range(40), range(40), chunksize=-1))
@@ -81,6 +83,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
     def _test_traceback(cls):
         raise RuntimeError(123) # some comment
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_traceback(self):
         # We want ensure that the traceback from the child process is
         # contained in the traceback raised in the main process.
@@ -103,6 +106,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
         self.assertIn('raise RuntimeError(123) # some comment',
                       f1.getvalue())
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @hashlib_helper.requires_hashdigest('md5')
     def test_ressources_gced_in_workers(self):
         # Ensure that argument for a job are correctly gc-ed after the job
@@ -123,6 +127,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
         mgr.shutdown()
         mgr.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_saturation(self):
         executor = self.executor
         mp_context = self.get_context()
@@ -208,6 +213,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
         for i, future in enumerate(futures):
             self.assertEqual(future.result(), mul(i, i))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_python_finalization_error(self):
         # gh-109047: Catch RuntimeError on thread creation
         # during Python finalization.
@@ -258,6 +264,7 @@ class ProcessPoolExecutorTest(ExecutorTest):
                               executor._force_shutdown,
                               operation='invalid operation'),
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @parameterize(*FORCE_SHUTDOWN_PARAMS)
     def test_force_shutdown_workers(self, function_name):
         manager = self.get_context().Manager()
index 43812248104c91981eccbe0dc31dac0eb33d5b92..c576df1068ed320915c516d348e3828b9d659cd9 100644 (file)
@@ -6,6 +6,7 @@ import unittest
 from concurrent import futures
 
 from test import support
+from test.support import warnings_helper
 from test.support.script_helper import assert_python_ok
 
 from .util import (
@@ -78,12 +79,14 @@ class ExecutorShutdownTest:
         self.assertIn("RuntimeError: cannot schedule new futures", err.decode())
         self.assertEqual(out.strip(), b"runtime-error")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_hang_issue12364(self):
         fs = [self.executor.submit(time.sleep, 0.1) for _ in range(50)]
         self.executor.shutdown()
         for f in fs:
             f.result()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_cancel_futures(self):
         assert self.worker_count <= 5, "test needs few workers"
         fs = [self.executor.submit(time.sleep, .1) for _ in range(50)]
@@ -129,6 +132,7 @@ class ExecutorShutdownTest:
         self.assertFalse(err)
         self.assertEqual(out.strip(), b"apple")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_hang_gh94440(self):
         """shutdown(wait=True) doesn't hang when a future was submitted and
         quickly canceled right before shutdown.
@@ -172,6 +176,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase
         for t in self.executor._threads:
             t.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_context_manager_shutdown(self):
         with futures.ThreadPoolExecutor(max_workers=5) as e:
             executor = e
@@ -181,6 +186,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase
         for t in executor._threads:
             t.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_del_shutdown(self):
         executor = futures.ThreadPoolExecutor(max_workers=5)
         res = executor.map(abs, range(-5, 5))
@@ -194,6 +200,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase
         # executor got shutdown.
         assert all([r == abs(v) for r, v in zip(res, range(-5, 5))])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_shutdown_no_wait(self):
         # Ensure that the executor cleans up the threads when calling
         # shutdown with wait=False
@@ -208,7 +215,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase
         # executor got shutdown.
         assert all([r == abs(v) for r, v in zip(res, range(-5, 5))])
 
-
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_thread_names_assigned(self):
         executor = futures.ThreadPoolExecutor(
             max_workers=5, thread_name_prefix='SpecialPool')
@@ -221,6 +228,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase
             self.assertRegex(t.name, r'^SpecialPool_[0-4]$')
             t.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_thread_names_default(self):
         executor = futures.ThreadPoolExecutor(max_workers=5)
         executor.map(abs, range(-5, 5))
@@ -254,6 +262,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase
 
 
 class ProcessPoolShutdownTest(ExecutorShutdownTest):
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_processes_terminate(self):
         def acquire_lock(lock):
             lock.acquire()
@@ -277,6 +286,7 @@ class ProcessPoolShutdownTest(ExecutorShutdownTest):
         for p in processes.values():
             p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_context_manager_shutdown(self):
         with futures.ProcessPoolExecutor(
                 max_workers=5, mp_context=self.get_context()) as e:
@@ -287,6 +297,7 @@ class ProcessPoolShutdownTest(ExecutorShutdownTest):
         for p in processes.values():
             p.join()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_del_shutdown(self):
         executor = futures.ProcessPoolExecutor(
                 max_workers=5, mp_context=self.get_context())
@@ -309,6 +320,7 @@ class ProcessPoolShutdownTest(ExecutorShutdownTest):
         # executor got shutdown.
         assert all([r == abs(v) for r, v in zip(res, range(-5, 5))])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_shutdown_no_wait(self):
         # Ensure that the executor cleans up the processes when calling
         # shutdown with wait=False
index 4324241b3749676958014963dc5cb4cc721fbe03..226b7acb64fb295e0862d0ebe488b4367e025c9a 100644 (file)
@@ -7,6 +7,7 @@ import threading
 import unittest
 from concurrent import futures
 from test import support
+from test.support import warnings_helper
 
 from .executor import ExecutorTest, mul
 from .util import BaseTestCase, ThreadPoolMixin, setup_module
@@ -53,6 +54,7 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase):
     @support.requires_fork()
     @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork')
     @support.requires_resource('cpu')
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_hang_global_shutdown_lock(self):
         # bpo-45021: _global_shutdown_lock should be reinitialized in the child
         # process, otherwise it will never exit
@@ -68,6 +70,7 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase):
 
     @support.requires_fork()
     @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork')
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_process_fork_from_a_threadpool(self):
         # bpo-43944: clear concurrent.futures.thread._threads_queues after fork,
         # otherwise child process will try to join parent thread
index cc387883141b0eb76e6a4c92de2e6966f404fe3d..b8250cec7ab3e7c49619c54508b9d0197ef7090c 100644 (file)
@@ -3,7 +3,7 @@ import threading
 import unittest
 from concurrent import futures
 from test import support
-from test.support import threading_helper
+from test.support import threading_helper, warnings_helper
 
 from .util import (
     CANCELLED_FUTURE, CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE,
@@ -22,6 +22,7 @@ def wait_and_raise(e):
 
 
 class WaitTests:
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_20369(self):
         # See https://bugs.python.org/issue20369
         future = self.executor.submit(mul, 1, 2)
@@ -30,7 +31,7 @@ class WaitTests:
         self.assertEqual({future}, done)
         self.assertEqual(set(), not_done)
 
-
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_first_completed(self):
         event = self.create_event()
         future1 = self.executor.submit(mul, 21, 2)
@@ -47,6 +48,7 @@ class WaitTests:
             event.set()
         future2.result()  # wait for job to finish
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_first_completed_some_already_completed(self):
         event = self.create_event()
         future1 = self.executor.submit(event.wait)
@@ -64,6 +66,7 @@ class WaitTests:
             event.set()
         future1.result()  # wait for job to finish
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_first_exception(self):
         event1 = self.create_event()
         event2 = self.create_event()
@@ -93,6 +96,7 @@ class WaitTests:
             event2.set()
         future3.result()  # wait for job to finish
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_first_exception_some_already_complete(self):
         event = self.create_event()
         future1 = self.executor.submit(divmod, 21, 0)
@@ -114,6 +118,7 @@ class WaitTests:
             event.set()
         future2.result()  # wait for job to finish
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_first_exception_one_already_failed(self):
         event = self.create_event()
         future1 = self.executor.submit(event.wait)
@@ -129,6 +134,7 @@ class WaitTests:
             event.set()
         future1.result()  # wait for job to finish
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_all_completed(self):
         future1 = self.executor.submit(divmod, 2, 0)
         future2 = self.executor.submit(mul, 2, 21)
@@ -148,6 +154,7 @@ class WaitTests:
                               future2]), finished)
         self.assertEqual(set(), pending)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_timeout(self):
         short_timeout = 0.050
 
index b12940414d9142d26622c1b00e2b551fbd5a43ca..2a9e55152b82d5484c1ea174d5b3c7d341628bb7 100644 (file)
@@ -10,7 +10,7 @@ from concurrent.futures._base import (
 from concurrent.futures.process import _check_system_limits
 
 from test import support
-from test.support import threading_helper
+from test.support import threading_helper, warnings_helper
 
 
 def create_future(state=PENDING, exception=None, result=None):
@@ -51,7 +51,8 @@ class ExecutorMixin:
                 max_workers=self.worker_count,
                 mp_context=self.get_context(),
                 **self.executor_kwargs)
-            self.manager = self.get_context().Manager()
+            with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
+                self.manager = self.get_context().Manager()
         else:
             self.executor = self.executor_type(
                 max_workers=self.worker_count,
index a6523bbc518176946a832ad48e557f0b055ed495..550faa8a174ec626da4c8f3f0e04946184369266 100644 (file)
@@ -11,6 +11,7 @@ import unittest
 
 from test.fork_wait import ForkWait
 from test import support
+from test.support import warnings_helper
 
 
 # Skip test if fork does not exist.
@@ -19,6 +20,7 @@ if not support.has_fork_support:
 
 
 class ForkTest(ForkWait):
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_threaded_import_lock_fork(self):
         """Check fork() in main thread works while a subthread is doing an import"""
         import_started = threading.Event()
@@ -61,7 +63,7 @@ class ForkTest(ForkWait):
             except OSError:
                 pass
 
-
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_nested_import_lock_fork(self):
         """Check fork() in main thread works while the main thread is doing an import"""
         exitcode = 42
index e94edcbc107ba926b95be8dffdada07dbbc1c646..d2ab45c4a5b1ea6bc6842ccad99477268bf4be15 100644 (file)
@@ -9,6 +9,8 @@ from test import support
 import time
 import unittest
 
+from test.support import warnings_helper
+
 if not hasattr(select, "kqueue"):
     raise unittest.SkipTest("test works only on BSD")
 
@@ -257,6 +259,7 @@ class TestKQueue(unittest.TestCase):
         self.addCleanup(kqueue.close)
         self.assertEqual(os.get_inheritable(kqueue.fileno()), False)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_fork()
     def test_fork(self):
         # gh-110395: kqueue objects must be closed after fork
index 275f7ce47d09b5865b8aa9a20eab10c96cc34e0a..7a08f9ec9de9fb8505e840c6d73ee7576a7f7341 100644 (file)
@@ -730,6 +730,7 @@ class HandlerTest(BaseTest):
     # based on os.fork existing because that is what users and this test use.
     # This helps ensure that when fork exists (the important concept) that the
     # register_at_fork mechanism is also present and used.
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_fork()
     @threading_helper.requires_working_threading()
     @skip_if_asan_fork
@@ -4045,6 +4046,7 @@ class ConfigDictTest(BaseTest):
                 self._apply_simple_queue_listener_configuration(qspec)
                 manager.assert_not_called()
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @skip_if_tsan_fork
     @support.requires_subprocess()
     @unittest.skipUnless(support.Py_DEBUG, "requires a debug build for testing"
@@ -4067,6 +4069,7 @@ class ConfigDictTest(BaseTest):
                 with self.assertRaises(ValueError):
                     self._apply_simple_queue_listener_configuration(qspec)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @skip_if_tsan_fork
     @support.requires_subprocess()
     @unittest.skipUnless(support.Py_DEBUG, "requires a debug build for testing"
@@ -4107,6 +4110,7 @@ class ConfigDictTest(BaseTest):
         # log a message (this creates a record put in the queue)
         logging.getLogger().info(message_to_log)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @skip_if_tsan_fork
     @support.requires_subprocess()
     def test_multiprocessing_queues(self):
@@ -5337,6 +5341,7 @@ class LogRecordTest(BaseTest):
         else:
             return results
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @skip_if_tsan_fork
     def test_multiprocessing(self):
         support.skip_if_broken_multiprocessing_synchronize()
index 0169948e453438d76309e3e6767784dee6bc83d6..288b2c4496faa1e4ed774edcc00a7a72856b76e8 100644 (file)
@@ -8,7 +8,7 @@ import re
 import io
 import tempfile
 from test import support
-from test.support import import_helper
+from test.support import import_helper, warnings_helper
 from test.support import os_helper
 from test.support import refleak_helper
 from test.support import socket_helper
@@ -1212,6 +1212,7 @@ class _TestMboxMMDF(_TestSingleFile):
             self.assertEqual(contents, f.read())
         self._box = self._factory(self._path)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_fork()
     @unittest.skipUnless(hasattr(socket, 'socketpair'), "Test needs socketpair().")
     def test_lock_conflict(self):
index de3a17fe893170aa6388be6884154352940ca19e..9827a7f12ea21d63f7c33868ad521aafced1993a 100644 (file)
@@ -3518,6 +3518,7 @@ class PidTests(unittest.TestCase):
         self.assertEqual(error, b'')
         self.assertEqual(int(stdout), os.getpid())
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def check_waitpid(self, code, exitcode, callback=None):
         if sys.platform == 'win32':
             # On Windows, os.spawnv() simply joins arguments with spaces:
@@ -3620,30 +3621,35 @@ class SpawnTests(unittest.TestCase):
 
         return program, args
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnl')
     def test_spawnl(self):
         program, args = self.create_args()
         exitcode = os.spawnl(os.P_WAIT, program, *args)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnle')
     def test_spawnle(self):
         program, args = self.create_args(with_env=True)
         exitcode = os.spawnle(os.P_WAIT, program, *args, self.env)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnlp')
     def test_spawnlp(self):
         program, args = self.create_args()
         exitcode = os.spawnlp(os.P_WAIT, program, *args)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnlpe')
     def test_spawnlpe(self):
         program, args = self.create_args(with_env=True)
         exitcode = os.spawnlpe(os.P_WAIT, program, *args, self.env)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnv')
     def test_spawnv(self):
         program, args = self.create_args()
@@ -3654,30 +3660,35 @@ class SpawnTests(unittest.TestCase):
         exitcode = os.spawnv(os.P_WAIT, FakePath(program), args)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnve')
     def test_spawnve(self):
         program, args = self.create_args(with_env=True)
         exitcode = os.spawnve(os.P_WAIT, program, args, self.env)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnvp')
     def test_spawnvp(self):
         program, args = self.create_args()
         exitcode = os.spawnvp(os.P_WAIT, program, args)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnvpe')
     def test_spawnvpe(self):
         program, args = self.create_args(with_env=True)
         exitcode = os.spawnvpe(os.P_WAIT, program, args, self.env)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnv')
     def test_nowait(self):
         program, args = self.create_args()
         pid = os.spawnv(os.P_NOWAIT, program, args)
         support.wait_process(pid, exitcode=self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnve')
     def test_spawnve_bytes(self):
         # Test bytes handling in parse_arglist and parse_envlist (#28114)
@@ -3685,18 +3696,21 @@ class SpawnTests(unittest.TestCase):
         exitcode = os.spawnve(os.P_WAIT, program, args, self.env)
         self.assertEqual(exitcode, self.exitcode)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnl')
     def test_spawnl_noargs(self):
         program, __ = self.create_args()
         self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, program)
         self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, program, '')
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnle')
     def test_spawnle_noargs(self):
         program, __ = self.create_args()
         self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, program, {})
         self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, program, '', {})
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnv')
     def test_spawnv_noargs(self):
         program, __ = self.create_args()
@@ -3705,6 +3719,7 @@ class SpawnTests(unittest.TestCase):
         self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ('',))
         self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, [''])
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnve')
     def test_spawnve_noargs(self):
         program, __ = self.create_args()
@@ -3761,10 +3776,12 @@ class SpawnTests(unittest.TestCase):
         exitcode = spawn(os.P_WAIT, program, args, newenv)
         self.assertEqual(exitcode, 0)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnve')
     def test_spawnve_invalid_env(self):
         self._test_invalid_env(os.spawnve)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_os_func('spawnvpe')
     def test_spawnvpe_invalid_env(self):
         self._test_invalid_env(os.spawnvpe)
@@ -4881,6 +4898,7 @@ class PseudoterminalTests(unittest.TestCase):
         self.addCleanup(os.close, son_fd)
         self.assertEqual(os.ptsname(mother_fd), os.ttyname(son_fd))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(hasattr(os, 'spawnl'), "need os.spawnl()")
     @support.requires_subprocess()
     def test_pipe_spawnl(self):
index 479649053abc01616d54068c0ee286f1f032b97c..2e26134bae83231c59c20b155e2ab6083b659c2a 100644 (file)
@@ -11,7 +11,7 @@ import unittest
 from unittest import mock
 
 from test import support
-from test.support import os_helper
+from test.support import os_helper, warnings_helper
 
 try:
     # Some of the iOS tests need ctypes to operate.
@@ -465,7 +465,7 @@ class PlatformTest(unittest.TestCase):
             else:
                 self.assertEqual(res[2], 'PowerPC')
 
-
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(sys.platform == 'darwin', "OSX only test")
     def test_mac_ver_with_fork(self):
         # Issue7895: platform.mac_ver() crashes when using fork without exec
index ed4fe8a140879dff109af8f560fa23a80c348732..fbba7025ac4abfd6461e98e4fe78b08a18fa963d 100644 (file)
@@ -1,6 +1,6 @@
 import unittest
 from test.support import (
-    is_android, is_apple_mobile, is_wasm32, reap_children, verbose
+    is_android, is_apple_mobile, is_wasm32, reap_children, verbose, warnings_helper
 )
 from test.support.import_helper import import_module
 from test.support.os_helper import TESTFN, unlink
@@ -194,6 +194,7 @@ class PtyTest(unittest.TestCase):
         s2 = _readline(master_fd)
         self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_fork(self):
         debug("calling pty.fork()")
         pid, master_fd = pty.fork()
@@ -295,6 +296,7 @@ class PtyTest(unittest.TestCase):
 
         self.assertEqual(data, b"")
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     def test_spawn_doesnt_hang(self):
         self.addCleanup(unlink, TESTFN)
         with open(TESTFN, 'wb') as f:
index 0217ebd132b1104f8053a331002f81c719ceecee..1e57b9244b4fd54148d0d2a529ddd0e7bf0e99b8 100644 (file)
@@ -14,6 +14,8 @@ from test import support
 from fractions import Fraction
 from collections import abc, Counter
 
+from test.support import warnings_helper
+
 
 class MyIndex:
     def __init__(self, value):
@@ -1399,6 +1401,7 @@ class TestModule(unittest.TestCase):
         # tests validity but not completeness of the __all__ list
         self.assertTrue(set(random.__all__) <= set(dir(random)))
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @test.support.requires_fork()
     def test_after_fork(self):
         # Test the global Random instance gets reseeded in child
index 0f62f9eb200e42ddb4303fadc675e78b5b8f66bc..893372cbbd0be9064cc8d25a54ebe4fafb2bdadb 100644 (file)
@@ -17,6 +17,7 @@ from test.support import reap_children, verbose
 from test.support import os_helper
 from test.support import socket_helper
 from test.support import threading_helper
+from test.support import warnings_helper
 
 
 test.support.requires("network")
@@ -43,6 +44,7 @@ def receive(sock, n, timeout=test.support.SHORT_TIMEOUT):
         raise RuntimeError("timed out on %r" % (sock,))
 
 
+@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
 @test.support.requires_fork()
 @contextlib.contextmanager
 def simple_subprocess(testcase):
@@ -173,6 +175,7 @@ class SocketServerTest(unittest.TestCase):
                         socketserver.StreamRequestHandler,
                         self.stream_examine)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_forking
     def test_ForkingTCPServer(self):
         with simple_subprocess(self):
@@ -192,6 +195,7 @@ class SocketServerTest(unittest.TestCase):
                         socketserver.StreamRequestHandler,
                         self.stream_examine)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_unix_sockets
     @requires_forking
     def test_ForkingUnixStreamServer(self):
@@ -210,6 +214,7 @@ class SocketServerTest(unittest.TestCase):
                         socketserver.DatagramRequestHandler,
                         self.dgram_examine)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_forking
     def test_ForkingUDPServer(self):
         with simple_subprocess(self):
@@ -229,6 +234,7 @@ class SocketServerTest(unittest.TestCase):
                         socketserver.DatagramRequestHandler,
                         self.dgram_examine)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_unix_sockets
     @requires_forking
     def test_ForkingUnixDatagramServer(self):
@@ -314,11 +320,13 @@ class ErrorHandlerTest(unittest.TestCase):
 
             self.assertIs(cm.exc_type, SystemExit)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_forking
     def test_forking_handled(self):
         ForkingErrorTestServer(ValueError)
         self.check_result(handled=True)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @requires_forking
     def test_forking_not_handled(self):
         ForkingErrorTestServer(SystemExit)
index 9ec382afb65fe42df79daf35f4072f1796511825..12361aa4e518a605617db178946ae45d4a03d1eb 100644 (file)
@@ -485,6 +485,7 @@ class TestSupport(unittest.TestCase):
 
         self.assertRaises(AssertionError, support.check__all__, self, unittest)
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'),
                          'need os.waitpid() and os.WNOHANG')
     @support.requires_fork()
index 6dc6880ff8c356a6fa3a8a541e1bafc579119fc1..9d3ff8a620b6f26fa02bf3cf6b2108aa37c4c0e0 100644 (file)
@@ -8,7 +8,7 @@ from unittest.mock import patch
 from test.support.script_helper import (assert_python_ok, assert_python_failure,
                                         interpreter_requires_environment)
 from test import support
-from test.support import force_not_colorized
+from test.support import force_not_colorized, warnings_helper
 from test.support import os_helper
 from test.support import threading_helper
 
@@ -354,6 +354,7 @@ class TestTracemallocEnabled(unittest.TestCase):
         # everything is fine
         return 0
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_fork()
     def test_fork(self):
         # check that tracemalloc is still working after fork
index 0e1a723ce3a15104cce73c78e35b4d9679d51349..edce504fc4ba65a273be2be254e1497b9a9d516b 100755 (executable)
@@ -13,7 +13,7 @@ from itertools import product
 from unittest import mock
 
 from test import support
-from test.support import import_helper
+from test.support import import_helper, warnings_helper
 from test.support.script_helper import assert_python_ok
 
 py_uuid = import_helper.import_fresh_module('uuid', blocked=['_uuid'])
@@ -1112,6 +1112,7 @@ class BaseTestUUID:
         versions = {u.version for u in uuids}
         self.assertSetEqual(versions, {8})
 
+    @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
     @support.requires_fork()
     def testIssue8621(self):
         # On at least some versions of OSX self.uuid.uuid4 generates
diff --git a/Misc/NEWS.d/next/Library/2025-07-19-11-53-19.gh-issue-135427.iJM_X2.rst b/Misc/NEWS.d/next/Library/2025-07-19-11-53-19.gh-issue-135427.iJM_X2.rst
new file mode 100644 (file)
index 0000000..a14aa84
--- /dev/null
@@ -0,0 +1,4 @@
+With :option:`-Werror <-W>`, the DeprecationWarning emitted by :py:func:`os.fork`
+and :py:func:`os.forkpty` in mutli-threaded processes is now raised as an exception.
+Previously it was silently ignored.
+Patch by Rani Pinchuk.
index d9753a654685fffa69a0669b4e7f8d808a400bf8..db18e868661edd75e3b57c09d115d3f21abcb9ab 100644 (file)
@@ -8000,7 +8000,7 @@ os_register_at_fork_impl(PyObject *module, PyObject *before,
 //
 // This should only be called from the parent process after
 // PyOS_AfterFork_Parent().
-static void
+static int
 warn_about_fork_with_threads(const char* name)
 {
     // It's not safe to issue the warning while the world is stopped, because
@@ -8051,14 +8051,14 @@ warn_about_fork_with_threads(const char* name)
         PyObject *threading = PyImport_GetModule(&_Py_ID(threading));
         if (!threading) {
             PyErr_Clear();
-            return;
+            return 0;
         }
         PyObject *threading_active =
                 PyObject_GetAttr(threading, &_Py_ID(_active));
         if (!threading_active) {
             PyErr_Clear();
             Py_DECREF(threading);
-            return;
+            return 0;
         }
         PyObject *threading_limbo =
                 PyObject_GetAttr(threading, &_Py_ID(_limbo));
@@ -8066,7 +8066,7 @@ warn_about_fork_with_threads(const char* name)
             PyErr_Clear();
             Py_DECREF(threading);
             Py_DECREF(threading_active);
-            return;
+            return 0;
         }
         Py_DECREF(threading);
         // Duplicating what threading.active_count() does but without holding
@@ -8082,7 +8082,7 @@ warn_about_fork_with_threads(const char* name)
         Py_DECREF(threading_limbo);
     }
     if (num_python_threads > 1) {
-        PyErr_WarnFormat(
+        return PyErr_WarnFormat(
                 PyExc_DeprecationWarning, 1,
 #ifdef HAVE_GETPID
                 "This process (pid=%d) is multi-threaded, "
@@ -8094,8 +8094,8 @@ warn_about_fork_with_threads(const char* name)
                 getpid(),
 #endif
                 name);
-        PyErr_Clear();
     }
+    return 0;
 }
 #endif  // HAVE_FORK1 || HAVE_FORKPTY || HAVE_FORK
 
@@ -8134,7 +8134,9 @@ os_fork1_impl(PyObject *module)
         /* parent: release the import lock. */
         PyOS_AfterFork_Parent();
         // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
-        warn_about_fork_with_threads("fork1");
+        if (warn_about_fork_with_threads("fork1") < 0) {
+            return NULL;
+        }
     }
     if (pid == -1) {
         errno = saved_errno;
@@ -8183,7 +8185,8 @@ os_fork_impl(PyObject *module)
         /* parent: release the import lock. */
         PyOS_AfterFork_Parent();
         // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
-        warn_about_fork_with_threads("fork");
+        if (warn_about_fork_with_threads("fork") < 0)
+            return NULL;
     }
     if (pid == -1) {
         errno = saved_errno;
@@ -9040,7 +9043,8 @@ os_forkpty_impl(PyObject *module)
         /* parent: release the import lock. */
         PyOS_AfterFork_Parent();
         // After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
-        warn_about_fork_with_threads("forkpty");
+        if (warn_about_fork_with_threads("forkpty") < 0)
+            return NULL;
     }
     if (pid == -1) {
         return posix_error();