Skip to content

Commit 2e6bc39

Browse files
CPython developersyouknowone
authored andcommitted
update venv from CPython 3.10.5
1 parent b7dd1b7 commit 2e6bc39

File tree

8 files changed

+94
-31
lines changed

8 files changed

+94
-31
lines changed

Lib/test/test_venv.py

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
Licensed to the PSF under a contributor agreement.
66
"""
77

8-
# pip isn't working yet
9-
# import ensurepip
8+
import ensurepip
109
import os
1110
import os.path
1211
import re
@@ -15,12 +14,12 @@
1514
import subprocess
1615
import sys
1716
import tempfile
18-
from test.support import captured_stdout, captured_stderr, requires_zlib
17+
from test.support import (captured_stdout, captured_stderr, requires_zlib,
18+
skip_if_broken_multiprocessing_synchronize)
1919
from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree)
20-
from test.support.import_helper import import_module
21-
import threading
2220
import unittest
2321
import venv
22+
from unittest.mock import patch
2423

2524
try:
2625
import ctypes
@@ -80,8 +79,8 @@ def run_with_capture(self, func, *args, **kwargs):
8079
def get_env_file(self, *args):
8180
return os.path.join(self.env_dir, *args)
8281

83-
def get_text_file_contents(self, *args):
84-
with open(self.get_env_file(*args), 'r') as f:
82+
def get_text_file_contents(self, *args, encoding='utf-8'):
83+
with open(self.get_env_file(*args), 'r', encoding=encoding) as f:
8584
result = f.read()
8685
return result
8786

@@ -139,6 +138,45 @@ def test_prompt(self):
139138
self.assertEqual(context.prompt, '(My prompt) ')
140139
self.assertIn("prompt = 'My prompt'\n", data)
141140

141+
rmtree(self.env_dir)
142+
builder = venv.EnvBuilder(prompt='.')
143+
cwd = os.path.basename(os.getcwd())
144+
self.run_with_capture(builder.create, self.env_dir)
145+
context = builder.ensure_directories(self.env_dir)
146+
data = self.get_text_file_contents('pyvenv.cfg')
147+
self.assertEqual(context.prompt, '(%s) ' % cwd)
148+
self.assertIn("prompt = '%s'\n" % cwd, data)
149+
150+
def test_upgrade_dependencies(self):
151+
builder = venv.EnvBuilder()
152+
bin_path = 'Scripts' if sys.platform == 'win32' else 'bin'
153+
python_exe = os.path.split(sys.executable)[1]
154+
with tempfile.TemporaryDirectory() as fake_env_dir:
155+
expect_exe = os.path.normcase(
156+
os.path.join(fake_env_dir, bin_path, python_exe)
157+
)
158+
if sys.platform == 'win32':
159+
expect_exe = os.path.normcase(os.path.realpath(expect_exe))
160+
161+
def pip_cmd_checker(cmd):
162+
cmd[0] = os.path.normcase(cmd[0])
163+
self.assertEqual(
164+
cmd,
165+
[
166+
expect_exe,
167+
'-m',
168+
'pip',
169+
'install',
170+
'--upgrade',
171+
'pip',
172+
'setuptools'
173+
]
174+
)
175+
176+
fake_context = builder.ensure_directories(fake_env_dir)
177+
with patch('venv.subprocess.check_call', pip_cmd_checker):
178+
builder.upgrade_dependencies(fake_context)
179+
142180
@requireVenvCreate
143181
def test_prefixes(self):
144182
"""
@@ -325,10 +363,11 @@ def test_multiprocessing(self):
325363
"""
326364
Test that the multiprocessing is able to spawn.
327365
"""
328-
# Issue bpo-36342: Instanciation of a Pool object imports the
366+
# bpo-36342: Instantiation of a Pool object imports the
329367
# multiprocessing.synchronize module. Skip the test if this module
330368
# cannot be imported.
331-
import_module('multiprocessing.synchronize')
369+
skip_if_broken_multiprocessing_synchronize()
370+
332371
rmtree(self.env_dir)
333372
self.run_with_capture(venv.create, self.env_dir)
334373
envpy = os.path.join(os.path.realpath(self.env_dir),
@@ -413,7 +452,7 @@ def do_test_with_pip(self, system_site_packages):
413452
# pip's cross-version compatibility may trigger deprecation
414453
# warnings in current versions of Python. Ensure related
415454
# environment settings don't cause venv to fail.
416-
envvars["PYTHONWARNINGS"] = "e"
455+
envvars["PYTHONWARNINGS"] = "ignore"
417456
# ensurepip is different enough from a normal pip invocation
418457
# that we want to ensure it ignores the normal pip environment
419458
# variable settings. We set PIP_NO_INSTALL here specifically
@@ -452,7 +491,8 @@ def do_test_with_pip(self, system_site_packages):
452491
# Ensure pip is available in the virtual environment
453492
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
454493
# Ignore DeprecationWarning since pip code is not part of Python
455-
out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning', '-I',
494+
out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning',
495+
'-W', 'ignore::ImportWarning', '-I',
456496
'-m', 'pip', '--version'])
457497
# We force everything to text, so unittest gives the detailed diff
458498
# if we get unexpected results
@@ -468,8 +508,12 @@ def do_test_with_pip(self, system_site_packages):
468508
# Check the private uninstall command provided for the Windows
469509
# installers works (at least in a virtual environment)
470510
with EnvironmentVarGuard() as envvars:
511+
# It seems ensurepip._uninstall calls subprocesses which do not
512+
# inherit the interpreter settings.
513+
envvars["PYTHONWARNINGS"] = "ignore"
471514
out, err = check_output([envpy,
472-
'-W', 'ignore::DeprecationWarning', '-I',
515+
'-W', 'ignore::DeprecationWarning',
516+
'-W', 'ignore::ImportWarning', '-I',
473517
'-m', 'ensurepip._uninstall'])
474518
# We force everything to text, so unittest gives the detailed diff
475519
# if we get unexpected results
@@ -481,7 +525,7 @@ def do_test_with_pip(self, system_site_packages):
481525
# executing pip with sudo, you may want sudo's -H flag."
482526
# where $HOME is replaced by the HOME environment variable.
483527
err = re.sub("^(WARNING: )?The directory .* or its parent directory "
484-
"is not owned by the current user .*$", "",
528+
"is not owned or is not writable by the current user.*$", "",
485529
err, flags=re.MULTILINE)
486530
self.assertEqual(err.rstrip(), "")
487531
# Being fairly specific regarding the expected behaviour for the
@@ -497,10 +541,8 @@ def do_test_with_pip(self, system_site_packages):
497541
self.assert_pip_not_installed()
498542

