From 0e65c2bb7109e74da6d0fcf987efb0b7da95eacb Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 22 Jun 2025 18:57:45 +0900 Subject: [PATCH 1/3] Start process from spawn context in multiprocessing no longer have side effect --- Lib/multiprocessing/spawn.py | 2 +- Lib/test/_test_multiprocessing.py | 16 ++++++++++++++++ ...025-06-22-18-57-19.gh-issue-109263.f92V95.rst | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-06-22-18-57-19.gh-issue-109263.f92V95.rst diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py index daac1ecc34b55e..d43864c939cb63 100644 --- a/Lib/multiprocessing/spawn.py +++ b/Lib/multiprocessing/spawn.py @@ -184,7 +184,7 @@ def get_preparation_data(name): sys_argv=sys.argv, orig_dir=process.ORIGINAL_DIR, dir=os.getcwd(), - start_method=get_start_method(), + start_method=get_start_method(allow_none=True), ) # Figure out whether to initialise main in the subprocess as a module diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index a1259ff1d63d18..3ce3510f730f4c 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5823,6 +5823,22 @@ def test_context(self): self.assertRaises(ValueError, ctx.set_start_method, None) self.check_context(ctx) + @staticmethod + def _dummy_func(): + pass + + def test_spawn_dont_set_context(self): + # Run a process with spawn or forkserver context may change + # the global start method, see gh-109263. + for method in ('fork', 'spawn', 'forkserver'): + multiprocessing.set_start_method(None, force=True) + + context = multiprocessing.get_context(method) + process = context.Process(target=self._dummy_func) + process.start() + process.join() + self.assertIsNone(multiprocessing.get_start_method(allow_none=True)) + def test_context_check_module_types(self): try: ctx = multiprocessing.get_context('forkserver') diff --git a/Misc/NEWS.d/next/Library/2025-06-22-18-57-19.gh-issue-109263.f92V95.rst b/Misc/NEWS.d/next/Library/2025-06-22-18-57-19.gh-issue-109263.f92V95.rst new file mode 100644 index 00000000000000..6b96b5b9b2a0de --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-22-18-57-19.gh-issue-109263.f92V95.rst @@ -0,0 +1,2 @@ +Starting a process from spawn context in :mod:`multiprocessing` no longer +sets the start method globally. From 82e787d77a201ab69e97521c76b2f450c894f4cc Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 22 Jun 2025 21:45:47 +0900 Subject: [PATCH 2/3] Fix test on Windows --- Lib/test/_test_multiprocessing.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 3ce3510f730f4c..26c3ec75656a70 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5833,8 +5833,11 @@ def test_spawn_dont_set_context(self): for method in ('fork', 'spawn', 'forkserver'): multiprocessing.set_start_method(None, force=True) - context = multiprocessing.get_context(method) - process = context.Process(target=self._dummy_func) + try: + ctx = multiprocessing.get_context(method) + except ValueError: + continue + process = ctx .Process(target=self._dummy_func) process.start() process.join() self.assertIsNone(multiprocessing.get_start_method(allow_none=True)) From 980ba9279330330cdc597164b9fa7d5a2cbd14b2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 3 Sep 2025 14:48:47 +0300 Subject: [PATCH 3/3] Silence deprecation warnings. --- Lib/test/_test_multiprocessing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index a5147d49716530..7a08791fde364c 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5936,6 +5936,7 @@ def test_context(self): def _dummy_func(): pass + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() def test_spawn_dont_set_context(self): # Run a process with spawn or forkserver context may change # the global start method, see gh-109263. @@ -5946,7 +5947,7 @@ def test_spawn_dont_set_context(self): ctx = multiprocessing.get_context(method) except ValueError: continue - process = ctx .Process(target=self._dummy_func) + process = ctx.Process(target=self._dummy_func) process.start() process.join() self.assertIsNone(multiprocessing.get_start_method(allow_none=True))