Python 工程管理及 virtualenv 的迁移
virtualenv 是管理 python 工程的利器,它可以很好的帮你维护项目中的依赖,使用 virtualenv,还能保持 global 库的干净、不会被不同项目中的第三方库所污染。
virtualenv 的默认功能简单好用,可一旦涉及到多人协作,或部署到不同的环境中时,错误的使用 virtualenv 会给你带来一些麻烦,从而你需要花很多时间在解决这些问题上。本文的目的就是总结过去使用 virtualenv 的经验,希望能帮你找到一种正确的打开方式。
首先,创建一个空的 virtualenv 时,你的目录中会包含以下文件和目录
drwxr-xr-x 7 fengyajie staff 224B Mar 21 22:49 .
drwxr-xr-x 8 fengyajie staff 256B Mar 21 20:28 ..
lrwxr-xr-x 1 fengyajie staff 83B Mar 21 22:49 .Python -> /usr/local/Cellar/...
drwxr-xr-x 16 fengyajie staff 512B Mar 21 22:49 bin
drwxr-xr-x 3 fengyajie staff 96B Mar 21 22:49 include
drwxr-xr-x 3 fengyajie staff 96B Mar 21 22:49 lib
-rw-r--r-- 1 fengyajie staff 61B Mar 21 22:49 pip-selfcheck.json
接着当你执行 source bin/activate
后,你安装的依赖都会在 lib
目录下,这一点很诱人,会让你觉得一切尽在掌握,因为该应用程序所需要的一切库文件全在这个 app 的根目录下,所以当这个应用需要部署时,为了避免产生 ImportError: No module named xxx
错误,你会很容易的想到将本地这个 app 目录打包,然后放到远程服务器或容器中去执行。
当你这么做时,你会发现虽然在远程是可以执行 source bin/activate
命令以进入 virtualenv ,但此时你引用的 python 可执行文件却并不是 ${app}/bin/pyhton
,而是 global 环境中的那个 /usr/bin/python
,所以 ${app}/lib
下的所有依赖包路径仍然是没有被包含进 sys.path
的。
这时,你才发现自己的假设是错误的,并开始怀疑自己使用 virtualenv 的方式存在问题,于是便 google 各种解决方案,但项目已处于部署阶段,时间紧迫,你很可能找不到最优的办法,只能退而求其次,寻求次优解,毕竟依赖包都在嘛,改下 sys.path
不就好了嘛?确实很容易想到这种方法,但又不想手动改,那就写个程序改吧,也不难:
# set_sys_path.py
def set_sys_path():
import sys
for path in sys.path:
if os.path.split(path)[1] == 'site-packages':
home = os.path.abspath(os.path.dirname(__file__))
pypath = os.path.join(home, 'lib/python2.7')
pypath_sitepackage = os.path.join(home, 'lib/python2.7/site-packages')
pth = os.path.join(path, 'pth.pth')
with open(pth, 'w') as f:
f.write("%s\n" % pypath)
f.write("%s\n" % pypath_sitepackage)
if __name__ == "__main__":
set_sys_path()
上面的程序很简单,它将 ${app}/lib/python2.7
和 ${app}/python2.7/site-packages
两个依赖路径写到 pth.pth
文件中,并将该文件 mv
到 global 的 site-packages
目录下,这样当你启动 global 的 python 时,会自动将 pth.pth
里的路径添加到 sys.path
下,这样只需要在启动你的 app 之前,执行该脚本即可,如下:
$ python set_sys_path.py
$ python main.py
问题暂时解决了,这次你的 app 也顺利发布了;但还没结束,我们希望在测试机集群上把 app 的自动化测试做起来,在做自动化测试时,系统会随机给你分配一台机器资源,当测试完成后,资源会被回收。你心想,这仍然很简单嘛,本地测试已经覆盖得很全了,只要自动化系统利用 git 把代码拉下来,先执行 set_sys_path.py
设置 sys.path
,再执行 python test.py
(测试入口)就可以了。
可这时又出现问题了,自动化测试在执行 set_sys_path.py
时,报 Permission denied
错误,原因是测试机为了保持环境不被污染,不允许你将 pth.pth
复制到 global 的 site-packages
下。
遇到这个问题怎么办?其实也很容易解决:我们都知道 python 中有个环境变量 PYTHONPATH
可以用来设置 sys.path
,既然没有写文件的权限,那定义环境变量总该可以吧:
$ export PYTHONPATH=$PYTHONPATH:${app}/lib/python2.7:${app}/lib/python2.7/site-packages
$ python main.py
果然可行,你再一次「顺利」的完成了需求。
经历过多次折腾后,我们发现这种使用 virtualenv 和修改 sys.path
的方法不算很好,还容易出错。于是开始思考最初的那个问题,virtualenv 该怎么迁移?有没有更好的办法?答案肯定是有的,在此之前,我们先仔细观察 virtualenv 产生的文件,会发现其中有 28 个软连接,它们的源文件均在 global 库中,如下所示
$ find . -type l
./.Python
./bin/python
./bin/python2
./include/python2.7
./lib/python2.7/lib-dynload
./lib/python2.7/encodings
...
所以,当你把整个 virtualenv 打包,放到另一个环境中运行时,肯定是会失败的,因为软连接失效了,于是,再一次证实这种把整个 virtualenv 打包的方法,实际上是错误的,virtualenv 就只是一个 local 方案,而不是让你可以「处处运行」的工具。电动叉车
但 virtualenv 的隔离功能,可以让你只关注项目范围内的依赖包,所以我们可以利用 pip freeze
命令,将项目内的依赖保存到一个叫 requirements.txt
的文件中,这样在任何其他环境,我们只要根据 requirements.txt
文件来安装项目所需的依赖包,即可将本地的运行环境克隆出来,而且这种克隆出来的环境更纯粹,不会受到源环境或 global 库的影响,没有不确定性。下面我们用一个例子来具体说明下:
假设 Bob 和 Alice 同在一个团队,他们决定使用 python 来开发新项目,一开始,Bob 在 github 上创建了一个新 repo,并在本地初始化它:
# 从 github clone 项目
$ git clone https://github.com/your_group/your_repo.git
$ cd your_repo
# 创建并进入 virtualenv
$ virtualenv .
$ source bin/activate
# 修改 .gitignore,过滤掉 virtualenv 产出的文件
$ cat .gitignore
*.py[cod]
__pycache__/
.Python
bin/
include/
lib/
pip-selfcheck.json
# 在本地安装基本依赖,例如 Flask、gevent、gunicorn 等
$ pip install Flask gevent gunicorn -i https://pypi.mirrors.ustc.edu.cn/simple/
# 将本地依赖写入 requirements.txt
$ pip freeze > requirements.txt
# 将变更提交到 github
$ git add .
$ git commit -m "init project"
$ git push origin master
# 继续开发
# ...
Bob 完成了初始化,实际上他只提交了 .gitignore
和 requirements.txt
两个文件到 git 中,之后 Alice 也可以加入进来了:
# 从 github clone 项目
$ git clone https://github.com/your_group/your_repo.git
$ cd your_repo
# 创建并进入 virtualenv
$ virtualenv .
$ source bin/activate
# 根据 requirements.txt 文件下载项目所需的依赖
$ pip install Flask gevent gunicorn -i https://pypi.mirrors.ustc.edu.cn/simple/
# 继续开发
# ...
可以看到,通过这样的步骤,Bob 和 Alice 不仅有了一摸一样的开发环境,还能最小化 git 仓库的大小,且按照这样的思路,他们还可以把相同的环境克隆到测试机上,以及 Docker 镜像中。显然,这种一致性不仅可以提高开发效率,还可以提高后续的运维效率。
参考:
- Pipenv & 虚拟环境
Python 工程管理及 virtualenv 的迁移的更多相关文章
- 将python工程部署到新服务器(对virtualenv工具进行环境迁移)
将python工程部署到新服务器(对virtualenv工具进行环境迁移) # 从开发的电脑上导出 pip list 到 requirements.txt 文件pip freeze > requ ...
- python包管理-distutils,setuptools,pip,virtualenv等介绍
python包管理-distutils,setuptools,pip,virtualenv等介绍 对于每个编程语言来说打包和发布开发包往往非常重要,而作为一个编程者能够快速容易的获得并应用这些由第三方 ...
- python的pip和virtualenv使用心得
pip可以很方便的安装.卸载和管理Python的包.virtualenv则可以建立多个独立的虚拟环境,各个环境中拥有自己的python解释器和各自的package包,互不影响.pip和virtuale ...
- Python包管理工具小结
此文已由作者张耕源授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 作为一名接触Python有一段时间的初学者,越来越体会到Python的方便之处,它使人能更 多的关注业务本身 ...
- 使用BLADE构建c++工程管理
使用BLADE构建c++工程管理 字数764 阅读2753 评论2 喜欢4 一. c++工程依赖管理 之前在百度一直使用comake2构建c++项目,十分方便.免去了手写Makefile的痛苦,很多项 ...
- python 包管理工具
python 包管理工具 Python当前的包管理工具链是 easy_install/pip + distribute/setuptools + distutils,显得较为混乱. 而将来的工具链组合 ...
- Python包管理工具和多版本环境管理
1. Python包管理工具 在安装Python包的过程中,经常涉及到distutils.setuptools.distribute.setup.py.easy_install.easy_instal ...
- Python 包管理(PYPA)
Python包的管理可以通过Python 自带的管理 工具,例如:package-autoremove,package-list-packages, package-install 等,使用起来也非常 ...
- python三大神器之virtualenv
virtualenv virtualenv用来管理python项目环境,隔离出一个只属于这个项目的虚拟python环境(windows和Linux用法一样). 首先你需要安装virtualenv模块 ...
随机推荐
- 设计模式--Proxy
转自:http://blog.csdn.net/dan_xp/article/details/1820852 最近一直在看java的设计模式 ,感觉印象最深刻的就是"面向接口编程" ...
- python 机器学习中模型评估和调参
在做数据处理时,需要用到不同的手法,如特征标准化,主成分分析,等等会重复用到某些参数,sklearn中提供了管道,可以一次性的解决该问题 先展示先通常的做法 import pandas as pd f ...
- Nginx:413 Request Entity Too Large
现象:在 Post 文件的时候遇到413 错误 :Request Entity Too Large: 原因:Nginx 限制了上传文件的大小,需在Nginx中修改/增加允许的最大文件大小: 操作:编辑 ...
- Linux读写执行权限对目录和文件的影响
提示:这里的用户指的是普通用户 读写执行权限对root无效 对于目录来说 1)只拥有读权限 可以ls 查看目录内容,不能切换进目录中去 也不能创建目录或文件 [support@node1 opt]$ ...
- 在excel中将缺失数据全部用0补齐
先ctrl+H ,出现如下对话框 点击“定位”,选择“空值” 在表格中空的位置上编辑栏输入0,CTRL+ENTER,即可将缺失数据全部用0补齐.
- 转载 Net多线程编程—System.Threading.Tasks.Parallel
.Net多线程编程—System.Threading.Tasks.Parallel System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Paral ...
- P1044-栈-洛谷luogu
题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表. 栈有两种最重要的操作,即poppop(从栈顶弹出一个元素)和pushpush(将一个元素进栈). 栈的重要性 ...
- Android对接微信支付体验
在写正文之前我不得不吐槽一下:微信支付所提供的参考文档以及技术支持真心太烂了. 微信的坑: 1.在生成prepay_id向微信服务器传递参数时<body>不支持中文.需要对其进行转码,否则 ...
- android 工具大集合
http://www.androiddevtools.cn/ http://www.sourcetreeapp.com/
- Android 其他特效展示
Android开源项目发现----其他特殊效果篇(持续更新) 发表时间:2014-03-01 15:10:10 来源:本站整理 浏览(160) Android开源项目发现----其他特殊效 ...