pyproject.toml 可完全替代 setup.py,但须满足:使用现代构建后端(如 setuptools≥61.0 或 hatchling)且全部元数据与逻辑迁移至 pyproject.toml;若 setup.py 存在(含空文件),仍会优先执行导致迁移失效。

可以完全替代,但必须同时满足两个条件:项目使用现代构建后端(如 setuptools ≥61.0 或 hatchling),且所有元数据和构建逻辑都迁移到 pyproject.toml 中——setup.py 一旦存在,多数工具仍会优先执行它,导致迁移失效。
pyproject.toml 的必备结构:[build-system] 和 [project]
这是最小可行配置,缺一不可。旧版 setup.py 中的 name、version、install_requires 等字段,现在统一归入 [project] 表。
常见错误是只写 [project] 却漏掉 [build-system],结果 pip install . 报错 ModuleNotFoundError: No module named 'setuptools',因为 pip 不知道该用哪个构建器。
-
[build-system]必须声明requires(构建依赖)和build-backend(如"setuptools.build_meta") -
[project]中dependencies替代install_requires,requires-python = ">=3.8"替代python_requires - 动态版本号(如从
__version__.py读取)需额外配置:setuptools≥61.0 支持dynamic.version+[[project.dynamic]],否则得用hatchling或硬编码
setup.py 还在?那 pyproject.toml 可能被忽略
很多项目删了 setup.py 文件,却保留了一个空文件或仅含 pass 的脚本,这依然会触发传统构建流程,导致 pyproject.toml 中的 [project] 不生效。
验证方法:运行 pip show your-package-name,看输出的 Version 和 Requires 是否来自 pyproject.toml;若仍是旧值,大概率 setup.py 被读取了。
- 彻底删除
setup.py(包括setup.cfg) - 检查是否意外引入了
pyproject.toml多个表(如同时有[tool.setuptools]和[project]),部分字段会覆盖冲突 - 某些 CI 脚本或 Makefile 显式调用
python setup.py sdist,需同步改为python -m build
可选但实用的扩展:[project.optional-dependencies] 和 [tool.*]
[project.optional-dependencies] 是替代 extras_require 的标准方式,语法更直观;而 [tool.*] 段用于构建后端或开发工具专属配置,比如 [tool.black]、[tool.ruff],它们不影响包分发,但和 [project] 共存于同一文件,减少配置碎片。
注意 [tool.setuptools] 和 [project] 的职责边界:前者控制构建行为(如 packages.find、include-package-data),后者只管元数据和依赖。混用时优先级以构建后端文档为准,setuptools 默认以 [project] 为主,[tool.setuptools] 为辅。
-
optional-dependencies示例:dev = ["pytest", "ruff"]→ 安装时用pip install ".[dev]" -
[tool.setuptools.packages.find]中where = ["src"]对应旧版package_dir={"": "src"} - 若用
hatchling,[project]已支持scripts和gui-scripts,无需再配[project.entry-points."console_scripts"]
真正麻烦的不是迁移语法,而是那些藏在 setup.py 里的自定义逻辑:编译 C 扩展、生成协议缓冲区代码、动态写入版本……这些无法用静态 TOML 表达,必须转成构建后端支持的钩子(如 setuptools 的 cmdclass 或 hatch 的插件),或者干脆抽成预构建步骤。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











