setup.py 已被 pep 517 弃用,pyproject.toml 是唯一合法构建入口;python 3.13 移除 distutils 导致 setup.py 报错;pip ≥23.0 忽略 setup.py,仅依赖 pyproject.toml 的 [build-system] 配置。

因为 setup.py 已不再是构建入口,而是被 PEP 517 明确弃用的遗留机制;pyproject.toml 是当前唯一受标准支持、可静态分析、能隔离构建依赖的合法起点。
为什么直接运行 python setup.py install 会报错?
这不是环境问题,而是 Python 3.12+ 已将 distutils 标记为 deprecated,3.13 彻底移除——所有依赖 distutils.core 或隐式调用它的代码(比如老版本 setup.py)都会触发 ModuleNotFoundError: No module named 'setuptools._distutils' 或 AttributeError: module 'setuptools' has no attribute 'setup'。
-
pip install .在 pip ≥ 23.0 中默认忽略setup.py,只读pyproject.toml的[build-system] - 如果项目只有
setup.py没有pyproject.toml,pip 会降级到 legacy 模式,并立刻打印DEPRECATION: Legacy setup.py install is deprecated - 哪怕你手动执行
python setup.py bdist_wheel,只要 setuptools ≥ 61.0,它内部也会尝试走 PEP 517 流程,失败后才 fallback —— 这就是你看到“卡住”或“半途崩溃”的原因
pyproject.toml 的 [build-system] 是什么?
它是整个现代打包流程的唯一入口契约,告诉构建前端(如 pip、build)该用哪个后端、需要哪些工具。没有它,就等于没声明“怎么建包”,一切都不合法。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- 必须包含
requires和build-backend两个字段,例如:[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta"
-
requires列的是构建时依赖(不是你的项目依赖),不能写成["setuptools"]这种模糊版本,否则在 CI 中可能拉到不兼容旧版 -
build-backend必须是可导入的路径字符串,"setuptools.build_meta"是官方推荐,"flit_core.buildapi"或"hatchling.build"也合法,但不能写错大小写或拼写
为什么 setup.py 无法满足现代需求?
它本质是一段任意 Python 代码,而现代流水线要求可审计、可复现、可提前解析——这三者它全做不到。
- IDE 和
pip show无法静态读取name、version、dependencies,因为它们藏在动态执行的函数调用里 - CI 构建时若
setup.py里写了os.system("curl ...")或读 Git tag 获取版本,就违反了“无网络、无副作用”的沙箱原则 - 不同 Python 版本下,
setup.py可能因find_packages()行为差异导致打包漏文件,而[tool.setuptools.packages.find]是声明式、版本无关的
迁移时最容易踩的坑是什么?
不是语法不会写,而是误以为“把 setup.py 内容抄进 pyproject.toml 就完事”——忽略了元数据位置和语义变化。
-
install_requires要挪到[project.dependencies],不是[project]顶层;extras_require对应[project.optional-dependencies] -
entry_points不再是字典,而是[project.scripts]或[project.entry-points."console_scripts"]这样的 TOML 表结构 -
long_description来自 README 的话,不能手写内容,得用readme = "README.md"+[project.readme]声明格式 - 如果你用了
setuptools_scm动态版本,pyproject.toml里得配[tool.setuptools.dynamic.version],而不是在setup.py里 import 调用
真正麻烦的从来不是配置文件换格式,而是那些藏在 setup.py 里的隐式逻辑:读文件、查环境变量、条件依赖、生成代码——这些都得显式迁移到 pyproject.toml 的对应扩展机制里,否则一跑就丢功能。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










