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