## 什么是pyproject.toml
pyproject.toml 是一种用于 Python 包管理的配置文件。它是由 PEP 518 引入的,旨在取代传统的 setup.py 文件和 requirements.txt 文件。pyproject.toml 提供了一种简单、直观且可扩展的方式来定义项目依赖项、构建系统和其他相关元数据。
使用 pyproject.toml 进行 Python 包管理具有许多优势。首先,它提供了更清晰、更结构化的包描述信息。通过使用 pyproject.toml,开发者可以明确指定项目所需的依赖项及其版本范围,以确保环境中安装正确版本的软件包。
此外,pyproject.toml 还支持多个构建工具和插件,并允许开发者根据自己项目特定需求进行灵活配置。例如,在 pyproject.toml 中可以定义要执行的脚本命令、测试套件以及其他与构建过程相关的操作。
## 为什么使用 pyproject.toml 进行 Python 包管理?
首先,pyproject.toml 是根据 TOML(Tom’s Obvious, Minimal Language)语法规范设计而成。相较于其他常见格式如 JSON 或 YAML,TOML 更加人类可读,并且支持注释,使得配置文件更加清晰易懂。
其次,pyproject.toml 提供了对项目构建过程中所需工具和依赖项进行统一定义和管理的能力。通过指定项目所需依赖包及其版本号等信息,可以确保团队成员之间共享相同环境并避免因不同版本引起的问题。
此外,pyproject.toml 还支持自定义脚本命令以及设置多个构建系统插件等功能。这意味着你可以轻松地添加额外操作或集成其他工具进入你的项目中。
## 如何使用 pyproject.toml 进行 Python 包管理?
以下是一些常见操作步骤:
1. 创建或编辑pyproject.toml文件:在你的项目根目录下创建一个名为pyprojecct.tml 的文本文件。
2. 定义项目依赖:在pyproject.toml中使用合适的语法定义项目所需的依赖库及其版本信息。例如:
```
[build-system]
requires = ["numpy", "pandas"]
```
上述示例指定了项目需要安装的两个依赖库,分别是numpy和pandas。
3. 运行包管理命令:通过运行相应的包管理命令来处理依赖关系并进行安装。常见的包管理工具有pip、poetry等。
4. 构建和发布项目:根据定义在pyproject.toml中的构建系统配置,执行相关操作以构建和发布你的Python项目。
## pyproject.toml 的常见应用场景
1. 定义项目元数据
在 pyproject.toml 文件中,您可以定义与您的项目相关的元数据信息,如项目名称、版本号、作者等。这些元数据对于包发布和其他工具(如打包工具)非常有用。例如:
```
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
```
2. 指定依赖项
通过 pyproject.toml 文件,您可以指定您的 Python 项目所需的依赖项及其版本范围。这使得其他开发者能够轻松地安装和运行你们共享代码库。例如:
```
[tool.poetry.dependencies]
python = "^3.8"
requests = "^2.25"
```
3. 构建和打包工具配置
使用 pyproject.toml 可以为不同类型或阶段(如构建、测试、文档生成)提供特定配置,并且支持多个构建系统。
例如,在以下示例中我们使用 Poetry 配置了一个自定义脚本:
```
[tool.poetry.scripts]
my-script = "my_module:main"
```
4. 描述项目的结构和文件布局
pyproject.toml 文件可以用于描述 Python 项目的目录结构、源代码位置以及其他相关文件。这对于维护大型或复杂的项目非常有帮助。
例如,在以下示例中,我们指定了源代码目录为 src/:
```
[build-system]
source = "src/"
```
5. 集成持续集成(CI)工具
许多持续集成工具支持读取 pyproject.toml 文件来配置自动化测试和部署流程。您可以在其中定义所需的脚本、依赖项等。
例如,Travis CI 的 .travis.yml 配置文件可以使用 Poetry 和 pyproject.toml 来安装和运行您的 Python 项目。
## Poetry
Poetry 是 Python 中的依赖管理和打包工具。它允许您声明您的项目所依赖的库,并且它将为您管理(安装/更新)它们。Poetry 提供了一个锁定文件来确保可重复安装,并可以构建您的项目以进行分发。
## Poetry VS 传统包管理
1. 自动生成、管理能够完整描述项目依赖的toml文件
* 传统包管理
- 以往经常会遇到一类情况,拿到一个项目,根据requirements.txt安装依赖的时候,由于requirements.txt缺乏对python版本的描述,导致接手的人不知道python版本
- 之前有个项目是基于python3.8开发的,我选了当时还算比较新的python3.6,安装requirements.txt,然后运行报错,排查之后才发现是python版本不一致导致的问题
* Poetry
- 能解决以上问题,它会自动生成并管理pyproject.toml文件,生成代码库名称、版本、lisence等meta信息,还有python版本、依赖包的版本等信息
2. 为生产和开发环境提供单独的依赖
* 传统包管理
- 一个场景是,开发、测试环境需要的包,生产环境不一定需要,比如pytest、flake8、black、pycodestyle等等,传统的做法是,建立多个requirements.txt,比如:requirements-dev.txt、requirements-test.txt、requirements-pro.txt,这样文件繁多,不利于统一管理
* Poetry
- 可以把所有环境的依赖比较好地区分,都放入pyproject.toml文件中统一管理
3. 更新包版本,自动在pyproject.toml中同步更新
* 传统包管理
- 传统工具pip或者conda在更新或者添加包之后,需要手动或者pip freeze一下依赖,频繁更新容易忘记
* Poetry
- 将这个过程合二为一,只需要poetry add XXX,依赖信息会自动更新到pyproject.toml
4. 依赖关系的解决
* 传统包管理
- 使用pip管理依赖比较大的一个痛点场景是,安装pandas==2.0.2,需要依赖numpy>=1.20.3,然后,你又安装了numpy==1.20.2,尽管发生了依赖冲突,pip依然会将numpy版本更新到1.20.2(与pandas==2.0.2对于numpy版本的要求冲突),这样,默默地引入依赖冲突的包,会在后续的程序运行中导致潜在的冲突问题,而且不太好排查解决。
* Poetry
- 会立即报错,并提示合理的版本区间
5. 彻底删除已有依赖包以及子依赖包
* 传统包管理
- 使用pip管理依赖另一个比较大的痛点场景是,比如安装pandas==2.0.2的时候,顺带安装了包括numpy>=1.20.3在内的数十个子依赖,当你想要卸载pandas的时候,pip uninstall pandas,只会卸载pandas本身,而不会去卸载其下的数十个子依赖包,导致的问题就是,出现大量不会使用到的【孤儿】子依赖包,久而久之,包占用的空间【虚胖】,浪费存储空间,包管理也一团糟。
* Poetry
- 可以很好地管理依赖以及子依赖,删除依赖包的同时,一并删除子依赖,维护一个干净高效的项目环境。
**总结**
Poetry提供了比pip和conda更多的优势
1. 一致的软件包安装:Poetry提供了一个一致的格式来安装任何软件包,确保整个项目有一个标准化的方法。
2. 高效的依赖性管理:Poetry只为指定的软件包安装必要的依赖性,减少你环境中不相干的软件包的数量。
3. 简化的软件包移除:Poetry简化了软件包及其相关依赖关系的移除,使其易于维护一个干净和高效的项目环境。
4. 依赖性解决:Poetry的确定性解析器有效地解决了依赖关系,及时识别并处理任何不一致或冲突。
## Poetry使用
### 创建项目
```
poetry new demo1
demo1
├── pyproject.toml
├── README.rst
├── demo1
│ └── __init__.py
└── tests
├── __init__.py
└── test_demo1.py
```
### 创建虚拟环境
```
cd demo1
poetry install
```
### 设置Pypi的源
在 pyproject.toml 文件末尾追加以下内容:
```
[[tool.poetry.source]]
name = "aliyun"
url = "schema://mirrors.aliyun.com/pypi/simple"
default = true
```
### 激活使用虚拟环境
```
# 不激活虚拟环境使用命令
poetry run python start.py
# 激活虚拟环境使用命令
poetry shell
# 安装包
poetry add flask
# 查看安装的所有包
poetry show
# 查看单个包
poetry show flask
# 卸载包
poetry remove flask
# 退出虚拟环境
exit
# 查看虚拟环境路径
poetry env info --path
# 删除虚拟环境
poetry env remove /full/path/to/python
```