Skip to content

Commit

Permalink
gh-98251: Allow venv to pass along PYTHON* variables to pip and ensur…
Browse files Browse the repository at this point in the history
…epip when they do not impact path resolution (GH-98259)

(cherry picked from commit 2fe44f7)

Co-authored-by: Steve Dower <steve.dower@python.org>
  • Loading branch information
miss-islington and zooba authored Oct 14, 2022
1 parent fa9f65e commit c9da063
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 13 deletions.
8 changes: 4 additions & 4 deletions Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def test_upgrade_dependencies(self):
if sys.platform == 'win32':
expect_exe = os.path.normcase(os.path.realpath(expect_exe))

def pip_cmd_checker(cmd):
def pip_cmd_checker(cmd, **kwargs):
cmd[0] = os.path.normcase(cmd[0])
self.assertEqual(
cmd,
Expand All @@ -175,7 +175,7 @@ def pip_cmd_checker(cmd):
)

fake_context = builder.ensure_directories(fake_env_dir)
with patch('venv.subprocess.check_call', pip_cmd_checker):
with patch('venv.subprocess.check_output', pip_cmd_checker):
builder.upgrade_dependencies(fake_context)

@requireVenvCreate
Expand Down Expand Up @@ -547,8 +547,8 @@ def nicer_error(self):
try:
yield
except subprocess.CalledProcessError as exc:
out = exc.output.decode(errors="replace")
err = exc.stderr.decode(errors="replace")
out = (exc.output or b'').decode(errors="replace")
err = (exc.stderr or b'').decode(errors="replace")
self.fail(
f"{exc}\n\n"
f"**Subprocess Output**\n{out}\n\n"
Expand Down
28 changes: 19 additions & 9 deletions Lib/venv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,14 +308,25 @@ def setup_python(self, context):
shutil.copyfile(src, dst)
break

def _call_new_python(self, context, *py_args, **kwargs):
"""Executes the newly created Python using safe-ish options"""
# gh-98251: We do not want to just use '-I' because that masks
# legitimate user preferences (such as not writing bytecode). All we
# really need is to ensure that the path variables do not overrule
# normal venv handling.
args = [context.env_exec_cmd, *py_args]
kwargs['env'] = env = os.environ.copy()
env['VIRTUAL_ENV'] = context.env_dir
env.pop('PYTHONHOME', None)
env.pop('PYTHONPATH', None)
kwargs['cwd'] = context.env_dir
kwargs['executable'] = context.env_exec_cmd
subprocess.check_output(args, **kwargs)

def _setup_pip(self, context):
"""Installs or upgrades pip in a virtual environment"""
# We run ensurepip in isolated mode to avoid side effects from
# environment vars, the current directory and anything else
# intended for the global Python environment
cmd = [context.env_exec_cmd, '-Im', 'ensurepip', '--upgrade',
'--default-pip']
subprocess.check_output(cmd, stderr=subprocess.STDOUT)
self._call_new_python(context, '-m', 'ensurepip', '--upgrade',
'--default-pip', stderr=subprocess.STDOUT)

def setup_scripts(self, context):
"""
Expand Down Expand Up @@ -414,9 +425,8 @@ def upgrade_dependencies(self, context):
logger.debug(
f'Upgrading {CORE_VENV_DEPS} packages in {context.bin_path}'
)
cmd = [context.env_exec_cmd, '-m', 'pip', 'install', '--upgrade']
cmd.extend(CORE_VENV_DEPS)
subprocess.check_call(cmd)
self._call_new_python(context, '-m', 'pip', 'install', '--upgrade',
*CORE_VENV_DEPS)


def create(env_dir, system_site_packages=False, clear=False,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow :mod:`venv` to pass along :envvar:`PYTHON*` variables to ``ensurepip`` and ``pip`` when
they do not impact path resolution

0 comments on commit c9da063

Please sign in to comment.