1. 引例
在我们开发python项目的时候,常常需要在本机开发完之后部署到一个全新的环境中去。在这个过程中,一个重要的问题就是如何快速的将开发环境中依赖的包也部署到新环境中,特别是当新环境无法联网的时候。有很多方法可以为迁移部署工作提供帮助。其实利用python的pip
模块就可以做到这一点。
2. pip
的使用
2.1 pip是什么
pip
实际上是一个python包的管理工具,安装完成之后,就可以在命令行调用pip
的相关命令来管理python包,例如,最常用的pip install <pkg>
、pip list
等。
2.2 pip的使用
如果你的项目是在一个单独的虚拟环境中开发的话,那么利用pip
可以非常容易进行项目环境的迁移部署。
首先,我们需要获取到安装在当前环境下的所有的第三方包,利用pip
非常容易做到:
pip freeze > requirements.txt
命令也非常好理解,就是将当前环境下的第三方包进行freeze,然后将结果写入到requirements.txt
文件中去。如果你注意观察的话,很多作者发布的第三方包里都会带有一个这样的文本文档,其生成方式就是这样的。
至此,如果你的新环境可以联网,那么你需要做的就是在新环境下安装好python,然后将requirements.txt
文件拷贝到新环境中,执行:
pip install -r requirements.txt
2.3 安装*.whl文件
很多情况下,新环境是没办法连接互联网的,这个时候,就需要将安装文件拷贝到新环境中进行离线安装了。如果安装的包不是很多,可以从pypi上下载源码,解压后运行命令安装。下面介绍安装*.whl文件的方式。
关于介绍*.whl文件的文章有很多,我们可以把它看成是一种特殊的压缩文件,而且利用pip
命令可以直接进行安装:pip install somepkg.whl
。
要想安装whl文件,首先要制作whl文件。启动项目的虚拟环境后,使用以下命令可以批量制作whl文件:
pip wheel --wheel-dir=/tmp/wheelhouse -r requirements.txt
根据requirements.txt
生成的whl文件全部放在/tmp/wheelhouse
目录下了,这时候只需要将目录打包上传到新环境中,然后运行:
pip install --no-index --find-links=/tmp/wheelhouse -r requirements.txt
这样,就完成了批量依赖包的安装。
注意:必须保证在制作和安装whl文件时python的版本与操作系统分别一致。
3. conda
的使用
conda
是一个开源的包与环境管理工具,在第2部分中的利用pip freeze
命令所做的事情,conda
也有对应的命令:
conda list --export
另外,conda
也包含了一系列的命令来迁移一个开发环境,可以参看它的帮助文档,理解了pip
的工作方法之后,应该不会有什么困难。
4. pipreqs
的使用
在第2部分,我们可以使用pip freeze > requirements.txt
来获取所有的依赖包。但这里存在几个问题问题:
问题来自官方文档,我对第一个问题表示怀疑。
- 上述命令只能将用
pip
安装的包进行freeze,用其他方式——例如conda
——安装的包可能会无法freeze; - 上述命令会freeze环境中的所有依赖包,除非为每一个项目单独建立了虚拟环境,否则得到的
requirements.txt
中会有许多非指定项目必需的依赖包。
这个时候,可以尝试使用pipreqs
命令。pipreqs
也是python的第三方包,其项目主页在这,可以使用pip install pipreqs
进行安装。
安装完成后,可以在命令行进行使用:
pipreqs <path>
<path>
指定目录,那么pipreqs
将会在指定的目录进行查找,并获取所有的第三方包及版本,并生成requirements.txt
文件。
可能的问题:
pipreqs
只能生成项目的直接依赖包,无法获取依赖包的依赖,即如果项目直接依赖numpy
,生成的requirements.txt
中并不包含numpy
的依赖包;- 如果在使用的过程中出现
UnicodeDecodeError
,可以尝试使用--encoding
命令,指定编码格式,如pipreqs --encoding=utf-8 ./
。
5. 其他
- 为每个项目创建一个单独的虚拟环境是一个非常好的习惯;
- 目前我还没有发现一种可以获取指定项目依赖的包及其依赖的开源工具,如果读者有好的资源,欢迎分享;
- 学会用
docker
真得可以事半功倍。
2021.11.3更新: 有时候我们从离线文件安装的第三方依赖后再使用上述命令生成requirements时,包名后跟的不是版本号,而是类似于如下内容:
pandas @ file:///opt/concourse/worker/volumes/live/38d1301c-8fa9-4d2f-662e-34dddf33b183/volume/pandas_1592841668171/work
一种变通的方法是,采用如下命令:
pip list --format=freeze > requirements.txt
关于此更多的描述,可以参考这里。