diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index de714de2a2049f..ca37abcf79854a 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -19,7 +19,7 @@ from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv -from unittest.mock import patch +from unittest.mock import patch, Mock try: import ctypes @@ -114,6 +114,11 @@ def test_defaults(self): executable = sys._base_executable path = os.path.dirname(executable) self.assertIn('home = %s' % path, data) + self.assertIn('executable = %s' % + os.path.realpath(sys.executable), data) + copies = '' if os.name=='nt' else ' --copies' + cmd = f'command = {sys.executable} -m venv{copies} --without-pip {self.env_dir}' + self.assertIn(cmd, data) fn = self.get_env_file(self.bindir, self.exe) if not os.path.exists(fn): # diagnostics for Windows buildbot failures bd = self.get_env_file(self.bindir) @@ -121,6 +126,37 @@ def test_defaults(self): print(' %r' % os.listdir(bd)) self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn) + def test_config_file_command_key(self): + attrs = [ + (None, None), + ('symlinks', '--copies'), + ('with_pip', '--without-pip'), + ('system_site_packages', '--system-site-packages'), + ('clear', '--clear'), + ('upgrade', '--upgrade'), + ('upgrade_deps', '--upgrade-deps'), + ('prompt', '--prompt'), + ] + for attr, opt in attrs: + rmtree(self.env_dir) + if not attr: + b = venv.EnvBuilder() + else: + b = venv.EnvBuilder( + **{attr: False if attr in ('with_pip', 'symlinks') else True}) + b.upgrade_dependencies = Mock() # avoid pip command to upgrade deps + b._setup_pip = Mock() # avoid pip setup + self.run_with_capture(b.create, self.env_dir) + data = self.get_text_file_contents('pyvenv.cfg') + if not attr: + for opt in ('--system-site-packages', '--clear', '--upgrade', + '--upgrade-deps', '--prompt'): + self.assertNotRegex(data, rf'command = .* {opt}') + elif os.name=='nt' and attr=='symlinks': + pass + else: + self.assertRegex(data, rf'command = .* {opt}') + def test_prompt(self): env_name = os.path.split(self.env_dir)[1] diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 6f1af294ae63e3..b90765074c36d8 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -51,6 +51,7 @@ def __init__(self, system_site_packages=False, clear=False, self.symlinks = symlinks self.upgrade = upgrade self.with_pip = with_pip + self.orig_prompt = prompt if prompt == '.': # see bpo-38901 prompt = os.path.basename(os.getcwd()) self.prompt = prompt @@ -178,6 +179,29 @@ def create_configuration(self, context): f.write('version = %d.%d.%d\n' % sys.version_info[:3]) if self.prompt is not None: f.write(f'prompt = {self.prompt!r}\n') + f.write('executable = %s\n' % os.path.realpath(sys.executable)) + args = [] + nt = os.name == 'nt' + if nt and self.symlinks: + args.append('--symlinks') + if not nt and not self.symlinks: + args.append('--copies') + if not self.with_pip: + args.append('--without-pip') + if self.system_site_packages: + args.append('--system-site-packages') + if self.clear: + args.append('--clear') + if self.upgrade: + args.append('--upgrade') + if self.upgrade_deps: + args.append('--upgrade-deps') + if self.orig_prompt is not None: + args.append(f'--prompt="{self.orig_prompt}"') + + args.append(context.env_dir) + args = ' '.join(args) + f.write(f'command = {sys.executable} -m venv {args}\n') if os.name != 'nt': def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): diff --git a/Misc/NEWS.d/next/Library/2022-01-03-21-03-50.bpo-41011.uULmGi.rst b/Misc/NEWS.d/next/Library/2022-01-03-21-03-50.bpo-41011.uULmGi.rst new file mode 100644 index 00000000000000..1b1fa5d376527b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-03-21-03-50.bpo-41011.uULmGi.rst @@ -0,0 +1,3 @@ +Added two new variables to *pyvenv.cfg* which is generated by :mod:`venv` +module: *executable* for the executable and *command* for the command line used +to create the environment.