[Python-checkins] bpo-46720: Add support for path-like objects to multiprocessing.set_executable for Windows (GH-31279)

brettcannon webhook-mailer at python.org
Fri Apr 22 18:47:18 EDT 2022


https://github.com/python/cpython/commit/5576ddbbbc9c1d7a7819abc961e5d604ae0f7dd7
commit: 5576ddbbbc9c1d7a7819abc961e5d604ae0f7dd7
branch: main
author: Géry Ogam <gery.ogam at gmail.com>
committer: brettcannon <brett at python.org>
date: 2022-04-22T15:47:09-07:00
summary:

bpo-46720: Add support for path-like objects to multiprocessing.set_executable for Windows (GH-31279)

This bring the API to be on a par with Unix-like systems.

files:
A Misc/NEWS.d/next/Library/2022-02-11-23-11-35.bpo-46720.nY8spB.rst
M Doc/library/multiprocessing.rst
M Lib/multiprocessing/spawn.py
M Lib/multiprocessing/util.py
M Lib/test/_test_multiprocessing.py

diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
index 83aa5cb87f49f..70802ee1fdecb 100644
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -1075,6 +1075,9 @@ Miscellaneous
    .. versionchanged:: 3.4
       Now supported on Unix when the ``'spawn'`` start method is used.
 
+   .. versionchanged:: 3.11
+      Accepts a :term:`path-like object`.
+
 .. function:: set_start_method(method)
 
    Set the method which should be used to start child processes.
diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py
index 7cc129e261076..09f8a229d7ccc 100644
--- a/Lib/multiprocessing/spawn.py
+++ b/Lib/multiprocessing/spawn.py
@@ -33,18 +33,21 @@
     WINEXE = getattr(sys, 'frozen', False)
     WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
 
-if WINSERVICE:
-    _python_exe = os.path.join(sys.exec_prefix, 'python.exe')
-else:
-    _python_exe = sys.executable
-
 def set_executable(exe):
     global _python_exe
-    _python_exe = exe
+    if sys.platform == 'win32':
+        _python_exe = os.fsdecode(exe)
+    else:
+        _python_exe = os.fsencode(exe)
 
 def get_executable():
     return _python_exe
 
+if WINSERVICE:
+    set_executable(os.path.join(sys.exec_prefix, 'python.exe'))
+else:
+    set_executable(sys.executable)
+
 #
 #
 #
@@ -86,7 +89,8 @@ def get_command_line(**kwds):
         prog = 'from multiprocessing.spawn import spawn_main; spawn_main(%s)'
         prog %= ', '.join('%s=%r' % item for item in kwds.items())
         opts = util._args_from_interpreter_flags()
-        return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork']
+        exe = get_executable()
+        return [exe] + opts + ['-c', prog, '--multiprocessing-fork']
 
 
 def spawn_main(pipe_handle, parent_pid=None, tracker_fd=None):
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
index a4683339820f5..abbc4c5e6088b 100644
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -450,7 +450,7 @@ def spawnv_passfds(path, args, passfds):
     errpipe_read, errpipe_write = os.pipe()
     try:
         return _posixsubprocess.fork_exec(
-            args, [os.fsencode(path)], True, passfds, None, None,
+            args, [path], True, passfds, None, None,
             -1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
             False, False, None, None, None, -1, None)
     finally:
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 427fc0c47a3ca..67bb17c0ede36 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -20,6 +20,7 @@
 import subprocess
 import struct
 import operator
+import pathlib
 import pickle
 import weakref
 import warnings
@@ -256,6 +257,21 @@ def test_current(self):
         self.assertEqual(current.ident, os.getpid())
         self.assertEqual(current.exitcode, None)
 
+    def test_set_executable(self):
+        if self.TYPE == 'threads':
+            self.skipTest(f'test not appropriate for {self.TYPE}')
+        paths = [
+            sys.executable,               # str
+            sys.executable.encode(),      # bytes
+            pathlib.Path(sys.executable)  # os.PathLike
+        ]
+        for path in paths:
+            self.set_executable(path)
+            p = self.Process()
+            p.start()
+            p.join()
+            self.assertEqual(p.exitcode, 0)
+
     def test_args_argument(self):
         # bpo-45735: Using list or tuple as *args* in constructor could
         # achieve the same effect.
@@ -5787,6 +5803,7 @@ class ProcessesMixin(BaseMixin):
     current_process = staticmethod(multiprocessing.current_process)
     parent_process = staticmethod(multiprocessing.parent_process)
     active_children = staticmethod(multiprocessing.active_children)
+    set_executable = staticmethod(multiprocessing.set_executable)
     Pool = staticmethod(multiprocessing.Pool)
     Pipe = staticmethod(multiprocessing.Pipe)
     Queue = staticmethod(multiprocessing.Queue)
diff --git a/Misc/NEWS.d/next/Library/2022-02-11-23-11-35.bpo-46720.nY8spB.rst b/Misc/NEWS.d/next/Library/2022-02-11-23-11-35.bpo-46720.nY8spB.rst
new file mode 100644
index 0000000000000..70d5e5ef34333
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-02-11-23-11-35.bpo-46720.nY8spB.rst
@@ -0,0 +1,2 @@
+Add support for path-like objects to :func:`multiprocessing.set_executable` for
+Windows to be on a par with Unix-like systems. Patch by Géry Ogam.



More information about the Python-checkins mailing list