499543
# Issue #26610: pip/pep425tags.py requires ctypes
500-
# TODO: RUSTPYTHON
501544
@unittest.skipUnless(ctypes, 'pip requires ctypes')
502-
@requires_zlib
503-
@unittest.expectedFailure
545+
@requires_zlib()
504546
def test_with_pip(self):
505547
self.do_test_with_pip(False)
506548
self.do_test_with_pip(True)

Lib/venv/__init__.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,20 @@ def create_if_needed(d):
142142
context.bin_name = binname
143143
context.env_exe = os.path.join(binpath, exename)
144144
create_if_needed(binpath)
145+
# Assign and update the command to use when launching the newly created
146+
# environment, in case it isn't simply the executable script (e.g. bpo-45337)
147+
context.env_exec_cmd = context.env_exe
148+
if sys.platform == 'win32':
149+
# bpo-45337: Fix up env_exec_cmd to account for file system redirections.
150+
# Some redirects only apply to CreateFile and not CreateProcess
151+
real_env_exe = os.path.realpath(context.env_exe)
152+
if os.path.normcase(real_env_exe) != os.path.normcase(context.env_exe):
153+
logger.warning('Actual environment location may have moved due to '
154+
'redirects, links or junctions.\n'
155+
' Requested location: "%s"\n'
156+
' Actual location: "%s"',
157+
context.env_exe, real_env_exe)
158+
context.env_exec_cmd = real_env_exe
145159
return context
146160

147161
def create_configuration(self, context):
@@ -267,8 +281,9 @@ def setup_python(self, context):
267281
os.path.normcase(f).startswith(('python', 'vcruntime'))
268282
]
269283
else:
270-
suffixes = ['python.exe', 'python_d.exe', 'pythonw.exe',
271-
'pythonw_d.exe']
284+
suffixes = {'python.exe', 'python_d.exe', 'pythonw.exe', 'pythonw_d.exe'}
285+
base_exe = os.path.basename(context.env_exe)
286+
suffixes.add(base_exe)
272287

273288
for suffix in suffixes:
274289
src = os.path.join(dirname, suffix)
@@ -290,15 +305,11 @@ def setup_python(self, context):
290305

