venv ——创建虚拟环境

3.3 新版功能.

源代码: Lib/venv/


这个 venv 模块提供了创建轻量级“虚拟环境”的支持,该环境具有自己的站点目录,可以选择与系统站点目录隔离。每个虚拟环境都有自己的python二进制文件(与用于创建此环境的二进制文件的版本相匹配),并且可以在其站点目录中有自己独立的一组已安装的python包。

PEP 405 有关Python虚拟环境的详细信息。

创建虚拟环境

创造 virtual environments 通过执行命令完成 venv ::

python3 -m venv /path/to/new/virtual/environment

运行此命令将创建目标目录(创建任何不存在的父目录),并将 pyvenv.cfg 文件中包含 home 指向运行命令的python安装的键(目标目录的通用名称是 .venv )。它还创建了一个 bin (或) Scripts 在Windows上)包含python binary/binaries的copy/symlink的子目录(适用于环境创建时使用的平台或参数)。它还创建一个(最初为空) lib/pythonX.Y/site-packages 子目录(在Windows上,这是 Lib\site-packages )。如果指定了现有目录,则将重新使用该目录。

3.6 版后已移除: pyvenv 是为python 3.3和3.4创建虚拟环境的推荐工具,并且是 deprecated in Python 3.6 .

在 3.5 版更改: venv 现在建议用于创建虚拟环境。

在Windows上,调用 venv 命令如下:

c:\>c:\Python35\python -m venv c:\path\to\myenv

或者,如果配置了 PATHPATHEXT 你的变量 Python installation ::

c:\>python -m venv c:\path\to\myenv

命令,如果与一起运行 -h ,将显示可用选项::

usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear]
            [--upgrade] [--without-pip] [--prompt PROMPT] [--upgrade-deps]
            ENV_DIR [ENV_DIR ...]

Creates virtual Python environments in one or more target directories.

positional arguments:
  ENV_DIR               A directory to create the environment in.

optional arguments:
  -h, --help            show this help message and exit
  --system-site-packages
                        Give the virtual environment access to the system
                        site-packages dir.
  --symlinks            Try to use symlinks rather than copies, when symlinks
                        are not the default for the platform.
  --copies              Try to use copies rather than symlinks, even when
                        symlinks are the default for the platform.
  --clear               Delete the contents of the environment directory if it
                        already exists, before environment creation.
  --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)
  --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.

在 3.9 版更改: 添加 --upgrade-deps 将pip+安装工具升级到pypi上的最新版本的选项

在 3.4 版更改: 默认情况下安装PIP,添加了 --without-pip--copies 选项

在 3.4 版更改: 在早期版本中,如果目标目录已经存在,则会引发错误,除非 --clear--upgrade 提供了选项。

注解

虽然在Windows上支持符号链接,但不建议使用它们。特别要注意的是双击 python.exe 在文件资源管理器中,会急切地解析symlink并忽略虚拟环境。

注解

在Microsoft Windows上,可能需要启用 Activate.ps1 通过设置用户的执行策略编写脚本。可以通过发出以下PowerShell命令来执行此操作:

PS C:>设置执行策略-执行策略远程签名-作用域当前用户

About Execution Policies 更多信息。

创造的 pyvenv.cfg 文件还包括 include-system-site-packages 设置为 true 如果 venv 正在运行 --system-site-packages 选项, false 否则。

除非 --without-pip 有选择权, ensurepip 将被调用以引导 pip 进入虚拟环境。

可以给多个路径 venv 在这种情况下,将根据给定的选项在每个提供的路径上创建相同的虚拟环境。

一旦创建了虚拟环境,就可以使用虚拟环境二进制目录中的脚本“激活”它。脚本的调用是平台特定的(必须用包含虚拟环境的目录的路径替换“<venv>”):

Platform

Shell

激活虚拟环境的命令

POSIX

BASH/ZSH

$source<venv>/bin/激活

$source<venv>/bin/activate.fish

CSH/TCSH

$source<venv>/bin/activate.csh

PowerShell核心

$<venv>/bin/activate.ps1

Windows

cmd.exe

C:\><venv>\scripts\activate.bat

PowerShell

ps c:\><venv>\scripts\activate.ps1

当虚拟环境处于活动状态时 VIRTUAL_ENV 环境变量设置为虚拟环境的路径。这可以用来检查是否在虚拟环境中运行。

你不是特别的 need 要激活一个环境,激活只需将虚拟环境的二进制目录预先设置为您的路径,这样“python”就可以调用虚拟环境的python解释器,并且您可以运行已安装的脚本,而不必使用它们的完整路径。但是,安装在虚拟环境中的所有脚本都应该可以在不激活它的情况下运行,并且可以使用虚拟环境的python自动运行。

