Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a8474d0

Browse files
authored
bpo-35872 and bpo-35873: Clears __PYVENV_LAUNCHER__ variable (GH-11745)
After reading __PYVENV_LAUNCHER__ we now set sys._base_executable value for later use. Make the same changes for macOS to avoid extra platform checks.
1 parent 2f6fae6 commit a8474d0

7 files changed

Lines changed: 33 additions & 23 deletions

File tree

Lib/multiprocessing/popen_spawn_win32.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
2020

2121

22+
def _path_eq(p1, p2):
23+
return p1 == p2 or os.path.normcase(p1) == os.path.normcase(p2)
24+
25+
WINENV = (hasattr(sys, '_base_executable') and
26+
not _path_eq(sys.executable, sys._base_executable))
27+
28+
2229
def _close_handles(*handles):
2330
for handle in handles:
2431
_winapi.CloseHandle(handle)
@@ -50,12 +57,23 @@ def __init__(self, process_obj):
5057
pipe_handle=rhandle)
5158
cmd = ' '.join('"%s"' % x for x in cmd)
5259

60+
python_exe = spawn.get_executable()
61+
62+
# bpo-35797: When running in a venv, we bypass the redirect
63+
# executor and launch our base Python.
64+
if WINENV and _path_eq(python_exe, sys.executable):
65+
python_exe = sys._base_executable
66+
env = os.environ.copy()
67+
env["__PYVENV_LAUNCHER__"] = sys.executable
68+
else:
69+
env = None
70+
5371
with open(wfd, 'wb', closefd=True) as to_child:
5472
# start process
5573
try:
5674
hp, ht, pid, tid = _winapi.CreateProcess(
57-
spawn.get_executable(), cmd,
58-
None, None, False, 0, None, None, None)
75+
python_exe, cmd,
76+
env, None, False, 0, None, None, None)
5977
_winapi.CloseHandle(ht)
6078
except:
6179
_winapi.CloseHandle(rhandle)

Lib/multiprocessing/spawn.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,12 @@
2929
if sys.platform != 'win32':
3030
WINEXE = False
3131
WINSERVICE = False
32-
_WINENV = False
3332
else:
3433
WINEXE = getattr(sys, 'frozen', False)
3534
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
36-
_WINENV = '__PYVENV_LAUNCHER__' in os.environ
3735

3836
if WINSERVICE:
3937
_python_exe = os.path.join(sys.exec_prefix, 'python.exe')
40-
elif _WINENV:
41-
# bpo-35797: When running in a venv, we need to bypass the redirect
42-
# executor and launch our base Python.
43-
import _winapi
44-
_python_exe = _winapi.GetModuleFileName(0)
4538
else:
4639
_python_exe = sys.executable
4740

Lib/site.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,14 @@ def venv(known_paths):
457457

458458
env = os.environ
459459
if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
460-
executable = os.environ['__PYVENV_LAUNCHER__']
460+
executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__']
461+
elif sys.platform == 'win32' and '__PYVENV_LAUNCHER__' in env:
462+
executable = sys.executable
463+
import _winapi
464+
sys._base_executable = _winapi.GetModuleFileName(0)
465+
# bpo-35873: Clear the environment variable to avoid it being
466+
# inherited by child processes.
467+
del os.environ['__PYVENV_LAUNCHER__']
461468
else:
462469
executable = sys.executable
463470
exe_dir, _ = os.path.split(os.path.abspath(executable))

Lib/test/test_venv.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,7 @@ def setUp(self):
5252
self.bindir = 'bin'
5353
self.lib = ('lib', 'python%d.%d' % sys.version_info[:2])
5454
self.include = 'include'
55-
if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in os.environ:
56-
executable = os.environ['__PYVENV_LAUNCHER__']
57-
else:
58-
executable = sys.executable
55+
executable = getattr(sys, '_base_executable', sys.executable)
5956
self.exe = os.path.split(executable)[-1]
6057

6158
def tearDown(self):
@@ -100,11 +97,7 @@ def test_defaults(self):
10097
else:
10198
self.assertFalse(os.path.exists(p))
10299
data = self.get_text_file_contents('pyvenv.cfg')
103-
if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__'
104-
in os.environ):
105-
executable = os.environ['__PYVENV_LAUNCHER__']
106-
else:
107-
executable = sys.executable
100+
executable = getattr(sys, '_base_executable', sys.executable)
108101
path = os.path.dirname(executable)
109102
self.assertIn('home = %s' % path, data)
110103
fn = self.get_env_file(self.bindir, self.exe)

Lib/venv/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,7 @@ def create_if_needed(d):
106106
context.prompt = '(%s) ' % prompt
107107
create_if_needed(env_dir)
108108
env = os.environ
109-
if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
110-
executable = os.environ['__PYVENV_LAUNCHER__']
111-
else:
112-
executable = sys.executable
109+
executable = getattr(sys, '_base_executable', sys.executable)
113110
dirname, exename = os.path.split(os.path.abspath(executable))
114111
context.executable = executable
115112
context.python_dir = dirname
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prevents venv paths being inherited by child processes
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Uses the base Python executable when invoking venv in a virtual environment

0 commit comments

Comments
 (0)