diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 4f083a3181e7a9..d3d5ae2b007d5f 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -97,7 +97,7 @@ creation according to their needs, the :class:`EnvBuilder` class. .. class:: EnvBuilder(system_site_packages=False, clear=False, \ symlinks=False, upgrade=False, with_pip=False, \ - prompt=None) + prompt=None, upgrade_deps=False) The :class:`EnvBuilder` class accepts the following keyword arguments on instantiation: @@ -123,12 +123,17 @@ creation according to their needs, the :class:`EnvBuilder` class. (defaults to ``None`` which means directory name of the environment would be used). + * ``upgrade_deps`` -- Update the base venv modules to the latest on PyPI + .. versionchanged:: 3.4 Added the ``with_pip`` parameter .. versionadded:: 3.6 Added the ``prompt`` parameter + .. versionadded:: 3.8 + Added the ``upgrade_deps`` parameter + Creators of third-party virtual environment tools will be free to use the provided ``EnvBuilder`` class as a base class. diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index 1ada83c07a67f1..8fd107b332026e 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -35,7 +35,7 @@ your :ref:`Python installation `:: The command, if run with ``-h``, will show the available options:: usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear] - [--upgrade] [--without-pip] [--prompt PROMPT] + [--upgrade] [--without-pip] [--prompt PROMPT] [--upgrade-deps] ENV_DIR [ENV_DIR ...] Creates virtual Python environments in one or more target directories. @@ -60,10 +60,15 @@ The command, if run with ``-h``, will show the available options:: environment (pip is bootstrapped by default) --prompt PROMPT Provides an alternative prompt prefix for this environment. + --upgrade-deps Upgrade core dependencies: pip setuptools to the + latest version in PyPI Once an environment has been created, you may wish to activate it, e.g. by sourcing an activate script in its bin directory. +.. versionchanged:: 3.8 + Add ``--upgrade-deps`` option to upgrade pip + setuptools to the latest on PyPI + .. versionchanged:: 3.4 Installs pip by default, added the ``--without-pip`` and ``--copies`` options diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 24d3a69b1878b5..4f6c11b2663efd 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -16,9 +16,9 @@ from test.support import (captured_stdout, captured_stderr, requires_zlib, can_symlink, EnvironmentVarGuard, rmtree, import_module) -import threading import unittest import venv +from unittest.mock import patch try: import ctypes @@ -131,6 +131,28 @@ def test_prompt(self): self.assertEqual(context.prompt, '(My prompt) ') self.assertIn("prompt = 'My prompt'\n", data) + def test_upgrade_dependencies(self): + builder = venv.EnvBuilder() + bin_path = 'Scripts' if sys.platform == 'win32' else 'bin' + pip_exe = 'pip.exe' if sys.platform == 'win32' else 'pip' + with tempfile.TemporaryDirectory() as fake_env_dir: + + def pip_cmd_checker(cmd): + self.assertEqual( + cmd, + [ + os.path.join(fake_env_dir, bin_path, pip_exe), + 'install', + '-U', + 'pip', + 'setuptools' + ] + ) + + fake_context = builder.ensure_directories(fake_env_dir) + with patch('venv.subprocess.check_call', pip_cmd_checker): + builder.upgrade_dependencies(fake_context) + @requireVenvCreate def test_prefixes(self): """ diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 4a49b240b8e217..b64125fa4fe175 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -12,6 +12,8 @@ import sysconfig import types + +CORE_VENV_DEPS = ('pip', 'setuptools') logger = logging.getLogger(__name__) @@ -38,16 +40,19 @@ class EnvBuilder: :param with_pip: If True, ensure pip is installed in the virtual environment :param prompt: Alternative terminal prefix for the environment. + :param upgrade_deps: Update the base venv modules to the latest on PyPI """ def __init__(self, system_site_packages=False, clear=False, - symlinks=False, upgrade=False, with_pip=False, prompt=None): + symlinks=False, upgrade=False, with_pip=False, prompt=None, + upgrade_deps=False): self.system_site_packages = system_site_packages self.clear = clear self.symlinks = symlinks self.upgrade = upgrade self.with_pip = with_pip self.prompt = prompt + self.upgrade_deps = upgrade_deps def create(self, env_dir): """ @@ -74,6 +79,8 @@ def create(self, env_dir): # restore it and rewrite the configuration self.system_site_packages = True self.create_configuration(context) + if self.upgrade_deps: + self.upgrade_dependencies(context) def clear_directory(self, path): for fn in os.listdir(path): @@ -105,7 +112,6 @@ def create_if_needed(d): prompt = self.prompt if self.prompt is not None else context.env_name context.prompt = '(%s) ' % prompt create_if_needed(env_dir) - env = os.environ executable = getattr(sys, '_base_executable', sys.executable) dirname, exename = os.path.split(os.path.abspath(executable)) context.executable = executable @@ -363,13 +369,25 @@ def install_scripts(self, context, path): f.write(data) shutil.copymode(srcfile, dstfile) + def upgrade_dependencies(self, context): + logger.debug( + f'Upgrading {CORE_VENV_DEPS} packages in {context.bin_path}' + ) + if sys.platform == 'win32': + pip_exe = os.path.join(context.bin_path, 'pip.exe') + else: + pip_exe = os.path.join(context.bin_path, 'pip') + cmd = [pip_exe, 'install', '-U'] + cmd.extend(CORE_VENV_DEPS) + subprocess.check_call(cmd) + def create(env_dir, system_site_packages=False, clear=False, - symlinks=False, with_pip=False, prompt=None): + symlinks=False, with_pip=False, prompt=None, upgrade_deps=False): """Create a virtual environment in a directory.""" builder = EnvBuilder(system_site_packages=system_site_packages, clear=clear, symlinks=symlinks, with_pip=with_pip, - prompt=prompt) + prompt=prompt, upgrade_deps=upgrade_deps) builder.create(env_dir) def main(args=None): @@ -432,6 +450,11 @@ def main(args=None): parser.add_argument('--prompt', help='Provides an alternative prompt prefix for ' 'this environment.') + parser.add_argument('--upgrade-deps', default=False, action='store_true', + dest='upgrade_deps', + help='Upgrade core dependencies: {} to the latest ' + 'version in PyPI'.format( + ' '.join(CORE_VENV_DEPS))) options = parser.parse_args(args) if options.upgrade and options.clear: raise ValueError('you cannot supply --upgrade and --clear together.') @@ -440,7 +463,8 @@ def main(args=None): symlinks=options.symlinks, upgrade=options.upgrade, with_pip=options.with_pip, - prompt=options.prompt) + prompt=options.prompt, + upgrade_deps=options.upgrade_deps) for d in options.dirs: builder.create(d) diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-05-18-09-40.bpo-34556.o9kfpu.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-05-18-09-40.bpo-34556.o9kfpu.rst new file mode 100644 index 00000000000000..7861eac5cb2560 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-05-18-09-40.bpo-34556.o9kfpu.rst @@ -0,0 +1 @@ +Add ``--upgrade-deps`` to venv module. Patch by Cooper Ry Lees pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy