相比 Pipenv,Poetry 是一个更好的选择

4,035 阅读5分钟

前情提要

Pipenv 描绘了一个美梦,让我们以为 Python 也有了其他语言那样完善的包管理器,不过这一切却在后来者 Poetry 这里得到了更好的实现。

这几年 Pipenv 收获了很多用户,但是也暴露了很多问题。虽然 Lock 太慢、Windows 支持不好和 bug 太多的问题都已经改进了很多,但对我来说,仍然不能接受随时更新锁定依赖的设定,在上一篇文章《不要用 Pipenv》里也吐槽了很多相关的问题。

在这篇文章里,我会介绍一个看起来和事实上都更靠谱的 Python 虚拟环境和依赖管理工具 Poetry,作者是 Sébastien Eustace。这是一个新的坑吗?我想并不是,尽管这是一个更年轻的工具,1.0 还没有发布,也存在各种各样的 bug,但至少基本使用流程没有问题,用法设计也符合直觉。

Poetry 是什么

Poetry 和 Pipenv 类似,是一个 Python 虚拟环境和依赖管理工具,另外它还提供了包管理功能,比如打包和发布。你可以把它看做是 Pipenv 和 Flit 这些工具的超集。它可以让你用 Poetry 来同时管理 Python 库和 Python 程序。

安装 Poetry

官方推荐的安装命令是使用自带的 get-poetry.py 脚本,使用 curl:

$ curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

或者直接下载这个安装脚本 get-poetry.py,然后在本地执行。

因为这个命令在安装时会从 GitHub 下载一个 7M 的压缩包,如果不用代理某些地区可能会很慢。实际测试使用代理安装耗时约 30 秒,不用代理等了 5 分钟,然后连接被重置。

如果没有用代理,可以用 pip 安装(不过 Poetry 官方文档不建议这么做,因为有可能会造成依赖冲突,可以考虑用 pipxpipsi):

$ pip install --user poetry

安装后可以使用下面的命令确认安装成功:

$ poetry --version
Poetry 0.12.17

如果报错,可以试试重新创建一个命令行会话。

附注 在 Mac 上安装报错 ~/.bash_profile 权限错误,临时没管,也能正常运行。后续可以考虑手动把 ~/.poetry/bin 加进去。

Poetry 的基本用法

Poetry 的用法很简单,大部分命令和 Pipenv 接近。我们需要先了解一些基本概念和 Tips:

  • 使用 PEP 518 引入的新标准 pyproject.toml 文件管理依赖列表和项目的各种 meta 信息,用来替代 Pipfile、requirements.txt、setup.py、setup.cfg、MANIFEST.in 等等各种配置文件。
  • 依赖分为两种,普通依赖(生产环境)和开发依赖。
  • 安装某个包,会在 pyproject.toml 文件中默认使用 upper bound(中文翻译?)版本限定,比如 Flask^1.1。这被叫做 Caret requirements(中文翻译?),比如某个依赖的版本限定是 ^2.9.0,当你执行 poetry update 的时候,它或许会更新到 2.14.0,但不会更新到 3.0.0;假如固定的版本是 ^0.1.11,它可能会更新到 0.1.19,但不会更新到 0.2.0。总之,在更新依赖的时候不会修改最左边非零的数字号版本(对于 SemVer 版本号而言),这样的默认设定可以确保你在更新依赖的时候不会更新到具有不兼容变动的版本。另外也支持更多依赖版本限定符号
  • 不会像 Pipenv 那样随时更新你的锁定依赖版本,锁定依赖存储在 poetry.lock 文件里(这个文件会自动生成)。所以,记得把你的 poetry.lock 文件纳入版本控制。
  • 执行 poetry 或 poetry list 命令查看所有可用的命令。

如果你想了解更多进阶的内容,比如设置命令行补全、打包和发布等等,请阅读 Poetry 文档

准备工作

如果你是在一个已有的项目里使用 Poetry,你只需要执行 poetry init 命令来创建一个 pyproject.toml 文件:

$ poetry init

根据它的提示输入你的项目信息,不确定的内容就按下 Enter 使用默认值,后续也可以手动更新。指定依赖的环节可以跳过,手动安装会更高效一点。

如果你想创建一个新的 Python 项目,使用 poetry new <文件夹名称> 命令可以创建一个项目模板:

$ poetry new foo

这会创建一个这样的项目结构:

foo
├── pyproject.toml
├── README.rst
├── foo
│   └── __init__.py
└── tests
    ├── __init__.py
    └── test_foo.py

如果你想使用 src 文件夹,可以添加 --src 选项,这会把程序包嵌套在 src 文件夹里。

创建虚拟环境

使用 poetry install 命令创建虚拟环境(确保当前目录有 pyproject.toml 文件):

$ poetry install

这个命令会读取 pyproject.toml 中的所有依赖(包括开发依赖)并安装,如果不想安装开发依赖,可以附加 --no-dev 选项。如果项目根目录有 poetry.lock 文件,会安装这个文件中列出的锁定版本的依赖。如果执行 add/remove 命令的时候没有检测到虚拟环境,也会为当前目录自动创建虚拟环境。

激活虚拟环境

执行 poetry 开头的命令并不需要激活虚拟环境,因为它会自动检测到当前虚拟环境。如果你想快速在当前目录对应的虚拟环境中执行命令,可以使用 poetry run <你的命令> 命令,比如:

$ poetry run python app.py

如果你想显式的激活虚拟环境,使用 poetry shell 命令:

$ poetry shell

安装包

使用 poetry add 命令来安装一个包:

$ poetry add flask

添加 --dev 参数可以指定为开发依赖:

$ poetry add pytest --dev

追踪 & 更新包

使用 poetry show 命令可以查看所有安装的依赖(可以传递包名称作为参数查看具体某个包的信息):

$ poetry show

添加 --tree 选项可以查看依赖关系:

$ poetry show --tree

添加 --outdated 可以查看可以更新的依赖:

$ poetry show --outdated

执行 poetry update 命令可以更新所有锁定版本的依赖:

$ poetry update

如果你想更新某个指定的依赖,传递包名作为参数:

$ poetry update foo

卸载包

使用 poetry remove <包名称> 卸载一个包:

$ poetry remove foo

常用配置

Poetry 的配置存储在单独的文件中,比 Pipenv 设置环境变量的方式要方便一点。配置通过 poetry config 命令设置,比如下面的命令可以写入 PyPI 的账号密码信息:

$ poetry config http-basic.pypi username password

下面的命令设置在项目内创建虚拟环境文件夹:

$ poetry config settings.virtualenvs.in-project true

另一个常用的配置是设置 PyPI 镜像源,以使用豆瓣提供的 PyPI 镜像源为例,你需要在 pyproject.toml 文件里加入这部分内容:

[[tool.poetry.source]]
name = "douban"
url = "https://pypi.doubanio.com/simple/"

不过经过测试 Poetry 会使用 pip.ini 设置的 PyPI 镜像,而且豆瓣的源好像很久没更新了(创建虚拟环境安装的默认依赖里 importlib-metadata==0.20 找不到),这篇文章列出了一些其他国内的 PyPI 源。

总结

总的来说,我愿意深入尝试和使用 Poetry。当然,经过使用 Pipenv 的痛苦经历,我对推荐工具这种事情变得更保守了。所以我不推荐 Python 初学者使用,不推荐直接在生产环境使用,不推荐没法正常访问国际互联网的人使用。

列一些我了解到的优缺点:

优点

  • 使用标准的 pyproject.toml 标准,不用写多个配置文件
  • 同时支持管理 Python 程序和 Python 库
  • 更符合直觉的默认设计,比如不会随便更新锁定版本的依赖
  • 干净简洁的命令行输出,没有星星和蛋糕
  • 安装包的时候,使用 upper bound 版本限定,而不是 Pipenv 默认的通配符
  • 卸载包的时候,直接卸载孤立的子依赖,不需要像 Pipenv 那样需要再执行 pipenv clean

缺点

  • 「poetry」这个单词有一点难打……
  • 引入新的 pyproject.toml 标准,旧项目需要一点迁移成本和学习成本
  • 会有一些潜在的 bug
  • 解析依赖的过程偶尔会久一点
  • 对虚拟环境的管理控制有些弱,没有 Pipenv 那样的删除虚拟环境和清空依赖的操作
  • 缺少一个稳定的维护团队,有大量 issue 和 PR 等待处理,但情况在逐渐好转

当然,你还是可以选择继续使用 virtualenv 和 pip 这些基础工具,直到有一个完美的解决方案出现。或者,也可以选择试试新东西,然后尝试改进它,让完美的解决方案早一点出现。

(2)


原标题是「相比 Pipenv,Poetry 是一个更好的选择吗?」