291306
def _setup_pip(self, context):
292307
"""Installs or upgrades pip in a virtual environment"""
293-
# TODO: RustPython
294-
msg = ("Pip isn't supported yet. To create a virtual environment"
295-
"without pip, call venv with the --without-pip flag.")
296-
raise NotImplementedError(msg)
297308
# We run ensurepip in isolated mode to avoid side effects from
298309
# environment vars, the current directory and anything else
299310
# intended for the global Python environment
300-
cmd = [context.env_exe, '-Im', 'ensurepip', '--upgrade',
301-
'--default-pip']
311+
cmd = [context.env_exec_cmd, '-Im', 'ensurepip', '--upgrade',
312+
'--default-pip']
302313
subprocess.check_output(cmd, stderr=subprocess.STDOUT)
303314

304315
def setup_scripts(self, context):
@@ -398,11 +409,7 @@ def upgrade_dependencies(self, context):
398409
logger.debug(
399410
f'Upgrading {CORE_VENV_DEPS} packages in {context.bin_path}'
400411
)
401-
if sys.platform == 'win32':
402-
python_exe = os.path.join(context.bin_path, 'python.exe')
403-
else:
404-
python_exe = os.path.join(context.bin_path, 'python')
405-
cmd = [python_exe, '-m', 'pip', 'install', '--upgrade']
412+
cmd = [context.env_exec_cmd, '-m', 'pip', 'install', '--upgrade']
406413
cmd.extend(CORE_VENV_DEPS)
407414
subprocess.check_call(cmd)
408415

Lib/venv/scripts/common/Activate.ps1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ function global:deactivate ([switch]$NonDestructive) {
9696
Remove-Item -Path env:VIRTUAL_ENV
9797
}
9898

99+
# Just remove VIRTUAL_ENV_PROMPT altogether.
100+
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
101+
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
102+
}
103+
99104
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
100105
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
101106
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
@@ -197,7 +202,7 @@ else {
197202
$Prompt = $pyvenvCfg['prompt'];
198203
}
199204
else {
200-
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)"
205+
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
201206
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
202207
$Prompt = Split-Path -Path $venvDir -Leaf
203208
}
@@ -228,6 +233,7 @@ if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
228233
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
229234
_OLD_VIRTUAL_PROMPT
230235
}
236+
$env:VIRTUAL_ENV_PROMPT = $Prompt
231237
}
232238

233239
# Clear PYTHONHOME

Lib/venv/scripts/common/activate

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ deactivate () {
2828
fi
2929

3030
unset VIRTUAL_ENV
31+
unset VIRTUAL_ENV_PROMPT
3132
if [ ! "${1:-}" = "nondestructive" ] ; then
3233
# Self destruct!
3334
unset -f deactivate
@@ -56,6 +57,8 @@ if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
5657
_OLD_VIRTUAL_PS1="${PS1:-}"
5758
PS1="__VENV_PROMPT__${PS1:-}"
5859
export PS1
60+
VIRTUAL_ENV_PROMPT="__VENV_PROMPT__"
61+
export VIRTUAL_ENV_PROMPT
5962
fi
6063

6164
# This should detect bash and zsh, which have a hash command that must

Lib/venv/scripts/nt/activate.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
2525
if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%
2626

2727
set PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%
28+
set VIRTUAL_ENV_PROMPT=__VENV_PROMPT__
2829

2930
:END
3031
if defined _OLD_CODEPAGE (

Lib/venv/scripts/nt/deactivate.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ if defined _OLD_VIRTUAL_PATH (
1717
set _OLD_VIRTUAL_PATH=
1818

1919
set VIRTUAL_ENV=
20+
set VIRTUAL_ENV_PROMPT=
2021

2122
:END

Lib/venv/scripts/posix/activate.csh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Created by Davide Di Blasi <davidedb@gmail.com>.
44
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
55

6-
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
6+
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
77

88
# Unset irrelevant variables.
99
deactivate nondestructive
@@ -18,6 +18,7 @@ set _OLD_VIRTUAL_PROMPT="$prompt"
1818

1919
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
2020
set prompt = "__VENV_PROMPT__$prompt"
21+
setenv VIRTUAL_ENV_PROMPT "__VENV_PROMPT__"
2122
endif
2223

2324
alias pydoc python -m pydoc

Lib/venv/scripts/posix/activate.fish

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function deactivate -d "Exit virtual environment and return to normal shell env
2020
end
2121

2222
set -e VIRTUAL_ENV
23+
set -e VIRTUAL_ENV_PROMPT
2324
if test "$argv[1]" != "nondestructive"
2425
# Self-destruct!
2526
functions -e deactivate
@@ -61,4 +62,5 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
6162
end
6263

6364
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
65+
set -gx VIRTUAL_ENV_PROMPT "__VENV_PROMPT__"
6466
end

0 commit comments

Comments
 (0)