cpython: 57fbab22ab4e (original) (raw)
Mercurial > cpython
changeset 87341:57fbab22ab4e
Close #19552: venv and pyvenv ensurepip integration [#19552]
Nick Coghlan ncoghlan@gmail.com | |
---|---|
date | Sat, 23 Nov 2013 00:30:34 +1000 |
parents | 4051f2dcd99b |
children | d71251d9fbbe 331b7a8bb830 |
files | Doc/library/venv.rst Doc/using/venv-create.inc Lib/test/test_venv.py Lib/venv/__init__.py Misc/NEWS |
diffstat | 5 files changed, 105 insertions(+), 13 deletions(-)[+] [-] Doc/library/venv.rst 15 Doc/using/venv-create.inc 10 Lib/test/test_venv.py 54 Lib/venv/__init__.py 34 Misc/NEWS 5 |
line wrap: on
line diff
--- a/Doc/library/venv.rst
+++ b/Doc/library/venv.rst
@@ -85,7 +85,8 @@ The high-level method described above ma
mechanisms for third-party virtual environment creators to customize environment
creation according to their needs, the :class:EnvBuilder
class.
-.. class:: EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False)
+.. class:: EnvBuilder(system_site_packages=False, clear=False, [](#l1.8)
symlinks=False, upgrade=False, with_pip=False)[](#l1.9)
The :class:EnvBuilder
class accepts the following keyword arguments on
instantiation:
@@ -105,6 +106,12 @@ creation according to their needs, the :
environment with the running Python - for use when that Python has been
upgraded in-place (defaults to False
).
installed in the virtual environment[](#l1.18)
+
Creators of third-party virtual environment tools will be free to use the
provided EnvBuilder
class as a base class.
@@ -201,11 +208,15 @@ creation according to their needs, the :
There is also a module-level convenience function:
-.. function:: create(env_dir, system_site_packages=False, clear=False, symlinks=False)
+.. function:: create(env_dir, system_site_packages=False, clear=False, [](#l1.31)
symlinks=False, with_pip=False)[](#l1.32)
Create an :class:EnvBuilder
with the given keyword arguments, and call its
:meth:~EnvBuilder.create
method with the env_dir argument.
+
An example of extending EnvBuilder
--------------------------------------
--- a/Doc/using/venv-create.inc
+++ b/Doc/using/venv-create.inc
@@ -25,7 +25,7 @@ or equivalently::
The command, if run with -h
, will show the available options::
usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear]
[--upgrade] ENV_DIR [ENV_DIR ...][](#l2.7)
[--upgrade] [--without-pip] ENV_DIR [ENV_DIR ...][](#l2.8)
Creates virtual Python environments in one or more target directories.
@@ -43,6 +43,11 @@ The command, if run with -h
, will sh
raised.
--upgrade Upgrade the environment directory to use this version
of Python, assuming Python has been upgraded in-place.
--without-pip Skips installing or upgrading pip in the virtual[](#l2.16)
environment (pip is bootstrapped by default)[](#l2.17)
If the target directory already exists an error will be raised, unless
the --clear
or --upgrade
option was provided.
@@ -51,6 +56,9 @@ The created pyvenv.cfg
file also inc
include-system-site-packages
key, set to true
if venv
is
run with the --system-site-packages
option, false
otherwise.
+Unless the --without-pip
option is given, :mod:ensurepip
will be
+invoked to bootstrap pip
into the virtual environment.
+
Multiple paths can be given to pyvenv
, in which case an identical
virtualenv will be created, according to the given options, at each
provided path.
--- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -16,6 +16,10 @@ from test.support import (captured_stdou import unittest import venv +skipInVenv = unittest.skipIf(sys.prefix != sys.base_prefix,
'Test not appropriate in a venv')[](#l3.8)
+ + class BaseTest(unittest.TestCase): """Base class for venv tests.""" @@ -83,8 +87,7 @@ class BasicTest(BaseTest): print(' %r' % os.listdir(bd)) self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
@@ -217,8 +220,7 @@ class BasicTest(BaseTest): # run the test, the pyvenv.cfg in the venv created in the test will # point to the venv being used to run the test, and we lose the link # to the source build - so Python can't initialise properly.
@@ -247,8 +249,50 @@ class BasicTest(BaseTest): out, err = p.communicate() self.assertEqual(out.strip(), envpy.encode()) + +@skipInVenv +class EnsurePipTest(BaseTest):
- def test_no_pip_by_default(self):
shutil.rmtree(self.env_dir)[](#l3.44)
self.run_with_capture(venv.create, self.env_dir)[](#l3.45)
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)[](#l3.46)
try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'[](#l3.47)
cmd = [envpy, '-c', try_import][](#l3.48)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,[](#l3.49)
stderr=subprocess.PIPE)[](#l3.50)
out, err = p.communicate()[](#l3.51)
self.assertEqual(err, b"")[](#l3.52)
self.assertEqual(out.strip(), b"OK")[](#l3.53)
- def test_explicit_no_pip(self):
shutil.rmtree(self.env_dir)[](#l3.56)
self.run_with_capture(venv.create, self.env_dir, with_pip=False)[](#l3.57)
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)[](#l3.58)
try_import = 'try:\n import pip\nexcept ImportError:\n print("OK")'[](#l3.59)
cmd = [envpy, '-c', try_import][](#l3.60)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,[](#l3.61)
stderr=subprocess.PIPE)[](#l3.62)
out, err = p.communicate()[](#l3.63)
self.assertEqual(err, b"")[](#l3.64)
self.assertEqual(out.strip(), b"OK")[](#l3.65)
- def test_with_pip(self):
shutil.rmtree(self.env_dir)[](#l3.68)
self.run_with_capture(venv.create, self.env_dir, with_pip=True)[](#l3.69)
envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)[](#l3.70)
cmd = [envpy, '-m', 'pip', '--version'][](#l3.71)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,[](#l3.72)
stderr=subprocess.PIPE)[](#l3.73)
out, err = p.communicate()[](#l3.74)
self.assertEqual(err, b"")[](#l3.75)
self.assertTrue(out.startswith(b"pip"))[](#l3.76)
self.assertIn(self.env_dir.encode(), out)[](#l3.77)
if name == "main": test_main()
--- a/Lib/venv/init.py +++ b/Lib/venv/init.py @@ -24,10 +24,13 @@ optional arguments: raised. --upgrade Upgrade the environment directory to use this version of Python, assuming Python has been upgraded in-place.
- --without-pip Skips installing or upgrading pip in the virtual
environment (pip is bootstrapped by default)[](#l4.8)
""" import logging import os import shutil +import subprocess import sys import sysconfig import types @@ -56,14 +59,17 @@ class EnvBuilder: :param symlinks: If True, attempt to symlink rather than copy files into virtual environment. :param upgrade: If True, upgrade an existing virtual environment.
- :param with_pip: If True, ensure pip is installed in the virtual
""" def init(self, system_site_packages=False, clear=False,environment[](#l4.22)
symlinks=False, upgrade=False):[](#l4.26)
symlinks=False, upgrade=False, with_pip=False):[](#l4.27) self.system_site_packages = system_site_packages[](#l4.28) self.clear = clear[](#l4.29) self.symlinks = symlinks[](#l4.30) self.upgrade = upgrade[](#l4.31)
self.with_pip = with_pip[](#l4.32)
def create(self, env_dir): """ @@ -76,6 +82,8 @@ class EnvBuilder: context = self.ensure_directories(env_dir) self.create_configuration(context) self.setup_python(context)
if self.with_pip:[](#l4.40)
self._setup_pip(context)[](#l4.41) if not self.upgrade:[](#l4.42) self.setup_scripts(context)[](#l4.43) self.post_setup(context)[](#l4.44)
@@ -224,6 +232,12 @@ class EnvBuilder: shutil.copyfile(src, dst) break
- def _setup_pip(self, context):
"""Installs or upgrades pip in a virtual environment"""[](#l4.50)
cmd = [context.env_exe, '-m', 'ensurepip', '--upgrade',[](#l4.51)
'--default-pip'][](#l4.52)
subprocess.check_output(cmd)[](#l4.53)
+ def setup_scripts(self, context): """ Set up scripts into the created environment from a directory. @@ -317,7 +331,8 @@ class EnvBuilder: shutil.copymode(srcfile, dstfile) -def create(env_dir, system_site_packages=False, clear=False, symlinks=False): +def create(env_dir, system_site_packages=False, clear=False,
""" Create a virtual environment in a directory. @@ -333,9 +348,11 @@ def create(env_dir, system_site_packages raised. :param symlinks: If True, attempt to symlink rather than copy files into virtual environment.symlinks=False, with_pip=False):[](#l4.64)
- :param with_pip: If True, ensure pip is installed in the virtual
""" builder = EnvBuilder(system_site_packages=system_site_packages,environment[](#l4.73)
clear=clear, symlinks=symlinks)[](#l4.76)
builder.create(env_dir) def main(args=None): @@ -390,12 +407,19 @@ def main(args=None): 'directory to use this version ' 'of Python, assuming Python ' 'has been upgraded in-place.')clear=clear, symlinks=symlinks, with_pip=with_pip)[](#l4.77)
parser.add_argument('--without-pip', dest='with_pip',[](#l4.85)
default=True, action='store_false',[](#l4.86)
help='Skips installing or upgrading pip in the '[](#l4.87)
'virtual environment (pip is bootstrapped '[](#l4.88)
'by default)')[](#l4.89) options = parser.parse_args(args)[](#l4.90) if options.upgrade and options.clear:[](#l4.91) raise ValueError('you cannot supply --upgrade and --clear together.')[](#l4.92) builder = EnvBuilder(system_site_packages=options.system_site,[](#l4.93)
clear=options.clear, symlinks=options.symlinks,[](#l4.94)
upgrade=options.upgrade)[](#l4.95)
clear=options.clear,[](#l4.96)
symlinks=options.symlinks,[](#l4.97)
upgrade=options.upgrade,[](#l4.98)
with_pip=options.with_pip)[](#l4.99) for d in options.dirs:[](#l4.100) builder.create(d)[](#l4.101)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -65,6 +65,8 @@ Core and Builtins Library ------- +- Issue #19552: venv now supports bootstrapping pip into virtual environments +