DesseraLab

Technology exploration and development

0%

Poetry - 现代的 Python 依赖管理工具

一直以来,我们管理 Python 项目的依赖都是通过手动创建虚拟环境,然后在虚拟环境中安装依赖。这种方式简单且有效,但如果读者尝试过 cargo、npm、yarn 等现代化的依赖管理工具,就会发现 Python 的依赖管理方式有些落后。

何出此言?我们来对比一下 cargo 和 conda 的依赖管理方式:

cargo针对每个项目都会创建一个 Cargo.toml 文件,用于记录项目的依赖信息。这样,我们只需要在 Cargo.toml 中添加依赖,然后执行 cargo build 即可安装依赖。这个过程是声明式的,我们随时可以看到项目的依赖信息,而这份信息也严格地与项目真正的依赖保持一致。

而对于 conda,即便有 environment.yml 文件与 requirements.txt 文件,我们也无法保证这份文件中的依赖与项目真正的依赖保持一致。往往我们改变了项目的依赖后,忘记更新这份文件,导致项目无法正常运行。

从以上的对比我们可以看出, conda 式的项目管理实际上是命令式的,这种以交互的方式构建项目环境的方式天生具有可变性,而 cargo 式的项目管理则是声明式的,这种方式实际上代表了不可变性。而后者是构建可复现系统的基础。

由此,我们引出了一个问题,如何让 Python 的依赖管理更像 cargo 呢?今天,我们介绍一个现代的 Python 依赖管理工具:Poetry。

Poetry

Poetry 是一个 Python 项目的依赖管理工具,它的目标是让 Python 项目的依赖管理更加现代化。Poetry 通过一个 pyproject.toml 文件来管理项目的依赖,这个文件类似于 cargo 的 Cargo.toml 文件。

要安装 Poetry,官方推荐使用 pipx

1
pipx install poetry

如果你正在使用 Arch Linux,你可以直接通过 pacman 安装 Poetry:

1
sudo pacman -S python-poetry

如果你想同时使用多个版本的 Poetry,你可以通过 asdf 来管理 Poetry 的版本:

1
2
3
asdf plugin add poetry
asdf install poetry latest # 安装最新版本的 Poetry
asdf global poetry latest # 设置全局的 Poetry 版本

安装完成后,我们可以通过 poetry --version 来查看 Poetry 的版本:

1
poetry --version

然后,我们使用 Poetry 来创建一个新的 Python 项目:

1
poetry new poetry-demo

这个命令会在当前目录下创建一个名为 poetry-demo 的 Python 项目。我们可以进入这个项目,然后查看整个项目结构:

1
2
3
4
5
6
7
.
├── poetry_demo
│   └── __init__.py
├── pyproject.toml
├── README.md
└── tests
└── __init__.py

pyproject.toml

我们先来熟悉一下 pyproject.toml 文件,以下是一个新建项目的 pyproject.toml 文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["dessera <1533653159@qq.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

基本配置没有什么好说的,这里只强调一些重要的配置项,更多的配置项可以参考 官方文档

  • tool.poetry.package-mode:指定项目的性质,true 代表项目是一个库,false 代表项目是一个应用程序。
  • tool.poetry.dependencies:项目的依赖,这里我们可以指定项目的依赖,例如 requests = "^2.31.0"
  • build-system:构建系统的配置,可以指定构建系统。

还有一些进阶配置,比如依赖分组、依赖源管理、extra 等,但这些不适合在这篇文章中展开讨论。

添加依赖

我们可以通过 poetry add 命令来添加依赖,例如我们添加一个 requests 依赖:

1
poetry add requests

也可以直接在 pyproject.toml 文件中手动添加依赖:

1
2
3
[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31.0"

二者的区别是,poetry add 会自动同步虚拟环境中的依赖,而手动添加依赖则需要执行 poetry install 来同步虚拟环境中的依赖。

当添加好依赖后,我们可以执行 poetry run python 来进入虚拟环境,然后引入依赖来测试:

1
poetry run python
1
2
3
>>> import requests
>>> requests.__version__
'2.31.0'

构建项目

只有库项目才能使用 poetry build 命令来构建项目,这个命令会在项目根目录下生成一个 dist 目录,里面包含了项目的构建产物。

1
2
3
4
5
poetry build

# 查看构建产物
ls dist
poetry_demo-0.1.0-py3-none-any.whl poetry_demo-0.1.0.tar.gz

发布项目

如果我们想发布项目到 PyPI,我们可以使用 poetry publish 命令:

1
poetry publish

这个命令会将项目发布到 PyPI,当然,你需要先在 PyPI 上注册一个账号,鉴于现在的 PyPI 状态,这个步骤暂时无法完成。

作为应用程序

如果我们的项目是一个应用程序,我们可以使用 poetry run 命令来运行项目:

1
poetry run python -m poetry_demo

这需要我们在包中拥有一个 __main__.py 文件,这个文件会在我们执行 poetry run python -m poetry_demo 时被执行。

或者,你可以手动执行项目的入口文件:

1
poetry run python path/to/entry.py

该入口文件可以是任意 Python 文件。

环境兼容

Poetry 可以使用 requirements.txt 文件来兼容 pip,这样我们可以在 Poetry 与 pip 之间无缝切换。

1
poetry export -f requirements.txt > requirements.txt

这个命令会将项目的依赖导出到 requirements.txt 文件中,然后我们可以使用 pip 来安装这些依赖:

1
pip install -r requirements.txt

总结

Poetry 实际上更像是一个现代化的 Python 库管理工具,但个人认为,使用 Poetry 的意义在于让我们的项目更加现代化,更加可维护。Poetry 的出现,让我们的 Python 项目管理更加像 cargo,这是一个好的方向。

Poetry 还有诸多进阶功能,将在后续的文章中展开讨论。