venv
--- 創(chuàng)建虛擬環(huán)境?
3.3 新版功能.
源碼: Lib/venv/
venv
模塊支持使用自己的站點目錄創(chuàng)建輕量級“虛擬環(huán)境”,可選擇與系統(tǒng)站點目錄隔離。每個虛擬環(huán)境都有自己的 Python 二進(jìn)制文件(與用于創(chuàng)建此環(huán)境的二進(jìn)制文件的版本相匹配),并且可以在其站點目錄中擁有自己獨立的已安裝 Python 軟件包集。
有關(guān) Python 虛擬環(huán)境的更多信息,請參閱 PEP 405 。
創(chuàng)建虛擬環(huán)境?
通過執(zhí)行 venv
指令來創(chuàng)建一個 虛擬環(huán)境:
python3 -m venv /path/to/new/virtual/environment
運行此命令將創(chuàng)建目標(biāo)目錄(父目錄若不存在也將創(chuàng)建),并放置一個 pyvenv.cfg
文件在其中,文件中有一個 home
鍵,它的值指向運行此命令的 Python 安裝(目標(biāo)目錄的常用名稱是 .venv
)。它還會創(chuàng)建一個 bin
子目錄(在 Windows 上是 Scripts
),其中包含 Python 二進(jìn)制文件的副本或符號鏈接(視創(chuàng)建環(huán)境時使用的平臺或參數(shù)而定)。它還會創(chuàng)建一個(初始為空的) lib/pythonX.Y/site-packages
子目錄(在 Windows 上是 Lib\site-packages
)。如果指定了一個現(xiàn)有的目錄,這個目錄就將被重新使用。
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ù)運行,將顯示可用的選項:
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 + setuptools 升級到 PyPI 上的最新版本
在 3.4 版更改: 默認(rèn)安裝 pip,并添加 --without-pip
和 --copies
選項
在 3.4 版更改: 在早期版本中,如果目標(biāo)目錄已存在,將引發(fā)錯誤,除非使用了 --clear
或 --upgrade
選項。
備注
雖然 Windows 支持符號鏈接,但不推薦使用它們。特別注意,在文件資源管理器中雙擊 python.exe
將立即解析符號鏈接,并忽略虛擬環(huán)境。
備注
在 Microsoft Windows 上,為了啟用 Activate.ps1
腳本,可能需要修改用戶的執(zhí)行策略??梢赃\行以下 PowerShell 命令來執(zhí)行此操作:
PS C:> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
參閱 About Execution Policies 以獲取更多信息。
生成的 pyvenv.cfg
文件還包括 include-system-site-packages
鍵,如果運行 venv
時帶有 --system-site-packages
選項,則鍵值為 true
,否則為 false
。
除非采用 --without-pip
選項,否則將會調(diào)用 ensurepip
將 pip
引導(dǎo)到虛擬環(huán)境中。
可以向 venv
傳入多個路徑,此時將根據(jù)給定的選項,在所給的每個路徑上創(chuàng)建相同的虛擬環(huán)境。
創(chuàng)建虛擬環(huán)境后,可以使用虛擬環(huán)境的二進(jìn)制目錄中的腳本來“激活”該環(huán)境。不同平臺調(diào)用的腳本是不同的(須將 <venv> 替換為包含虛擬環(huán)境的目錄路徑):
平臺 |
Shell |
用于激活虛擬環(huán)境的命令 |
---|---|---|
POSIX |
bash/zsh |
$ source <venv>/bin/activate |
fish |
$ source <venv>/bin/activate.fish |
|
csh/tcsh |
$ source <venv>/bin/activate.csh |
|
PowerShell Core |
$ <venv>/bin/Activate.ps1 |
|
Windows |
cmd.exe |
C:\> <venv>\Scripts\activate.bat |
PowerShell |
PS C:\> <venv>\Scripts\Activate.ps1 |
當(dāng)一個虛擬環(huán)境被激活時,VIRTUAL_ENV
環(huán)境變量會被設(shè)為該虛擬環(huán)境的路徑。 這可被用來檢測程序是否運行在虛擬環(huán)境中。
激活環(huán)境不是 必須 的,激活只是將虛擬環(huán)境的二進(jìn)制目錄添加到搜索路徑中,這樣 "python" 命令將調(diào)用虛擬環(huán)境的 Python 解釋器,可以運行其中已安裝的腳本,而不必輸入其完整路徑。但是,安裝在虛擬環(huán)境中的所有腳本都應(yīng)在不激活的情況下可運行,并自動與虛擬環(huán)境的 Python 一起運行。
在 shell 中輸入 "deactivate" 可以退出虛擬環(huán)境。具體機(jī)制取決于不同平臺,并且是內(nèi)部實現(xiàn)(通常使用腳本或 shell 函數(shù))。
3.4 新版功能: fish
和 csh
激活腳本。
3.8 新版功能: 在 POSIX 上安裝 PowerShell 激活腳本,以支持 PowerShell Core。
備注
虛擬環(huán)境是一個 Python 環(huán)境,安裝到其中的 Python 解釋器、庫和腳本與其他虛擬環(huán)境中的內(nèi)容是隔離的,且(默認(rèn))與“系統(tǒng)級” Python(操作系統(tǒng)的一部分)中安裝的庫是隔離的。
虛擬環(huán)境是一個目錄樹,其中包含 Python 可執(zhí)行文件和其他文件,其他文件指示了這是一個是虛擬環(huán)境。
常用安裝工具如 setuptools 和 pip 可以在虛擬環(huán)境中按預(yù)期工作。換句話說,當(dāng)虛擬環(huán)境被激活,它們就會將 Python 軟件包安裝到虛擬環(huán)境中,無需明確指示。
當(dāng)虛擬環(huán)境被激活(即虛擬環(huán)境的 Python 解釋器正在運行),屬性 sys.prefix
和 sys.exec_prefix
指向的是虛擬環(huán)境的基礎(chǔ)目錄,而 sys.base_prefix
和 sys.base_exec_prefix
指向非虛擬環(huán)境的 Python 安裝,即曾用于創(chuàng)建虛擬環(huán)境的那個 Python 安裝。如果虛擬環(huán)境沒有被激活,則 sys.prefix
與 sys.base_prefix
相同,且 sys.exec_prefix
與 sys.base_exec_prefix
相同(它們均指向非虛擬環(huán)境的 Python 安裝)。
當(dāng)虛擬環(huán)境被激活,所有 distutils
配置文件中更改安裝路徑的選項都會被忽略,以防止無意中將項目安裝在虛擬環(huán)境之外。
在命令行 shell 中工作時,用戶可以運行虛擬環(huán)境可執(zhí)行文件目錄中的 activate
腳本來激活虛擬環(huán)境(調(diào)用該文件的確切文件名和命令取決于 shell),這會將虛擬環(huán)境的可執(zhí)行文件目錄添加到當(dāng)前 shell 的 PATH
環(huán)境變量。在其他情況下,無需激活虛擬環(huán)境。安裝到虛擬環(huán)境中的腳本有 "shebang" 行,指向虛擬環(huán)境的 Python 解釋器。這意味著無論 PATH
的值如何,腳本都將與該解釋器一起運行。在 Windows 上,如果已安裝 Python Launcher for Windows,則支持處理 "shebang" 行(此功能在 Python 3.3 中添加,詳情請參閱 PEP 397)。這樣,在 Windows 資源管理器中雙擊已安裝的腳本,應(yīng)該會使用正確的解釋器運行該腳本,而在 PATH
中無需指向其虛擬環(huán)境。
API?
上述的高級方法使用了一個簡單的 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, upgrade_deps=False)?
EnvBuilder
類在實例化時接受以下關(guān)鍵字參數(shù):system_site_packages
-- 一個布爾值,要求系統(tǒng) Python 的 site-packages 對環(huán)境可用(默認(rèn)為False
)。clear
-- 一個布爾值,如果為 true,則在創(chuàng)建環(huán)境前將刪除目標(biāo)目錄的現(xiàn)有內(nèi)容。symlinks
-- 一個布爾值,指示是否嘗試符號鏈接 Python 二進(jìn)制文件,而不是進(jìn)行復(fù)制。upgrade
-- 一個布爾值,如果為 true,則將使用當(dāng)前運行的 Python 去升級一個現(xiàn)有的環(huán)境,這主要在原位置的 Python 更新后使用(默認(rèn)為False
)。with_pip
-- 一個布爾值,如果為 true,則確保在虛擬環(huán)境中已安裝 pip。這使用的是帶有--default-pip
選項的ensurepip
。prompt
-- 激活虛擬環(huán)境后顯示的提示符(默認(rèn)為None
,表示使用環(huán)境所在的目錄名稱)。如果使用了"."
這一特殊字符串,則使用當(dāng)前目錄的基本名稱作為提示符。upgrade_deps
-- 將基本 venv 模塊更新為 PyPI 上的最新版本。
在 3.4 版更改: 添加
with_pip
參數(shù)3.6 新版功能: 添加
prompt
參數(shù)3.9 新版功能: 添加
upgrade_deps
參數(shù)第三方虛擬環(huán)境工具的創(chuàng)建者可以自由地將此處提供的
EnvBuilder
類作為基類。返回的 env-builder 是一個對象,包含一個
create
方法:- create(env_dir)?
指定要建立虛擬環(huán)境的目標(biāo)目錄(絕對路徑或相對于當(dāng)前路徑)來創(chuàng)建虛擬環(huán)境。
create
方法將在指定目錄中創(chuàng)建環(huán)境,或者引發(fā)對應(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)
每個方法
ensure_directories()
,create_configuration()
,setup_python()
,setup_scripts()
和post_setup()
都可以被重寫。
- ensure_directories(env_dir)?
Creates the environment directory and all necessary subdirectories that don't already exist, and returns a context object. This context object is just a holder for attributes (such as paths) for use by the other methods. If the
EnvBuilder
is created with the argclear=True
, contents of the environment directory will be cleared and then all necessary subdirectories will be recreated.在 3.11 版更改: The venv sysconfig installation scheme is used to construct the paths of the created directories.
- create_configuration(context)?
在環(huán)境中創(chuàng)建
pyvenv.cfg
配置文件。
- setup_python(context)?
在環(huán)境中創(chuàng)建 Python 可執(zhí)行文件的拷貝或符號鏈接。在 POSIX 系統(tǒng)上,如果給定了可執(zhí)行文件
python3.x
,將創(chuàng)建指向該可執(zhí)行文件的python
和python3
符號鏈接,除非相同名稱的文件已經(jīng)存在。
- setup_scripts(context)?
將適用于平臺的激活腳本安裝到虛擬環(huán)境中。
- upgrade_dependencies(context)?
升級環(huán)境中 venv 依賴的核心軟件包(當(dāng)前為
pip
和setuptools
)。通過在環(huán)境中使用pip
可執(zhí)行文件來完成。3.9 新版功能.
- post_setup(context)?
占位方法,可以在第三方實現(xiàn)中重寫,用于在虛擬環(huán)境中預(yù)安裝軟件包,或是其他創(chuàng)建后要執(zhí)行的步驟。
在 3.7.2 版更改: Windows 現(xiàn)在為
python[w].exe
使用重定向腳本,而不是復(fù)制實際的二進(jìn)制文件。僅在 3.7.2 中,除非運行的是源碼樹中的構(gòu)建,否則setup_python()
不會執(zhí)行任何操作。在 3.7.3 版更改: Windows 將重定向腳本復(fù)制為
setup_python()
的一部分而非setup_scripts()
。在 3.7.2 中不是這種情況。使用符號鏈接時,將鏈接至原始可執(zhí)行文件。此外,
EnvBuilder
提供了如下實用方法,可以從子類的setup_scripts()
或post_setup()
調(diào)用,用來將自定義腳本安裝到虛擬環(huán)境中。- install_scripts(context, path)?
path 是一個目錄的路徑,該目錄應(yīng)包含子目錄 "common", "posix", "nt",每個子目錄存有發(fā)往對應(yīng)環(huán)境中 bin 目錄的腳本。在下列占位符替換完畢后,將復(fù)制 "common" 的內(nèi)容和與
os.name
對應(yīng)的子目錄:__VENV_DIR__
會被替換為環(huán)境目錄的絕對路徑。__VENV_NAME__
會被替換為環(huán)境名稱(環(huán)境目錄的最后一個字段)。__VENV_PROMPT__
會被替換為提示符(用括號括起來的環(huán)境名稱緊跟著一個空格)。__VENV_BIN_NAME__
會被替換為 bin 目錄的名稱(bin
或Scripts
)。__VENV_PYTHON__
會被替換為環(huán)境可執(zhí)行文件的絕對路徑。
允許目錄已存在(用于升級現(xiàn)有環(huán)境時)。
有一個方便實用的模塊級別的函數(shù):
- venv.create(env_dir, system_site_packages=False, clear=False, symlinks=False, with_pip=False, prompt=None, upgrade_deps=False)?
通過關(guān)鍵詞參數(shù)來創(chuàng)建一個
EnvBuilder
,并且使用 env_dir 參數(shù)來調(diào)用它的create()
方法。3.3 新版功能.
在 3.4 版更改: 添加
with_pip
參數(shù)在 3.6 版更改: 添加
prompt
參數(shù)在 3.9 版更改: 添加
upgrade_deps
參數(shù)
一個擴(kuò)展 EnvBuilder
的例子?
下面的腳本展示了如何通過實現(xiàn)一個子類來擴(kuò)展 EnvBuilder
。這個子類會安裝 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://bootstrap.pypa.io/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)
這個腳本同樣可以 在線下載。