DEBUG.WIKI
雨云;给项目一台云服务器
腾讯云;让你的想法跑起来;轻量服务器 · 建站 / Docker / API;查看产品 →
晚安云;香港 CN2 ¥15/月

Hatchling 1.32 起拒绝 ../README.md,README 必须放进项目边界

Hatchling 1.32 起检查 README 的项目边界。将说明文件放入各包或使用内联文本,再验证独立 sdist 与 wheel,避免依赖仓库父目录。

monorepo 里两个 Python 包共用仓库根部的说明文件,子目录中的配置写着 readme = "../README.md"。升级 Hatchling 1.32.0 后,构建在元数据阶段报错:

Readme path must be within the project directory: ../README.md

这是 1.32.0 引入并保留在 1.32.4 的路径检查。README 文件确实存在、终端也能读到,并不足以通过检查;该字段不能用绝对路径或解析到项目目录之外的路径。单纯升级到较新的修复版不会取消这条规则。

项目目录由这一个包的构建入口决定

仓库根目录不一定就是每个包的项目根。例如 repo/package-a/pyproject.toml 描述一个独立发行包,而共享说明位于 repo/README.md,../README.md 就离开了 package-a 的边界。

源码仓库检出后能找到父目录,不代表用户拿到这个包的 sdist 后也有相同的仓库布局。README 是包的长描述元数据,不能依赖发行包之外还存在另一个目录。这里与 wheel 安装后找不到运行时资源不同,失败发生在读取构建元数据时。

先对照触发构建的 pyproject.toml、后端版本和 readme 实际值。若错误是 Readme file does not exist,且路径本来就在项目里,应检查文件是否提交、大小写及构建上下文;不要把所有 README 报错都当成路径边界限制。

在每个包内维护可独立分发的 README

稳定的处理方式是在各项目目录内提供自己的说明文件,配置改为项目内路径。下面是应合并到原 [project] 表里的字段:

[project]
readme = "README.md"

保留原项目名称、版本、依赖等字段。文件内容可以由仓库统一生成流程同步,但生成步骤必须早于读取项目元数据,并让生成结果进入独立 sdist。不要只在本机临时复制一次,CI 和从 sdist 构建时却没有这个文件。

如果多个包确实共用一份短说明,也可在包各自的配置中直接保存文本并声明格式:

[project]
readme = {text = "该发行包的简短说明。", content-type = "text/markdown"}

这是另一种 readme 表达方式,不应与前一个字符串字段同时保留。内容要写成这个包实际需要的说明,不要为了绕过错误把长描述清空。较长文档通常仍适合放在包内文件中,便于审阅与维护。

把字段改成绝对路径不能解决边界问题。用符号链接指向仓库外文件,也不能据此保证独立 sdist 包含真实内容;应检查产物,不把某台开发机上的可读路径当成发行约束。

用独立源码包验证目录关系

保存改动前的配置和说明文件。在项目现有构建流程中生成新的 sdist,只读检查其中是否有正确的 README 及元数据,再在不依赖原仓库父目录的干净位置从这份 sdist 构建 wheel。长描述应完整,包的其他文件选择规则也应保持预期。

若同步生成 README,另检查直接构建 wheel、构建 sdist、从 sdist 再构建三条入口,避免只覆盖其中一条。回退配置之前保留包内说明文件;恢复 ../README.md 只会再次依赖旧布局,并不会让已分发的源码包补上缺失的父目录。