Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Lib/multiprocessing/popen_spawn_win32.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,20 @@ def __init__(self, process_obj):
wfd = msvcrt.open_osfhandle(whandle, 0)
cmd = spawn.get_command_line(parent_pid=os.getpid(),
pipe_handle=rhandle)
cmd = ' '.join('"%s"' % x for x in cmd)

python_exe = spawn.get_executable()

# bpo-35797: When running in a venv, we bypass the redirect
# executor and launch our base Python.
if WINENV and _path_eq(python_exe, sys.executable):
python_exe = sys._base_executable
cmd[0] = python_exe = sys._base_executable
env = os.environ.copy()
env["__PYVENV_LAUNCHER__"] = sys.executable
else:
env = None

cmd = ' '.join('"%s"' % x for x in cmd)

with open(wfd, 'wb', closefd=True) as to_child:
# start process
try:
Expand Down
40 changes: 40 additions & 0 deletions Lib/test/_test_venv_multiprocessing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import multiprocessing
import random
import sys
import time

def fill_queue(queue, code):
queue.put(code)


def drain_queue(queue, code):
if code != queue.get():
sys.exit(1)


def test_func():
code = random.randrange(0, 1000)
queue = multiprocessing.Queue()
fill_pool = multiprocessing.Process(
target=fill_queue,
args=(queue, code)
)
drain_pool = multiprocessing.Process(
target=drain_queue,
args=(queue, code)
)
drain_pool.start()
fill_pool.start()
fill_pool.join()
drain_pool.join()


def main():
test_pool = multiprocessing.Process(target=test_func)
test_pool.start()
test_pool.join()
sys.exit(test_pool.exitcode)


if __name__ == "__main__":
main()
16 changes: 15 additions & 1 deletion Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from test.support import (captured_stdout, captured_stderr, requires_zlib,
skip_if_broken_multiprocessing_synchronize, verbose,
requires_subprocess, is_emscripten, is_wasi,
requires_venv_with_pip)
requires_venv_with_pip, TEST_HOME_DIR)
from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree)
import unittest
import venv
Expand Down Expand Up @@ -482,6 +482,20 @@ def test_multiprocessing(self):
'pool.terminate()'])
self.assertEqual(out.strip(), "python".encode())

@requireVenvCreate
def test_multiprocessing_recursion(self):
"""
Test that the multiprocessing is able to spawn itself
"""
skip_if_broken_multiprocessing_synchronize()

rmtree(self.env_dir)
self.run_with_capture(venv.create, self.env_dir)
envpy = os.path.join(os.path.realpath(self.env_dir),
self.bindir, self.exe)
script = os.path.join(TEST_HOME_DIR, '_test_venv_multiprocessing.py')
subprocess.check_call([envpy, script])

@unittest.skipIf(os.name == 'nt', 'not relevant on Windows')
def test_deactivate_with_strict_bash_opts(self):
bash = shutil.which("bash")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fixes :mod:`multiprocessing` spawning child processes on Windows from a
virtual environment to ensure that child processes that also use
:mod:`multiprocessing` to spawn more children will recognize that they are
in a virtual environment.