您可以通过在shell中键入“deactivate”来停用虚拟环境。确切的机制是特定于平台的,是一个内部实现细节(通常使用脚本或shell函数)。

3.4 新版功能: fishcsh 激活脚本。

3.8 新版功能: 为PowerShell核心支持安装在POSIX下的PowerShell激活脚本。

注解

虚拟环境是一种python环境,其中安装的python解释器、库和脚本与其他虚拟环境中安装的库以及(默认情况下)安装在“系统”python中的任何库(即作为操作系统的一部分安装的库)都是隔离的。

虚拟环境是一个目录树,其中包含python可执行文件和其他指示它是虚拟环境的文件。

常用安装工具,如 setuptoolspip 在虚拟环境中按预期工作。换句话说,当一个虚拟环境处于活动状态时,他们将python包安装到虚拟环境中,而不需要被告知显式地这样做。

当虚拟环境处于活动状态(即虚拟环境的python解释器正在运行)时,属性 sys.prefixsys.exec_prefix 指向虚拟环境的基目录,而 sys.base_prefixsys.base_exec_prefix 指向用于创建虚拟环境的非虚拟环境python安装。如果虚拟环境未处于活动状态,则 sys.prefix 是一样的 sys.base_prefixsys.exec_prefix 是一样的 sys.base_exec_prefix (它们都指向非虚拟环境python安装)。

当虚拟环境处于活动状态时,所有更改安装路径的选项都将被忽略。 distutils 配置文件以防止项目意外安装在虚拟环境之外。

在命令shell中工作时,用户可以通过运行 activate 虚拟环境的可执行文件目录中的脚本(使用该文件的精确文件名和命令依赖于shell),它会将虚拟环境的可执行文件目录预处理为 PATH 正在运行的shell的环境变量。在其他情况下,不需要激活虚拟环境;安装在虚拟环境中的脚本有一条“shebang”线,指向虚拟环境的python解释器。这意味着脚本将与该解释器一起运行,而不管 PATH . 在Windows上,如果安装了用于Windows的python启动程序,则支持“shebang”行处理(这已在3.3中添加到python中-请参见 PEP 397 了解更多详细信息)。因此,双击Windows资源管理器窗口中安装的脚本应该使用正确的解释器运行该脚本,而不需要在 PATH .

API

上面描述的高级方法使用了一个简单的API,它为第三方虚拟环境创建者提供了根据他们的需求定制环境创建的机制,即 EnvBuilder 类。

class venv.EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False, with_pip=False, prompt=None, upgrade_deps=False)

