[toc]
Python统一构建配置PyProject.toml文件
什么是 pyproject.toml?
pyproject.toml 是 Python 项目的统一配置文件,一般放在项目的根目录下。
一句话概括它的作用:把项目相关的所有配置集中到一个文件里管理,包括项目基本信息、依赖哪些第三方包、项目如何构建打包、以及各种开发工具的配置。
为什么需要它
在 pyproject.toml 出现之前,Python 项目的配置散落在各种文件中,非常混乱:
- setup.py:项目的打包、安装配置(用 Python 语法写的)
- setup.cfg:setup.py 的配置版补充
- requirements.txt:依赖包清单
- pytest.ini、.flake8 等:各种工具各自的配置文件
每个工具都有自己的配置文件,格式还不统一(有的是 Python 语法,有的是 ini)。项目一大,根目录就堆满了各种配置文件。
而且 setup.py 本身是一段可执行的 Python 代码,安装项目时会被执行,既有安全风险,各家写法也五花八门,同一个功能可能有好几种写法。
于是在 2016 年(PEP 518),Python 社区决定采用 TOML 格式的 pyproject.toml 作为统一入口,之后(PEP 621)又规定了项目元数据(名称、版本、依赖等)的标准写法。
现在的 Python 项目基本都以 pyproject.toml 为核心。新建一个项目,通常只需要这一个配置文件就够了。
先认识一下 TOML 格式
TOML 是一种配置文件格式,特点是简单直白,可以理解为增强版的 ini。
# 这是注释
name = "myblog" # 字符串
count = 3 # 数字
is_ok = true # 布尔值
[project] # 用 [小节名] 表示分区
key = "value" # 小节下面的键值对
items = ["a", "b", "c"] # 数组用中括号TOML 文件的后缀就是 .toml,pyproject.toml 的意思就是"项目(project)的 TOML 配置"。
一个最小的例子
一个最简单的 pyproject.toml 长这样:
[build-system] # 用什么工具打包项目
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project] # 项目的基本信息
name = "myblog" # 项目名
version = "0.1.0" # 版本号
requires-python = ">=3.10" # 要求的 Python 版本
dependencies = [ # 依赖哪些第三方包
"requests>=2.31",
"loguru>=0.7",
]上面的内容分两大块:
[build-system]:声明打包这个项目需要什么构建工具。平时基本不用改,照抄即可。[project]:项目的基本信息,是平时最常打交道的部分。
[project] 常用字段说明
[project]
name = "myblog" # 项目名
version = "0.1.0" # 版本号
description = "我的博客系统" # 一句话描述
readme = "README.md" # 说明文档
authors = [
{ name = "shuyx", email = "xx@qq.com" },
]
requires-python = ">=3.10" # 支持的 Python 版本
dependencies = [ # 运行时必装的包
"requests>=2.31",
]
[project.optional-dependencies]
dev = [ # 只有开发时才需要的包
"pytest>=8.0",
"ruff>=0.4",
]依赖的版本约束怎么写
dependencies 里每个包后面都可以带版本约束,常用写法如下:
dependencies = [
"requests", # 不写版本:任何版本都行(不推荐,新版本可能不兼容旧代码)
"requests>=2.31", # 大于等于 2.31
"requests==2.31.0", # 精确锁定 2.31.0
"requests>=2.0,<3.0", # 2.0 及以上,3.0 以下
"requests~=2.31", # 约等于:允许 2.x 内的更新,不允许升到 3.0
]日常开发一般给个下限就够用了,比如 requests>=2.31,剩下的交给 pip 自动选兼容的版本。
另外还支持条件依赖,只有满足条件时才安装,比如只在 Windows 上安装的包:
dependencies = [
"pywin32>=306; sys_platform == 'win32'",
]分号后面是条件表达式,常见的判断依据有 sys_platform(操作系统)、python_version(Python 版本)等。
工具配置也放这里
pyproject.toml 的另一个好处:可以把各种开发工具的配置也写进来,不用再单独建配置文件。
比如同时配置 ruff(代码检查)和 pytest(测试):
[tool.ruff]
line-length = 100
[tool.pytest.ini_options]
testpaths = ["tests"]格式就是 [tool.工具名]。很多主流工具(ruff、pytest、black、mypy 等)都支持从 pyproject.toml 读取配置。
怎么使用它
安装项目(同时自动装好依赖)
在项目根目录下执行:
pip install .pip 会读取 pyproject.toml,把 dependencies 里的包全部装好。
开发模式安装
pip install -e .加 -e(editable,可编辑)后,修改项目代码会立即生效,不需要重新安装,开发时常用。
安装可选依赖
pip install -e .[dev] # 顺便装上 optional-dependencies 里的 dev 组现代工具基本都认它
uv、poetry、pdm 等新一代工具都以 pyproject.toml 为核心工作。比如用 uv:
uv init # 初始化项目,自动生成 pyproject.toml
uv add requests # 添加依赖,自动写入 pyproject.toml
uv sync # 根据锁文件安装所有依赖打包发布
如果想把项目打包成安装包(发给别人,或上传到 PyPI):
pip install build # 先安装构建工具
python -m build # 执行构建构建完成后项目下会多出一个 dist 文件夹,里面通常有两个文件:
- *.whl:wheel 安装包,pip 安装时用的就是这种,推荐分发这种
- *.tar.gz:源码包,对方拿到后需要本地构建一次
拿到 whl 文件的人,直接用 pip 安装即可,不需要再看你的源码:
pip install myblog-0.1.0-py3-none-any.whl和 requirements.txt 的区别
- pyproject.toml 描述"项目本身":元数据 + 依赖 + 构建方式 + 工具配置;requirements.txt 只是一个依赖清单
- pyproject.toml 里的依赖是范围约束(如
requests>=2.31);requirements.txt 通常锁定精确版本(如requests==2.31.0) - pyproject.toml 可以被 pip、uv、poetry 等各种工具使用;requirements.txt 主要给 pip 用
简单理解:
- pyproject.toml 声明"这个项目需要哪些包"(抽象需求)
- requirements.txt 记录"这个环境装了哪些版本的包"(精确清单),常用于服务器部署时保证环境一致
新项目直接用 pyproject.toml 即可,requirements.txt 一般是老项目或者部署需要才用。
常见问题
pyproject.toml 放在哪里?
项目根目录下,和 README.md 同级。pip、uv 等工具执行命令时默认只在当前目录找它。
有了 pyproject.toml,还需要虚拟环境吗?
需要。pyproject.toml 只负责声明依赖,依赖最终还是装在 Python 环境里的。配合虚拟环境使用,每个项目各用一套环境,互不干扰。虚拟环境的详细内容可以看 Python虚拟环境笔记。
dependencies 和 requirements.txt 可以二选一吗?
可以。个人项目或用 uv、poetry 管理的项目,只写 pyproject.toml 就够了;requirements.txt 通常用于服务器部署时锁定精确版本,保证线上环境和开发环境一致。
小结
- pyproject.toml 是 Python 项目的统一配置文件,放在项目根目录
- 它把散落各处的 setup.py、requirements.txt、工具配置等集中到一个文件
- 最核心的是
[project]小节,写明项目名、版本、依赖 pip install .安装项目,pip install -e .开发模式安装- 想打包分发项目时,用
python -m build生成 whl 安装包 - 新建 Python 项目,基本只需要 pyproject.toml 这一个配置文件
