venv --- 創(chuàng)建虛擬環(huán)境?
3.3 新版功能.
源碼: Lib/venv/
venv 模塊支持使用自己的站點(diǎn)目錄創(chuàng)建輕量級(jí)“虛擬環(huán)境”,可選擇與系統(tǒng)站點(diǎn)目錄隔離。每個(gè)虛擬環(huán)境都有自己的 Python 二進(jìn)制文件(與用于創(chuàng)建此環(huán)境的二進(jìn)制文件的版本相匹配),并且可以在其站點(diǎn)目錄中擁有自己獨(dú)立的已安裝 Python 軟件包集。
有關(guān) Python 虛擬環(huán)境的更多信息,請(qǐng)參閱 PEP 405 。
注解
從 Python 3.6 開始,不推薦使用 pyvenv 腳本,而是使用 python3 -m venv 來幫助防止任何關(guān)于虛擬環(huán)境將基于哪個(gè) Python 解釋器的混淆。
創(chuàng)建虛擬環(huán)境?
通過執(zhí)行 venv 指令來創(chuàng)建一個(gè) 虛擬環(huán)境:
python3 -m venv /path/to/new/virtual/environment
Running this command creates the target directory (creating any parent
directories that don't exist already) and places a pyvenv.cfg file in it
with a home key pointing to the Python installation from which the command
was run. It also creates a bin (or Scripts on Windows) subdirectory
containing a copy/symlink of the Python binary/binaries (as appropriate for the
platform or arguments used at environment creation time). It also creates an
(initially empty) lib/pythonX.Y/site-packages subdirectory
(on Windows, this is Lib\site-packages). If an existing
directory is specified, it will be re-used.
3.6 版后已移除: pyvenv 是 Python 3.3 和 3.4 中創(chuàng)建虛擬環(huán)境的推薦工具,不過 在 Python 3.6 中已棄用。
在 3.5 版更改: 現(xiàn)在推薦使用 venv 來創(chuàng)建虛擬環(huán)境。
在 Windows 上,調(diào)用 venv 命令如下:
c:\>c:\Python35\python -m venv c:\path\to\myenv
或者,如果已經(jīng)為 Python 安裝 配置好 PATH 和 PATHEXT 變量:
c:\>python -m venv c:\path\to\myenv
本命令如果以 -h 參數(shù)運(yùn)行,將顯示可用的選項(xiàng):
usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear]
[--upgrade] [--without-pip] [--prompt PROMPT]
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.
Once an environment has been created, you may wish to activate it, e.g. by
sourcing an activate script in its bin directory.
在 3.4 版更改: 默認(rèn)安裝 pip,并添加 --without-pip 和 --copies 選項(xiàng)
在 3.4 版更改: 在早期版本中,如果目標(biāo)目錄已存在,將引發(fā)錯(cuò)誤,除非使用了 --clear 或 --upgrade 選項(xiàng)。
注解
雖然 Windows 支持符號(hào)鏈接,但不推薦使用它們。特別注意,在文件資源管理器中雙擊 python.exe 將立即解析符號(hào)鏈接,并忽略虛擬環(huán)境。
生成的 pyvenv.cfg 文件還包括 include-system-site-packages 鍵,如果運(yùn)行 venv 帶有 --system-site-packages 選項(xiàng),則鍵值為 true,否則為 false。
除非采用 --without-pip 選項(xiàng),否則將會(huì)調(diào)用 ensurepip 將 pip 引導(dǎo)到虛擬環(huán)境中。
可以向 venv 傳入多個(gè)路徑,此時(shí)將根據(jù)給定的選項(xiàng),在所給的每個(gè)路徑上創(chuàng)建相同的虛擬環(huán)境。
創(chuàng)建虛擬環(huán)境后,可以使用虛擬環(huán)境的二進(jìn)制目錄中的腳本來“激活”該環(huán)境。不同平臺(tái)調(diào)用的腳本是不同的(須將 <venv> 替換為包含虛擬環(huán)境的目錄路徑):
平臺(tái) |
Shell |
用于激活虛擬環(huán)境的命令 |
|---|---|---|
Posix |
bash/zsh |
$ source <venv>/bin/activate |
fish |
$ . <venv>/bin/activate.fish |
|
csh/tcsh |
$ source <venv>/bin/activate.csh |
|
Windows |
cmd.exe |
C:\> <venv>\Scripts\activate.bat |
PowerShell |
PS C:\> <venv>\Scripts\Activate.ps1 |
激活環(huán)境不是 必須 的,激活只是將虛擬環(huán)境的二進(jìn)制目錄添加到搜索路徑中,這樣 "python" 命令將調(diào)用虛擬環(huán)境的 Python 解釋器,可以運(yùn)行其中已安裝的腳本,而不必輸入其完整路徑。但是,安裝在虛擬環(huán)境中的所有腳本都應(yīng)在不激活的情況下可運(yùn)行,并自動(dòng)與虛擬環(huán)境的 Python 一起運(yùn)行。
在 shell 中輸入 "deactivate" 可以退出虛擬環(huán)境。具體機(jī)制取決于不同平臺(tái),并且是內(nèi)部實(shí)現(xiàn)(通常使用腳本或 shell 函數(shù))。
3.4 新版功能: fish 和 csh 激活腳本。
注解
虛擬環(huán)境是一個(gè) Python 環(huán)境,安裝到其中的 Python 解釋器、庫(kù)和腳本與其他虛擬環(huán)境中的內(nèi)容是隔離的,且(默認(rèn))與“系統(tǒng)級(jí)” Python(操作系統(tǒng)的一部分)中安裝的庫(kù)是隔離的。
虛擬環(huán)境是一個(gè)目錄樹,其中包含 Python 可執(zhí)行文件和其他文件,其他文件指示了這是一個(gè)是虛擬環(huán)境。
常用安裝工具如 setuptools 和 pip 可以在虛擬環(huán)境中按預(yù)期工作。換句話說,當(dāng)虛擬環(huán)境被激活,它們就會(huì)將 Python 軟件包安裝到虛擬環(huán)境中,無需明確指示。
當(dāng)虛擬環(huán)境被激活(即虛擬環(huán)境的 Python 解釋器正在運(yùn)行),屬性 sys.prefix 和 sys.exec_prefix 指向的是虛擬環(huán)境的基礎(chǔ)目錄,而 sys.base_prefix 和 sys.base_exec_prefix 指向非虛擬環(huán)境的 Python 安裝,即曾用于創(chuàng)建虛擬環(huán)境的那個(gè) Python 安裝。如果虛擬環(huán)境沒有被激活,則 sys.prefix 與 sys.base_prefix 相同,且 sys.exec_prefix 與 sys.base_exec_prefix 相同(它們均指向非虛擬環(huán)境的 Python 安裝)。
當(dāng)虛擬環(huán)境被激活,所有 distutils 配置文件中更改安裝路徑的選項(xiàng)都會(huì)被忽略,以防止無意中將項(xiàng)目安裝在虛擬環(huán)境之外。
在命令行 shell 中工作時(shí),用戶可以運(yùn)行虛擬環(huán)境可執(zhí)行文件目錄中的 activate 腳本來激活虛擬環(huán)境(調(diào)用該文件的確切文件名和命令取決于 shell),這會(huì)將虛擬環(huán)境的可執(zhí)行文件目錄添加到當(dāng)前 shell 的 PATH 環(huán)境變量。在其他情況下,無需激活虛擬環(huán)境。安裝到虛擬環(huán)境中的腳本有 "shebang" 行,指向虛擬環(huán)境的 Python 解釋器。這意味著無論 PATH 的值如何,腳本都將與該解釋器一起運(yùn)行。在 Windows 上,如果已安裝 Python Launcher for Windows,則支持處理 "shebang" 行(此功能在 Python 3.3 中添加,詳情請(qǐng)參閱 PEP 397)。這樣,在 Windows 資源管理器中雙擊已安裝的腳本,應(yīng)該會(huì)使用正確的解釋器運(yùn)行該腳本,而在 PATH 中無需指向其虛擬環(huán)境。
API?
上述的高級(jí)方法使用了一個(gè)簡(jiǎn)單的 API,該 API 提供了一種機(jī)制,第三方虛擬環(huán)境創(chuàng)建者可以根據(jù)其需求自定義環(huán)境創(chuàng)建過程,該 API?為 EnvBuilder 類。
-
class
venv.EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False, with_pip=False, prompt=None)? EnvBuilder類在實(shí)例化時(shí)接受以下關(guān)鍵字參數(shù):system_site_packages-- 一個(gè)布爾值,要求系統(tǒng) Python 的 site-packages 對(duì)環(huán)境可用(默認(rèn)為False)。clear-- 一個(gè)布爾值,如果為 true,則在創(chuàng)建環(huán)境前將刪除目標(biāo)目錄的現(xiàn)有內(nèi)容。symlinks-- 一個(gè)布爾值,指示是否嘗試符號(hào)鏈接 Python 二進(jìn)制文件,而不是進(jìn)行復(fù)制。upgrade-- 一個(gè)布爾值,如果為 true,則將使用當(dāng)前運(yùn)行的 Python 去升級(jí)一個(gè)現(xiàn)有的環(huán)境,這主要在原位置的 Python 更新后使用(默認(rèn)為False)。with_pip-- 一個(gè)布爾值,如果為 true,則確保在虛擬環(huán)境中已安裝 pip。這使用的是帶有--default-pip選項(xiàng)的ensurepip。prompt-- a String to be used after virtual environment is activated (defaults toNonewhich means directory name of the environment would be used).
在 3.4 版更改: 添加
with_pip參數(shù)3.6 新版功能: 添加
prompt參數(shù)第三方虛擬環(huán)境工具的創(chuàng)建者可以自由地將此處提供的
EnvBuilder類作為基類。返回的 env-builder 是一個(gè)對(duì)象,包含一個(gè)
create方法:-
create(env_dir)? 指定要建立虛擬環(huán)境的目標(biāo)目錄(絕對(duì)路徑或相對(duì)于當(dāng)前路徑)來創(chuàng)建虛擬環(huán)境。
create方法將在指定目錄中創(chuàng)建環(huán)境,或者引發(fā)對(duì)應(yīng)的異常。EnvBuilder類的create方法說明了可用于定制子類的鉤子: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)
每個(gè)方法
ensure_directories(),create_configuration(),setup_python(),setup_scripts()和post_setup()?都可以被重寫。
-
ensure_directories(env_dir)? 創(chuàng)建環(huán)境目錄和所有必需的目錄,并返回一個(gè)上下文對(duì)象。該對(duì)象只是一個(gè)容器,保存屬性(如路徑),供其他方法使用。允許目錄已經(jīng)存在,如果指定了
clear或upgrade就允許在現(xiàn)有環(huán)境目錄上進(jìn)行操作。
-
create_configuration(context)? 在環(huán)境中創(chuàng)建
pyvenv.cfg配置文件。
-
setup_python(context)? 在環(huán)境中創(chuàng)建 Python 可執(zhí)行文件的拷貝或符號(hào)鏈接。在 POSIX 系統(tǒng)上,如果給定了可執(zhí)行文件
python3.x,將創(chuàng)建指向該可執(zhí)行文件的python和python3符號(hào)鏈接,除非相同名稱的文件已經(jīng)存在。
-
setup_scripts(context)? 將適用于平臺(tái)的激活腳本安裝到虛擬環(huán)境中。
-
post_setup(context)? 占位方法,可以在第三方實(shí)現(xiàn)中重寫,用于在虛擬環(huán)境中預(yù)安裝軟件包,或是其他創(chuàng)建后要執(zhí)行的步驟。
在 3.7.2 版更改: Windows 現(xiàn)在為
python[w].exe使用重定向腳本,而不是復(fù)制實(shí)際的二進(jìn)制文件。僅在 3.7.2 中,除非運(yùn)行的是源碼樹中的構(gòu)建,否則setup_python()不會(huì)執(zhí)行任何操作。在 3.7.3 版更改: Windows 將重定向腳本復(fù)制為
setup_python()的一部分而非setup_scripts()。在 3.7.2 中不是這種情況。使用符號(hào)鏈接時(shí),將鏈接至原始可執(zhí)行文件。此外,
EnvBuilder提供了如下實(shí)用方法,可以從子類的setup_scripts()或post_setup()調(diào)用,用來將自定義腳本安裝到虛擬環(huán)境中。-
install_scripts(context, path)? path 是一個(gè)目錄的路徑,該目錄應(yīng)包含子目錄 "common", "posix", "nt",每個(gè)子目錄存有發(fā)往對(duì)應(yīng)環(huán)境中 bin 目錄的腳本。在下列占位符替換完畢后,將復(fù)制 "common" 的內(nèi)容和與
os.name對(duì)應(yīng)的子目錄:__VENV_DIR__會(huì)被替換為環(huán)境目錄的絕對(duì)路徑。__VENV_NAME__會(huì)被替換為環(huán)境名稱(環(huán)境目錄的最后一個(gè)字段)。__VENV_PROMPT__會(huì)被替換為提示符(用括號(hào)括起來的環(huán)境名稱緊跟著一個(gè)空格)。__VENV_BIN_NAME__會(huì)被替換為 bin 目錄的名稱(bin或Scripts)。__VENV_PYTHON__會(huì)被替換為環(huán)境可執(zhí)行文件的絕對(duì)路徑。
允許目錄已存在(用于升級(jí)現(xiàn)有環(huán)境時(shí))。
有一個(gè)方便實(shí)用的模塊級(jí)別的函數(shù):
-
venv.create(env_dir, system_site_packages=False, clear=False, symlinks=False, with_pip=False, prompt=None)? 通過關(guān)鍵詞參數(shù)來創(chuàng)建一個(gè)
EnvBuilder,并且使用 env_dir 參數(shù)來調(diào)用它的create()方法。3.3 新版功能.
在 3.4 版更改: 添加
with_pip參數(shù)在 3.6 版更改: 添加
prompt參數(shù)
一個(gè)擴(kuò)展 EnvBuilder 的例子?
下面的腳本展示了如何通過實(shí)現(xiàn)一個(gè)子類來擴(kuò)展 EnvBuilder。這個(gè)子類會(huì)安裝 setuptotols 和 pip 的到被創(chuàng)建的虛擬環(huán)境中。
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)
這個(gè)腳本同樣可以 在線下載。
