背景
- 針對離線環(huán)境存在python版本不匹配涉枫,安裝三方庫緩慢或無外網(wǎng)的情況下,需要制作可移植的解釋器及其附帶的庫文件。
- 由于sys.path是在安裝時設(shè)置(見下圖),直接壓縮安裝的python解釋器及其lib,include文件必然導(dǎo)致不兼容捶箱。
- conda雖然內(nèi)置python解釋器但同樣需要安裝,不夠輕便
#sys.py
base_exec_prefix = 'C:\\ProgramData\\Anaconda3'
base_prefix = 'C:\\ProgramData\\Anaconda3'
byteorder = 'little'
copyright = 'Copyright (c) 2001-2019 Python Software Foundation.\nAll Rights Reserved.\n\nCopyright (c) 2000 BeOpen.com.\nAll Rights Reserved.\n\nCopyright (c) 1995-2001 Corporation for National Research Initiatives.\nAll Rights Reserved.\n\nCopyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\nAll Rights Reserved.'
dllhandle = 140724640546816
dont_write_bytecode = True
executable = 'C:\\ProgramData\\Anaconda3\\python.exe'
exec_prefix = 'C:\\ProgramData\\Anaconda3'
解決方案
使用virtualenv制作虛擬環(huán)境动漾,將原解釋器中l(wèi)ib丁屎、include與site-packages等不依賴路徑文件替換,并修改若干啟動項旱眯。
virtualenv用于制作虛擬環(huán)境晨川,python3.3后的標(biāo)準(zhǔn)庫中venv集成了virtualenv一些關(guān)鍵功能,具體區(qū)別:
virtualenv
is a tool to create isolated Python environments.Since Python3.3
, a subset of it has been integrated into the standard library under the venv module. Thevenv
module does not offer all features of this library, to name just a few more prominent:
- is slower (by not having the
app-data
seed method), - is not as extendable,
- cannot create virtual environments for arbitrarily installed python versions (and automatically discover these),
- is not upgrade-able via pip,
- does not have as rich programmatic API (describe virtual environments without creating them).
virtualenv命令選項
usage: virtualenv [--version] [--with-traceback] [-v | -q] [--discovery {builtin}] [-p py] [--creator {builtin,cpython2-posix}] [--seeder {app-data,pip}] [--no-seed] [--activators comma_separated_list] [--clear] [--system-site-packages]
[--symlinks | --copies] [--download | --no-download] [--extra-search-dir d [d ...]] [--pip version] [--setuptools version] [--wheel version] [--no-pip] [--no-setuptools] [--no-wheel] [--clear-app-data] [--symlink-app-data]
[--prompt prompt] [-h]
dest
optional arguments:
--version display the version of the virtualenv package and it's location, then exit
--with-traceback on failure also display the stacktrace internals of virtualenv (default: False)
-h, --help show this help message and exit
verbosity:
verbosity = verbose - quiet, default INFO, mapping => CRITICAL=0, ERROR=1, WARNING=2, INFO=3, DEBUG=4, NOTSET=5
-v, --verbose increase verbosity (default: 2)
-q, --quiet decrease verbosity (default: 0)
discovery:
discover and provide a target interpreter
--discovery {builtin} interpreter discovery method (default: builtin)
-p py, --python py target interpreter for which to create a virtual (either absolute path or identifier string) (default: /usr/bin/python)
creator:
options for creator builtin
--creator {builtin,cpython2-posix}
create environment via (builtin = cpython2-posix) (default: builtin)
dest directory to create virtualenv at
--clear remove the destination directory if exist before starting (will overwrite files otherwise) (default: False)
--system-site-packages give the virtual environment access to the system site-packages dir (default: False)
--symlinks try to use symlinks rather than copies, when symlinks are not the default for the platform (default: True)
--copies, --always-copy try to use copies rather than symlinks, even when symlinks are the default for the platform (default: False)
seeder:
options for seeder app-data
--seeder {app-data,pip} seed packages install method (default: app-data)
--no-seed, --without-pip do not install seed packages (default: False)
--download pass to enable download of the latest pip/setuptools/wheel from PyPI (default: False)
--no-download, --never-download pass to disable download of the latest pip/setuptools/wheel from PyPI (default: True)
--extra-search-dir d [d ...] a path containing wheels the seeder may also use beside bundled (can be set 1+ times) (default: [])
--pip version pip version to install, bundle for bundled (default: latest)
--setuptools version setuptools version to install, bundle for bundled (default: latest)
--wheel version wheel version to install, bundle for bundled (default: latest)
--no-pip do not install pip (default: False)
--no-setuptools do not install setuptools (default: False)
--no-wheel do not install wheel (default: False)
--clear-app-data clear the app data folder of seed images (/root/.local/share/virtualenv/seed-v1) (default: False)
--symlink-app-data symlink the python packages from the app-data folder (requires seed pip>=19.3) (default: False)
activators:
options for activation scripts
--activators comma_separated_list
activators to generate - default is all supported (default: bash,cshell,fish,powershell,python)
--prompt prompt provides an alternative prompt prefix for this environment (default: None)
操作步驟
1. pip install virtualenv
2. virtualenv venv -p 解釋器路徑 --system-site-packages --copies
執(zhí)行命令生成venv文件夾删豺,集成了python的虛擬環(huán)境共虑。
具體參數(shù)說明見virtualenv命令選項,特別說明下要選擇--copies呀页,默認(rèn)的--symlinks會創(chuàng)建引用鏈接妈拌,移植會導(dǎo)致鏈接失效不可用
選擇--symlinks后的venv/lib/python3.6
(root) [root@host-192-169-100-115 python3.6]# pwd
/home/venv/lib/python3.6
(root) [root@host-192-169-100-115 python3.6]# ls -al
lrwxrwxrwx. 1 root root 58 Mar 5 00:57 abc.py -> /home/runtime/lib/python3.6/abc.py
lrwxrwxrwx. 1 root root 61 Mar 5 00:57 base64.py -> /home/runtime/lib/python3.6/base64.py
lrwxrwxrwx. 1 root root 61 Mar 5 00:57 bisect.py -> /home/runtime/lib/python3.6/bisect.py
3.拷貝原有解釋器的lib(lib64)、include等文件(site-packages含在lib內(nèi))復(fù)制到venv一級目錄下
virtualenv的說明中有一段:
Created python virtual environments are usually not self-contained. A complete python packaging is usually made up of thousand of files, so it’s not efficient to install the entire python again into a new folder. Instead virtual environments are mere shells, that contain little within itself, and borrow most from the system python (this is what you installed, when you installed python itself). This does mean that if you upgrade your system python your virtual environments might break, so watch out. The upside of this referring to the system python is that creating virtual environments can be fast.
提到拷貝完整文件對于虛擬環(huán)境并沒有意義蓬蝶,會借用系統(tǒng)解釋器的部分組件供炎,故新版本的virtualenv已經(jīng)不含lib庫渴逻,并且脫離lib庫的python無法運(yùn)行。
本需求需要一個完整的python音诫,故手動拷貝惨奕。(如果virtualenv有選項更好,可惜并沒有找到)
venv目錄:
[root@host-192-169-100-115 venv]# ll
total 12
drwxr-xr-x. 2 root root 4096 Mar 5 01:02 bin
drwxr-xr-x. 2 root root 4096 Mar 5 00:57 include
drwxr-xr-x. 3 root root 4096 Mar 5 00:57 lib
drwxr-xr-x. 3 root root 4096 Mar 5 00:57 pyenv.cfg
4.刪除venv中目錄下的pyenv.cfg文件1
若無該文件可以不關(guān)注竭钝。
5.修改bin目錄下執(zhí)行腳本的絕對路徑
當(dāng)前有兩類文件存在絕對路徑:
- bin目錄下其他可執(zhí)行python工具梨撞,開頭解釋器為固定解釋器
以pip舉例:
#!/usr/bin/python3.6
# -*- coding: utf-8 -*-
import re
import sys
from pip import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(main())
修改前:
#!/usr/bin/python3.6
修改后:
#!/usr/bin/env python3.6
- 用于啟動虛擬環(huán)境的bin/activate文件,其中venv的目錄為絕對路徑
修改前:
VIRTUAL_ENV="/home/venv"
修改后:
CUR_BIN_DIR=$(cd $(dirname ${BASH_SOURCE:-$0});pwd)
VIRTUAL_ENV="$(dirname $CUR_BIN_DIR)"
驗證步驟
- 切換任意目錄讀取activate中命令(source venv所在文件夾/venv/bin/activate)
[root@SDN-4416-1 venv]# source /home/runtime/venv/bin/activate
- 檢查python命令索引
(venv) [root@SDN-4416-1 venv]# which python
/home/runtime/venv/bin/python
- 進(jìn)入python控制器臺檢查標(biāo)準(zhǔn)庫和三方庫路徑非借用
(venv) [root@SDN-4416-1 venv]# python
Python 3.7.4 (default, Aug 13 2019, 20:35:49)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.__file__
'/home/runtime/venv/lib/python3.7/os.py'
>>> import requests
>>> requests.__file__
'/home/runtime/venv/lib/python3.7/site-packages/requests/__init__.py'
>>>
延伸閱讀
1.刪除venv中目錄下的pyenv.cfg文件香罐?
文件內(nèi)容:
[root@SDN-4416-1 venv]# cat pyvenv.cfg
home = /usr
implementation = CPython
version_info = 2.7.5.final.0
virtualenv = 20.0.4
include-system-site-packages = true
base-prefix = /usr
base-exec-prefix = /usr
base-executable = /usr/bin/python
為了解釋這個操作的原因卧波,先引出兩個問題:
- 虛擬環(huán)境下的python可執(zhí)行文件與系統(tǒng)默認(rèn)的有什么不同呢?
- Python又是如何找到虛擬環(huán)境下的第三方庫的呢庇茫?
事實(shí)上港粱,上面提到的python可執(zhí)行文件之間并沒有什么不同,但是它們所在的位置至關(guān)重要旦签。在Python啟動的時候查坪,它會獲取自身所在的路徑。然后這一路徑(bin的上一級)被設(shè)置到sys.prefix和sys.exec_prefix之中宁炫。
sys.prefix
A string giving the site-specific directory prefix where the platform independent Python files are installed; by default, this is the string '/usr/local'. This can be set at build time with the --prefix argument to the configure script. The main collection of Python library modules is installed in the directory prefix/lib/pythonX.Y while the platform independent header files (all except pyconfig.h) are stored in prefix/include/pythonX.Y, where X.Y is the version number of Python, for example 3.2.
Note If a virtual environment is in effect, this value will be changed in site.py to point to the virtual environment. The value for the Python installation will still be available, via base_prefix.
在搜索第三方的site-packages時偿曙,搜索目錄是sys.prefix所指向的路徑下的lib/pythonX.X/site-packages/,其中X.X是Python的版本羔巢。
假設(shè)python文件所在路徑為/Users/michaelherman/python-virtual-environments/env/bin望忆,因此sys.prefix會被設(shè)為/Users/michaelherman/python-virtual-environments/env,從而site-packages的路徑就變成了/Users/michaelherman/python-virtual-environments/env/lib/pythonX.X/site-packages竿秆。最后启摄,這一路徑被存儲在sys.path數(shù)組中,其中包含著所有包的引用來源幽钢。
再來歉备,關(guān)于pyenv.cfg有這樣的解釋:
PEP-405 Python Virtual Environments
When the Python binary is executed, it attempts to determine its prefix (which it stores in sys.prefix), which is then used to find the standard library and other key files, and by the site module to determine the location of the site-package directories. Currently the prefix is found (assuming PYTHONHOME is not set) by first walking up the filesystem tree looking for a marker file (os.py) that signifies the presence of the standard library, and if none is found, falling back to the build-time prefix hardcoded in the binary.
This PEP proposes to add a new first step to this search. If a pyvenv.cfg file is found either adjacent to the Python executable or one directory above it (if the executable is a symlink, it is not dereferenced), this file is scanned for lines of the form key = value. If a home key is found, this signifies that the Python binary belongs to a virtual environment, and the value of the home key is the directory containing the Python executable used to create this virtual environment.
In this case, prefix-finding continues as normal using the value of the home key as the effective Python binary location, which finds the prefix of the base installation. sys.base_prefix is set to this value, while sys.prefix is set to the directory containing pyvenv.cfg.
(If pyvenv.cfg is not found or does not contain the home key, prefix-finding continues normally, and sys.prefix will be equal to sys.base_prefix.)
Also, sys.base_exec_prefix is added, and handled similarly with regard to sys.exec_prefix. (sys.exec_prefix is the equivalent of sys.prefix, but for platform-specific files; by default it has the same value as sys.prefix.)
The site and sysconfig standard-library modules are modified such that the standard library and header files are found relative to sys.base_prefix / sys.base_exec_prefix, while site-package directories ("purelib" and "platlib", in sysconfig terms) are still found relative to sys.prefix / sys.exec_prefix.
Thus, a Python virtual environment in its simplest form would consist of nothing more than a copy or symlink of the Python binary accompanied by a pyvenv.cfg file and a site-packages directory.
同樣可以通過標(biāo)準(zhǔn)site.py找到對pyenv.cfg文件的引用:
#site.py
If a file named "pyvenv.cfg" exists one directory above sys.executable,
sys.prefix and sys.exec_prefix are set to that directory and
it is also checked for site-packages (sys.base_prefix and
sys.base_exec_prefix will always be the "real" prefixes of the Python
installation). If "pyvenv.cfg" (a bootstrap configuration file) contains
the key "include-system-site-packages" set to anything other than "false"
(case-insensitive), the system-level prefixes will still also be
searched for site-packages; otherwise they won't.
也就是說sys.prefix和sys.exec_prefix被設(shè)置好后,pyenv.cfg存在時虛擬環(huán)境時會繼續(xù)替換為文件中的前綴,在本需求中沒有必要搅吁,故刪去威创。