联结地址:https://www.cnblogs.com/dangkai/p/9413932.html 此处简单有介绍,如果听不懂,请看下文:链接地址
PEP 405 -- Python Virtual Environments
PEP: | 405 |
---|---|
Title: | Python Virtual Environments |
Author: | Carl Meyer <carl at oddbird.net> |
BDFL-Delegate: | Nick Coghlan |
Status: | Final |
Type: | Standards Track |
Created: | 13-Jun-2011 |
Python-Version: | 3.3 |
Post-History: | 24-Oct-2011, 28-Oct-2011, 06-Mar-2012, 24-May-2012 |
Resolution: | https://mail.python.org/pipermail/python-dev/2012-May/119668.html |
Contents
摘要
PEP意图在python中添加一种轻量级的“虚拟环境”机制,该机制具有自己的站点(site directories)目录;可以选择与系统站点目录隔离。每个虚拟环境都有自己的python二进制文件(允许创建具有不同python版本的环境),并且可以在其站点目录中有自己独立的一组已安装的python包,但可以与基本已经安装的python共享标准库。
需求动机
现有第三方虚拟环境工具(主要是Ian Bicking的virtualenv)的普及,已经很好地证明了python虚拟环境的实用性。虚拟环境已经广泛用于依赖关系管理和隔离,在无需系统管理员介入前提下,易于安装和使用python包,以及跨多个python版本自动测试python软件等用途。
过去已有的虚拟环境工具缺乏对Python本身行为的支持。诸如rvirtualenv[2]这样的工具无法将python二进制文件复制到虚拟环境中,因此无法提供与系统站点目录的可靠隔离。virtualenv复制了python二进制文件,它强制复制python的大部分站点模块,并手动将一组不断变化的标准库模块symlink/复制到虚拟环境中,以便在每次启动时执行一个微妙的引导绑定动作。(virtualenv必须复制二进制文件以提供隔离,因为python在搜索sys.prefix之前,python会取消对符号链接可执行文件的引用。注意python的启动过程)
PYTHONHOME环境变量是Python现有的唯一针对虚拟环境的内置解决方案,它需要将整个标准库复制/符号化链接到每个环境中。如果采用复制整个标准库的方法,就不是一个轻量级的解决方案。对符号链接的跨平台支持仍然不一致(即使在支持它们的Windows平台上,创建它们通常需要管理员特权)。
一个与Python集成的虚拟环境机制,并利用现有第三方工具的多年经验,可以降低维护,提高可靠性,并且更容易为所有Python用户方便使用。
特点
当执行python二进制文件时,它首先要做的确定其前缀(前缀存储在sys.prefix中);然后使用该前缀查找标准库和其他密钥文件,并由站点模块确定站点包目录的位置。以上是在设置PythonHome环境变量的前提下;假如没设定环境变量,当前的前缀将从遍历文件,通过首先在文件系统树上查找标记文件(os.py),找到前缀。如果还是找不到,则返回到二进制文件中硬编码的构建时前缀。
PEP的方案是:在此搜索中添加新的第一步。如果pyvenv.cfg文件靠近python.exe文件或其上的一个目录,(如果可执行文件是symlink,则不会取消引用),则会扫描pyvenv.cfg中的key=value格式行。如果找到了主密钥,这意味着python二进制文件属于虚拟环境,并且主密钥的值是包含用于创建此虚拟环境的python可执行文件的目录。
在这种情况下,前缀查找将继续正常使用主键的值作为有效的Python二进制位置,该位置可查找基本安装的前缀。 sys.base_prefix设置为此值,而sys.prefix设置为包含pyvenv.cfg的目录。
(如果未找到pyvenv.cfg或不包含主键,则前缀查找将继续正常,并且sys.prefix将等于sys.base_prefix。)
此外,添加了sys.base_exec_prefix,并且对sys.exec_prefix进行了类似的处理。 (sys.exec_prefix相当于sys.prefix,但对于特定于平台的文件;默认情况下,它与sys.prefix具有相同的值。)
修改了站点和sysconfig标准库模块,以便找到相对于sys.base_prefix / sys.base_exec_prefix的标准库和头文件,而site-package目录(“purelib”和“platlib”,在sysconfig术语中)仍然是找到相对于sys.prefix / sys.exec_prefix。
因此,最简单形式的Python虚拟环境只包含Python二进制文件的副本或符号链接,并附带pyvenv.cfg文件和site-packages目录。
从系统站点包隔离
默认情况下,虚拟环境与系统级site-packages目录完全隔离。
如果pyvenv.cfg文件还包含值为true(不区分大小写)的键include-system-site-packages,则站点模块还将在虚拟环境站点目录之后将系统站点目录添加到sys.path。因此,系统安装的包仍然是可导入的,但是在虚拟环境中安装的同名包将优先。
PEP 370用户级站点包被认为是用于venv目的的系统站点包的一部分:它们不是从隔离的venv中获得的,而是可以从include-system-site-packages = true venv获得。
Creating virtual environments
该PEP还建议在标准库中添加新的venv模块,以实现虚拟环境的创建。可以使用-m标志执行此模块:
python3 -m venv /path/to/new/virtual/environment
还提供了pyvenv安装的脚本,以使这更方便:
pyvenv /path/to/new/virtual/environment
运行此命令将创建目标目录(创建不存在的任何父目录)并在其中放置pyvenv.cfg文件,其中主键指向运行该命令的Python安装。它还创建了一个bin /(或Windows上的Scripts)子目录,其中包含python3可执行文件的副本(或符号链接),以及来自打包标准库模块的pysetup3脚本(以便于将包从PyPI轻松安装到新的venv中)。它创建了一个(最初为空)lib / pythonX.Y / site-packages(或Windows上的Lib \ site-packages)子目录。
如果目标目录已经存在,则会引发错误,除非提供了--clear选项,在这种情况下,目标目录将被删除,虚拟环境创建将照常进行。
创建的pyvenv.cfg文件还包括include-system-site-packages密钥,如果pyvenv使用--system-site-packages选项运行,则设置为true,默认情况下为false。
可以为pyvenv提供多个路径,在这种情况下,根据给定的选项,在每个提供的路径上将创建相同的venv。
venv模块还在venv的bin或Scripts目录中为POSIX和Windows系统放置“shell激活脚本”。这些脚本只是将虚拟环境的bin(或Scripts)目录添加到用户shell PATH的前面。这对于虚拟环境的使用并不是绝对必要的(作为venv的python二进制文件的显式路径或者脚本也可以使用),但它很方便。
为了允许pysetup和其他Python包管理器以与安装到普通Python安装相同的方式将软件包安装到虚拟环境中,并避免在sysconfig中使用sys.base_prefix代替sys.prefix进行特殊套管虚拟环境。适当的,内部虚拟环境布局模仿每个平台上Python安装本身的布局。因此,POSIX系统上的典型虚拟环境布局将是:
pyvenv.cfg bin/python3 bin/python bin/pysetup3 include/ lib/python3.3/site-packages/
在Windows系统上:
pyvenv.cfg Scripts/python.exe Scripts/python3.dll Scripts/pysetup3.exe Scripts/pysetup3-script.py ... other DLLs and pyds... Include/ Lib/site-packages/
安装到虚拟环境中的第三方软件包将其Python模块放置在site-packages目录中,并将其可执行文件放在bin /或Scripts中。
注意
在正常的Windows系统级安装中,Python二进制文件本身不会进入“Scripts /”子目录,就像在默认的venv布局中一样。这在虚拟环境中很有用,因此用户只需将单个目录添加到其shell PATH中,以便有效地“激活”虚拟环境。
注意
在Windows上,还需要将编译的stdlib模块中的DLL和pyd文件复制或符号链接到env,因为如果从非系统范围的Python安装创建venv,Windows将无法找到Python安装的从venv运行Python时这些文件的副本。
Sysconfig安装方案和用户站点
这种方法明确选择不为venvs引入新的sysconfig安装方案。相反,通过修改sys.prefix,我们确保在sys.prefix上基于位置的现有安装方案将仅在venv中工作。安装到其路径与sys.prefix无关的其他安装方案(例如,用户站点方案)根本不会受到venv的影响。
基于特定于虚拟的sysconfig方案创建Python虚拟环境的替代实现可能是可行的,但它不太健壮,因为需要更多代码才能知道它是否在虚拟环境中运行。
拷贝和符号连接
The technique in this PEP works equally well in general with a copied or symlinked Python binary (and other needed DLLs on Windows). Symlinking is preferable where possible, because in the case of an upgrade to the underlying Python installation, a Python executable copied in a venv might become out-of-sync with the installed standard library and require manual upgrade.
There are some cross-platform difficulties with symlinks:
- Not all Windows versions support symlinks, and even on those that do, creating them often requires administrator privileges.
- On OS X framework builds of Python, sys.executable is just a stub that executes the real Python binary. Symlinking this stub does not work; it must be copied. (Fortunately the stub is also small, and not changed by bugfix upgrades to Python, so copying it is not an issue).
Thus, this PEP proposes to symlink the binary on all platforms except for Windows, and OS X framework builds. A --symlink option is available to force the use of symlinks on Windows versions that support them, if the appropriate permissions are available. (This option has no effect on OS X framework builds, since symlinking can never work there, and has no advantages).
On Windows, if --symlink is not used, this means that if the underlying Python installation is upgraded, the Python binary and DLLs in the venv should be updated, or there could be issues of mismatch with the upgraded standard library. The pyvenv script accepts a --upgrade option for easily performing this upgrade on an existing venv.
Include files
Current virtualenv handles include files in this way:
On POSIX systems where the installed Python's include files are found in ${base_prefix}/include/pythonX.X, virtualenv creates ${venv}/include/ and symlinks ${base_prefix}/include/pythonX.X to ${venv}/include/pythonX.X. On Windows, where Python's include files are found in {{ sys.prefix }}/Include and symlinks are not reliably available, virtualenv copies {{ sys.prefix }}/Include to ${venv}/Include. This ensures that extension modules built and installed within the virtualenv will always find the Python header files they need in the expected location relative to sys.prefix.
This solution is not ideal when an extension module installs its own header files, as the default installation location for those header files may be a symlink to a system directory that may not be writable. One installer, pip, explicitly works around this by installing header files to a nonstandard location ${venv}/include/site/pythonX.X/, as in Python there's currently no standard abstraction for a site-specific include directory.
This PEP proposes a slightly different approach, though one with essentially the same effect and the same set of advantages and disadvantages. Rather than symlinking or copying include files into the venv, we simply modify the sysconfig schemes so that header files are always sought relative to base_prefix rather than prefix. (We also create an include/ directory within the venv, so installers have somewhere to put include files installed within the env).
Better handling of include files in distutils/packaging and, by extension, pyvenv, is an area that may deserve its own future PEP. For now, we propose that the behavior of virtualenv has thus far proved itself to be at least "good enough" in practice.
API
The high-level method described above makes use of a simple API which provides mechanisms for third-party virtual environment creators to customize environment creation according to their needs.
The venv module contains an EnvBuilder class which accepts the following keyword arguments on instantiation:
- system_site_packages - A Boolean value indicating that the system Python site-packages should be available to the environment. Defaults to False.
- clear - A Boolean value which, if true, will delete any existing target directory instead of raising an exception. Defaults to False.
- symlinks - A Boolean value indicating whether to attempt to symlink the Python binary (and any necessary DLLs or other binaries, e.g. pythonw.exe), rather than copying. Defaults to False.
The instantiated env-builder has a create method, which takes as required argument the path (absolute or relative to the current directory) of the target directory which is to contain the virtual environment. The create method either creates the environment in the specified directory, or raises an appropriate exception.
The venv module also provides a module-level create function as a convenience:
def create(env_dir, system_site_packages=False, clear=False, use_symlinks=False): builder = EnvBuilder( system_site_packages=system_site_packages, clear=clear, use_symlinks=use_symlinks) builder.create(env_dir)
Creators of third-party virtual environment tools are free to use the provided EnvBuilder class as a base class.
The create method of the EnvBuilder class illustrates the hooks available for customization:
def create(self, env_dir): """ Create a virtualized Python environment in a directory. :param env_dir: The target directory to create an environment in. """ env_dir = os.path.abspath(env_dir) context = self.create_directories(env_dir) self.create_configuration(context) self.setup_python(context) self.post_setup(context)
Each of the methods create_directories, create_configuration, setup_python, and post_setup can be overridden. The functions of these methods are:
- create_directories - creates the environment directory and all necessary directories, and returns a context object. This is just a holder for attributes (such as paths), for use by the other methods.
- create_configuration - creates the pyvenv.cfg configuration file in the environment.
- setup_python - creates a copy of the Python executable (and, under Windows, DLLs) in the environment.
- post_setup - A (no-op by default) hook method which can be overridden in third party subclasses to pre-install packages or install scripts in the virtual environment.
In addition, EnvBuilder provides a utility method that can be called from post_setup in subclasses to assist in installing custom scripts into the virtual environment. The method install_scripts accepts as arguments the context object (see above) and a path to a directory. The directory should contain subdirectories "common", "posix", "nt", each containing scripts destined for the bin directory in the environment. The contents of "common" and the directory corresponding to os.name are copied after doing some text replacement of placeholders:
- __VENV_DIR__ is replaced with absolute path of the environment directory.
- __VENV_NAME__ is replaced with the environment name (final path segment of environment directory).
- __VENV_BIN_NAME__ is replaced with the name of the bin directory (either bin or Scripts).
- __VENV_PYTHON__ is replaced with the absolute path of the environment's executable.
The DistributeEnvBuilder subclass in the reference implementation illustrates how the customization hook can be used in practice to pre-install Distribute into the virtual environment. It's not envisaged that DistributeEnvBuilder will be actually added to Python core, but it makes the reference implementation more immediately useful for testing and exploratory purposes.
Backwards Compatibility
Splitting the meanings of sys.prefix
Any virtual environment tool along these lines (which attempts to isolate site-packages, while still making use of the base Python's standard library with no need for it to be symlinked into the virtual environment) is proposing a split between two different meanings (among others) that are currently both wrapped up in sys.prefix: the answers to the questions "Where is the standard library?" and "Where is the site-packages location where third-party modules should be installed?"
This split could be handled by introducing a new sys attribute for either the former prefix or the latter prefix. Either option potentially introduces some backwards-incompatibility with software written to assume the other meaning for sys.prefix. (Such software should preferably be using the APIs in the site and sysconfig modules to answer these questions rather than using sys.prefix directly, in which case there is no backwards-compatibility issue, but in practice sys.prefix is sometimes used.)
The documentation [7] for sys.prefix describes it as "A string giving the site-specific directory prefix where the platform independent Python files are installed," and specifically mentions the standard library and header files as found under sys.prefix. It does not mention site-packages.
Maintaining this documented definition would mean leaving sys.prefix pointing to the base system installation (which is where the standard library and header files are found), and introducing a new value in sys (something like sys.site_prefix) to point to the prefix for site-packages. This would maintain the documented semantics of sys.prefix, but risk breaking isolation if third-party code uses sys.prefix rather than sys.site_prefix or the appropriate site API to find site-packages directories.
The most notable case is probably setuptools [3] and its fork distribute [4], which mostly use distutils and sysconfig APIs, but do use sys.prefix directly to build up a list of site directories for pre-flight checking where pth files can usefully be placed.
Otherwise, a Google Code Search [5] turns up what appears to be a roughly even mix of usage between packages using sys.prefix to build up a site-packages path and packages using it to e.g. eliminate the standard-library from code-execution tracing.
Although it requires modifying the documented definition of sys.prefix, this PEP prefers to have sys.prefix point to the virtual environment (where site-packages is found), and introduce sys.base_prefix to point to the standard library and Python header files. Rationale for this choice:
- It is preferable to err on the side of greater isolation of the virtual environment.
- Virtualenv already modifies sys.prefix to point at the virtual environment, and in practice this has not been a problem.
- No modification is required to setuptools/distribute.
Impact on other Python implementations
The majority of this PEP's changes occur in the standard library, which is shared by other Python implementations and should not present any problem.
Other Python implementations will need to replicate the new sys.prefix-finding behavior of the interpreter bootstrap, including locating and parsing the pyvenv.cfg file, if it is present.
Reference Implementation
The reference implementation is found in a clone of the CPython Mercurial repository [6]. To test it, build and run bin/pyvenv /path/to/new/venv to create a virtual environment.
References
[1] | http://www.virtualenv.org |
[2] | https://github.com/kvbik/rvirtualenv |
[3] | http://peak.telecommunity.com/DevCenter/setuptools |
[4] | http://packages.python.org/distribute/ |
[5] | http://www.google.com/codesearch#search/&q=sys.prefix&p=1&type=cs |
[6] | http://hg.python.org/sandbox/vsajip#venv |
[7] | http://docs.python.org/dev/library/sys.html#sys.prefix |
Copyright
This document has been placed in the public domain.
Source: https://github.com/python/peps/blob/master/pep-0405.txt