这个 EnvBuilder 类在实例化时接受以下关键字参数:

  • system_site_packages --一个布尔值,指示系统python站点包应该对环境可用(默认为 False

  • clear --一个布尔值,如果为真,则在创建环境之前将删除任何现有目标目录的内容。

  • symlinks --一个布尔值,指示是否尝试对python二进制文件进行符号链接,而不是复制。

  • upgrade --一个布尔值,如果为真,它将使用运行中的python升级现有环境,以便在该python已升级到位时使用(默认为 False

  • with_pip --一个布尔值,如果为真,则确保PIP安装在虚拟环境中。这使用 ensurepip--default-pip 选择权。

  • prompt --激活虚拟环境后要使用的字符串(默认为 None 这意味着将使用环境的目录名)。如果特殊字符串 "." 提供时,将使用当前目录的基名作为提示。

  • upgrade_deps --将基础venv模块更新为pypi上的最新版本

在 3.4 版更改: 增加了 with_pip 参数

3.6 新版功能: 增加了 prompt 参数

3.9 新版功能: 增加了 upgrade_deps 参数

第三方虚拟环境工具的创建者将免费使用提供的 EnvBuilder 类作为基类。

返回的env builder是一个具有方法的对象, create

create(env_dir)

通过指定要包含虚拟环境的目标目录(绝对目录或相对于当前目录)来创建虚拟环境。这个 create 方法将在指定目录中创建环境,或引发适当的异常。

这个 create 方法 EnvBuilder 类说明了可用于子类自定义的挂钩:

def create(self, env_dir):
    """
    Create a virtualized Python environment in a directory.
    env_dir is the target directory to create an environment in.
    """
    env_dir = os.path.abspath(env_dir)
    context = self.ensure_directories(env_dir)
    self.create_configuration(context)
    self.setup_python(context)
    self.setup_scripts(context)
    self.post_setup(context)

每种方法 ensure_directories()create_configuration()setup_python()setup_scripts()post_setup() 可以重写。

ensure_directories(env_dir)

创建环境目录和所有必需的目录,并返回上下文对象。这只是属性(如路径)的一个持有者,供其他方法使用。允许目录已经存在,只要 clearupgrade 指定为允许在现有环境目录上操作。

create_configuration(context)

创建 pyvenv.cfg 环境中的配置文件。

setup_python(context)

创建到环境中的python可执行文件的副本或符号链接。在POSIX系统上,如果特定的可执行文件 python3.x 使用,符号链接到 pythonpython3 将创建指向该可执行文件的文件,除非已存在具有这些名称的文件。

setup_scripts(context)

将适合平台的激活脚本安装到虚拟环境中。

upgrade_dependencies(context)

升级核心venv依赖包(当前 pipsetuptools )在环境中。这是通过炮击 pip 可在环境中执行。

3.9 新版功能.

post_setup(context)

可在第三方实现中重写的占位符方法,用于在虚拟环境中预安装包或执行其他后期创建步骤。

在 3.7.2 版更改: Windows现在使用重定向器脚本 python[w].exe 而不是复制实际的二进制文件。仅在3.7.2中 setup_python() 除非从源码树中的生成运行,否则不执行任何操作。

在 3.7.3 版更改: Windows将重定向程序脚本复制为 setup_python() 而不是 setup_scripts() . 这不是3.7.2中的情况。使用符号链接时,将链接原始可执行文件。

此外, EnvBuilder 提供此实用程序方法,可以从 setup_scripts()post_setup() 在子类中帮助将自定义脚本安装到虚拟环境中。

install_scripts(context, path)

path 是指向目录的路径,该目录应包含子目录“common”、“posix”、“nt”,每个子目录都包含环境中用于bin目录的脚本。“common”的内容和对应的目录 os.name 在某些文本替换占位符后复制:

  • __VENV_DIR__ 替换为环境目录的绝对路径。

  • __VENV_NAME__ 替换为环境名称(环境目录的最终路径段)。

  • __VENV_PROMPT__ 替换为提示(用括号括起来的环境名称,并用以下空格)

  • __VENV_BIN_NAME__ 替换为bin目录的名称(或者 binScripts

  • __VENV_PYTHON__ 替换为环境可执行文件的绝对路径。

允许目录存在(用于升级现有环境时)。

还有一个模块级便利功能:

venv.create(env_dir, system_site_packages=False, clear=False, symlinks=False, with_pip=False, prompt=None, upgrade_deps=False)

创建一个 EnvBuilder 使用给定的关键字参数,并调用其 create() 方法与 env_dir 参数。

3.3 新版功能.

在 3.4 版更改: 增加了 with_pip 参数

在 3.6 版更改: 增加了 prompt 参数

在 3.9 版更改: 增加了 upgrade_deps 参数

扩展的例子 EnvBuilder

下面的脚本演示如何扩展 EnvBuilder 通过实现将安装工具和PIP安装到创建的虚拟环境中的子类:

import os
import os.path
from subprocess import Popen, PIPE
import sys
from threading import Thread
from urllib.parse import urlparse
from urllib.request import urlretrieve
import venv

class ExtendedEnvBuilder(venv.EnvBuilder):
    """
    This builder installs setuptools and pip so that you can pip or
    easy_install other packages into the created virtual environment.

    :param nodist: If true, setuptools and pip are not installed into the
                   created virtual environment.
    :param nopip: If true, pip is not installed into the created
                  virtual environment.
    :param progress: If setuptools or pip are installed, the progress of the
                     installation can be monitored by passing a progress
                     callable. If specified, it is called with two
                     arguments: a string indicating some progress, and a
                     context indicating where the string is coming from.
                     The context argument can have one of three values:
                     'main', indicating that it is called from virtualize()
                     itself, and 'stdout' and 'stderr', which are obtained
                     by reading lines from the output streams of a subprocess
                     which is used to install the app.

                     If a callable is not specified, default progress
                     information is output to sys.stderr.
    """

    def __init__(self, *args, **kwargs):
        self.nodist = kwargs.pop('nodist', False)
        self.nopip = kwargs.pop('nopip', False)
        self.progress = kwargs.pop('progress', None)
        self.verbose = kwargs.pop('verbose', False)
        super().__init__(*args, **kwargs)

    def post_setup(self, context):
        """
        Set up any packages which need to be pre-installed into the
        virtual environment being created.

        :param context: The information for the virtual environment
                        creation request being processed.
        """
        os.environ['VIRTUAL_ENV'] = context.env_dir
        if not self.nodist:
            self.install_setuptools(context)
        # Can't install pip without setuptools
        if not self.nopip and not self.nodist:
            self.install_pip(context)

    def reader(self, stream, context):
        """
        Read lines from a subprocess' output stream and either pass to a progress
        callable (if specified) or write progress information to sys.stderr.
        """
        progress = self.progress
        while True:
            s = stream.readline()
            if not s:
                break
            if progress is not None:
                progress(s, context)
            else:
                if not self.verbose:
                    sys.stderr.write('.')
                else:
                    sys.stderr.write(s.decode('utf-8'))
                sys.stderr.flush()
        stream.close()

    def install_script(self, context, name, url):
        _, _, path, _, _, _ = urlparse(url)
        fn = os.path.split(path)[-1]
        binpath = context.bin_path
        distpath = os.path.join(binpath, fn)
        # Download script into the virtual environment's binaries folder
        urlretrieve(url, distpath)
        progress = self.progress
        if self.verbose:
            term = '\n'
        else:
            term = ''
        if progress is not None:
            progress('Installing %s ...%s' % (name, term), 'main')
        else:
            sys.stderr.write('Installing %s ...%s' % (name, term))
            sys.stderr.flush()
        # Install in the virtual environment
        args = [context.env_exe, fn]
        p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
        t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
        t1.start()
        t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
        t2.start()
        p.wait()
        t1.join()
        t2.join()
        if progress is not None:
            progress('done.', 'main')
        else:
            sys.stderr.write('done.\n')
        # Clean up - no longer needed
        os.unlink(distpath)

    def install_setuptools(self, context):
        """
        Install setuptools in the virtual environment.

        :param context: The information for the virtual environment
                        creation request being processed.
        """
        url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
        self.install_script(context, 'setuptools', url)
        # clear up the setuptools archive which gets downloaded
        pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
        files = filter(pred, os.listdir(context.bin_path))
        for f in files:
            f = os.path.join(context.bin_path, f)
            os.unlink(f)

    def install_pip(self, context):
        """
        Install pip in the virtual environment.

        :param context: The information for the virtual environment
                        creation request being processed.
        """
        url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
        self.install_script(context, 'pip', url)

def main(args=None):
    compatible = True
    if sys.version_info < (3, 3):
        compatible = False
    elif not hasattr(sys, 'base_prefix'):
        compatible = False
    if not compatible:
        raise ValueError('This script is only for use with '
                         'Python 3.3 or later')
    else:
        import argparse

        parser = argparse.ArgumentParser(prog=__name__,
                                         description='Creates virtual Python '
                                                     'environments in one or '
                                                     'more target '
                                                     'directories.')
        parser.add_argument('dirs', metavar='ENV_DIR', nargs='+',
                            help='A directory in which to create the
                                 'virtual environment.')
        parser.add_argument('--no-setuptools', default=False,
                            action='store_true', dest='nodist',
                            help="Don't install setuptools or pip in the "
                                 "virtual environment.")
        parser.add_argument('--no-pip', default=False,
                            action='store_true', dest='nopip',
                            help="Don't install pip in the virtual "
                                 "environment.")
        parser.add_argument('--system-site-packages', default=False,
                            action='store_true', dest='system_site',
                            help='Give the virtual environment access to the '
                                 'system site-packages dir.')
        if os.name == 'nt':
            use_symlinks = False
        else:
            use_symlinks = True
        parser.add_argument('--symlinks', default=use_symlinks,
                            action='store_true', dest='symlinks',
                            help='Try to use symlinks rather than copies, '
                                 'when symlinks are not the default for '
                                 'the platform.')
        parser.add_argument('--clear', default=False, action='store_true',
                            dest='clear', help='Delete the contents of the '
                                               'virtual environment '
                                               'directory if it already '
                                               'exists, before virtual '
                                               'environment creation.')
        parser.add_argument('--upgrade', default=False, action='store_true',
                            dest='upgrade', help='Upgrade the virtual '
                                                 'environment directory to '
                                                 'use this version of '
                                                 'Python, assuming Python '
                                                 'has been upgraded '
                                                 'in-place.')
        parser.add_argument('--verbose', default=False, action='store_true',
                            dest='verbose', help='Display the output '
                                               'from the scripts which '
                                               'install setuptools and pip.')
        options = parser.parse_args(args)
        if options.upgrade and options.clear:
            raise ValueError('you cannot supply --upgrade and --clear together.')
        builder = ExtendedEnvBuilder(system_site_packages=options.system_site,
                                       clear=options.clear,
                                       symlinks=options.symlinks,
                                       upgrade=options.upgrade,
                                       nodist=options.nodist,
                                       nopip=options.nopip,
                                       verbose=options.verbose)
        for d in options.dirs:
            builder.create(d)

if __name__ == '__main__':
    rc = 1
    try:
        main()
        rc = 0
    except Exception as e:
        print('Error: %s' % e, file=sys.stderr)
    sys.exit(rc)

此脚本也可供下载 online .