Python pyproject.toml 的完整字段说明

1次阅读

pip install 仅读取 [build-system] 和 [project] 两个顶层表;前者需指定 requires 构建依赖,后者必填 name 和 version,其他字段如 [tool.*] 或 optional-dependencies 不影响安装行为。

Python pyproject.toml 的完整字段说明

pyproject.toml 里哪些字段是 pip install 时真正读的

pip install(包括从源码构建)只认 [build-system][project] 这两个顶层表。其他字段比如 [tool.black][project.optional-dependencies] 不影响安装行为,只是工具约定。

常见错误:把 requires-python 写在 [tool.poetry] 下,结果 pip 完全无视——它只看 [project].requires-python

  • [build-system.requires] 必须包含构建依赖,例如 ["setuptools>=45", "wheel"];缺了可能导致 ModuleNotFoundError: No module named 'setuptools.build_meta'
  • [project]nameversion 是必填项,否则 pip 构建失败并报错 Invalid pyproject.toml config: 'project.name' is required
  • [project.version] 推荐用动态方式(如 dynamic = ["version"] + [tool.setuptools.dynamic.version]),硬编码易遗漏发布前更新

setuptools、flit、poetry 对 [project] 字段的支持差异

不是所有字段在所有构建后端里都生效。比如 [project.urls] 在 setuptools 和 flit 中生成 wheel 的 METADATA 正确,但 poetry 2.0+ 默认忽略它,除非显式启用 include = ["pyproject.toml"]

使用场景:你想让 pip show mypkg 显示项目主页和文档链接,就得确认当前构建后端是否导出 [project.urls] 到元数据。

立即学习Python免费学习笔记(深入)”;

  • [project.dependencies] 所有后端都支持,但格式必须是 PEP 508 字符串列表,不能写成嵌套 TOML 表
  • [project.optional-dependencies] 全支持,但注意 poetry 会把 key 名自动转为小写并去空格,"django Support" 变成 django-support
  • [project.entry-points."console_scripts"] setuptools/flit 没问题;poetry 需要额外配置 [tool.poetry.plugins."console_scripts"] 才能注册

动态 version 怎么写才不被 pip build 忽略

直接写 version = "1.2.3" 看似简单,但版本号一变就要手动改,CI/CD 容易出错。动态方案得让构建后端“看得见、算得对”。

最容易踩的坑:用 Python 文件读取 __version__.py,但没在 [build-system] 中声明该文件为构建依赖,导致在干净环境中构建失败。

  • 推荐做法:用 [project.version] 设为 dynamic = ["version"],再配 [tool.setuptools.dynamic.version] + attr = "mymodule.__version__"
  • 路径必须可 import:如果模块不在 src/ 下,得同步设 [tool.setuptools.package-dir],否则构建时报 ModuleNotFoundError
  • 避免用 file 方式读取版本文件——TOML 解析器不执行 Python,file = "VERSION" 仅在 setuptools 61.0+ 支持,且要求文件纯文本不含任何逻辑

windows 上 pyproject.toml 路径或换行符引发的构建失败

不是语法问题,而是环境细节:CRLF 换行、bom 头、路径含中文或空格,都会让某些构建后端(尤其是旧版 setuptools)静默失败或报奇怪错误。

典型现象:pip wheel . 卡住几秒后退出,无报错;或提示 Invalid value for 'project.name': must be non-empty,其实 name 明明写了。

  • 保存为 UTF-8 无 BOM(Notepad++ / VS Code 都可设),BOM 会导致 TOML 解析器跳过首行
  • 避免在 [project.readme] 中写相对路径如 readme = "README.md",如果项目根目录路径含空格,部分后端解析失败;改用 readme = {file = "README.md"} 更稳
  • Windows 用户若用 git bash,确保 core.autocrlf 设为 true,否则 CRLF 可能被误判为非法字符

事情说清了就结束。字段再多,最终起作用的也就那几个表;工具再花哨,pip 只信 [project][build-system]。其他全是锦上添花,别当真。

text=ZqhQzanResources