项目地址: https://pypi.org/project/pip-tools/
pip-tools 是一个命令行工具集合,主要有两个命令: pip-compile
,pip-sync
,现在主要用的是 pip-compile
在写python项目的时候,我们通常会依赖到其他的包,比如写一个后端的服务,我们可能会依赖到flask/pymysql
这些基础的包,随着开发的进行,我们还可能会引入更多的依赖。
这些python依赖包构成了一个完整的服务,开发完成后,我们将这些服务部署到服务器上时,只需要安装好对应的依赖,便可以直接运行服务。
但是,如果我们不将生产环境的依赖固定下来的话,整个服务可能会因为某一次服务更新,其中某个的更新带来的不兼容导致整个服务崩溃。比如pyjwt,在1.7.1版本之前生成的jwt-token是一个bytes类型,我们将其转换成为字符串需要使用到decode()
方法。但是在更新到2.0之后,生成的jwt-token是一个字符串类型,如果我们对其再调用decode
方法的话,就会发生错误。
这就显现出了固定依赖的重要性了。
通常,固定依赖,我们可以在开发环境使用 pip freeze
命令,直接将开发环境的所有版本固定下来到一个 requirements.txt 文件里面,这是懒人做法,当然也很有效。但是文件里面会带有一些系统的依赖版本,比如urllib 之类的,这些我们是不需要再次安装的,所以,如果这些依赖出现在 requirements.txt 文件里面,就会显得不那么干净。
这时,我们可以使用 pip-tools里面的 pip-compile
工具,对依赖进行编译,生成一份漂亮的依赖文件。
直接生成最新依赖
- 首先,我们将项目中直接依赖的包写到
requirements.in
文件里面
requirements.in
pymysql
flask
- 使用
pip-compile
自动使用最新依赖版本生成依赖文件
命令: pip-compile
, 输出requirements.txt文件:
requirements.txt
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
#
# pip-compile
#
--index-url https://pypi.doubanio.com/simple
--trusted-host pypi.doubanio.com
click==8.1.3
# via flask
flask==2.1.2
# via -r requirements.in
importlib-metadata==4.11.4
# via flask
itsdangerous==2.1.2
# via flask
jinja2==3.1.2
# via flask
markupsafe==2.1.1
# via jinja2
pymysql==1.0.2
# via -r requirements.in
werkzeug==2.1.2
# via flask
zipp==3.8.0
# via importlib-metadata
这样,我们就得到了一份漂亮的依赖文件,我们还可以清晰的看到某一个依赖包是哪个包的依赖。
从本地已有依赖生成文件
有时候,我们的服务已经部署上云了,这时候,我们想要使用已有的(本地已安装的)依赖版本来生成依赖文件,而不是从pypi上查找最新的,因为现有正在运行的相对稳定,而更新后不确定会引入哪些不兼容问题。
我们可以这样做:
- 还是先将我们的直接依赖写到
requirements.in
文件里面 - 到生产环境中,使用
pip freeze --exclude-editable > requirements.txt
命令,将当前环境的所有包版本写到requirements.txt 文件里面 - 使用命令
pip-compile --no-upgrade
,只用本地依赖生成一份漂亮的依赖文件。
重新生成的依赖文件:
requirements.txt
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
#
# pip-compile
#
--index-url https://pypi.doubanio.com/simple
--trusted-host pypi.doubanio.com
click==7.1.2
# via flask
flask==1.1.4
# via -r requirements.in
itsdangerous==1.1.0
# via flask
jinja2==2.11.3
# via flask
markupsafe==2.1.1
# via jinja2
pymysql==0.10.1
# via -r requirements.in
werkzeug==1.0.1
# via flask
加上参数 --no-upgrade
,pip-compile 就会优先使用requirements.txt里面,我们freeze的依赖版本,而不是到pypi中寻找最新的版本。
可以看到,重新生成的 requirements.txt 文件的各个版本都相对落后一些,依赖总数也少一点。