python virtualenv迁移,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 镜像中。显然,这种一致性不仅可以提高开发效率,还可以提高后续的运维效率。

相关文章:

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于迁移 Linux 上的 Python 环境,你可以按照以下步骤进行操作: 1. 备份环境:首先,确保你的当前 Python 环境是稳定可用的,并且对其进行备份。你可以使用虚拟环境(如 virtualenv 或 conda)来隔离你的 Python 环境,以便更容易进行迁移。 2. 导出依赖:使用 pip 工具导出当前环境的依赖包列表到一个文本文件中。可以运行以下命令来完成这个操作: ```shell pip freeze > requirements.txt ``` 此命令将把当前环境的所有依赖包及其版本信息写入 requirements.txt 文件。 3. 迁移代码和配置:将你的代码和配置文件从当前环境迁移到目标环境。可以使用文件复制工具(如 scp)将文件从一个机器复制到另一个机器上,或者使用版本控制系统(如 Git)来管理代码。 4. 创建新环境:在目标机器上安装相同版本的 Python,并创建一个新的虚拟环境(如果你使用了虚拟环境)。可以使用以下命令创建一个新的虚拟环境: ```shell python3 -m venv myenv # 使用 venv 创建虚拟环境 ``` 5. 激活新环境:激活新创建的虚拟环境。可以使用以下命令激活虚拟环境: ```shell source myenv/bin/activate # Linux 上的激活命令 ``` 6. 安装依赖:在新环境中安装之前导出的依赖包。运行以下命令: ```shell pip install -r requirements.txt ``` 此命令将根据 requirements.txt 文件安装所有依赖包。 7. 测试和验证:在新环境中运行你的代码,并进行测试和验证,确保一切正常工作。 请注意,这些步骤是一个基本的指南,具体的迁移过程可能因你的项目和环境而有所不同。确保在迁移之前备份你的数据,并根据需要进行调整和适应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值