setuptools-scm 构建无标签归档时,报 tag '' 和 AssertionError
归档有提交哈希却没有describe-name,旧解析器可能把空值当标签。核对隔离构建的实际后端,修复后仍需检查wheel版本与真实发行身份。
从 Git 源码归档安装 Python 包,构建依赖已经装好,却在取版本号时先提示 tag '' no version found,再从 archival_to_version 或 _parse_tag 抛出 AssertionError。如果归档里有有效的提交信息、describe-name 却为空,需要检查版本解析后端是否包含处理空值的修复。
这与找不到 Git 可执行程序、构建环境没装 setuptools-scm,或者普通仓库缺少 tags 的所有情况不同。本文针对已经进入归档解析器的这条调用栈,不把所有 subprocess-exited-with-error 都归到它。
检查归档里的真实内容
在已经解压的源码目录中,只读查看 .git_archival.txt。支持归档取版本的项目通常保存 node、node-date 和 describe-name。当分支没有匹配的版本标签时,归档可能有真实提交哈希,但 describe-name: 后面没有内容。
这种空值与未展开模板不同。如果 node 仍是 $Format:%H$,说明尚未得到可用的归档提交信息;单纯把模板文件复制进 zip,不能代替 git archive 的替换过程。源码归档通常没有 .git,也不能指望在解压目录中重新查询完整提交历史。
保留最早的 warning 和完整版本解析栈,核对失败的是哪个后端。最后一行“可能不是 pip 的问题”只说明异常来自子进程,没有确定是哪份依赖需要调整。
外层环境升级,不等于隔离构建用了新解析器
检查 pyproject.toml 的 build-system.requires、构建约束以及安装日志里的实际版本。PEP 517 隔离构建会准备自己的依赖;终端里 pip show setuptools-scm 的结果,可能与失败构建环境不同。
在正式 vcs-versioning 2.6.0 中,归档解析器遇到空的 describe-name 会跳过标签解析,继续处理提交信息。setuptools-scm 10.3.4 则是调用该后端的适配包,其声明允许 vcs-versioning>=2.5.0.dev0,<3。这个范围包含 2.6.0,也允许其他版本,因此仅看到适配包版本,不能证明锁定的后端已经包含修复。
对符合项目 Python 和构建要求的环境,可以评估这组正式版本,并通过现有构建依赖管理明确选中它们。合并到原有 build-system.requires 时,保留其他构建工具和约束;不要为了修一处解析错误覆盖整个表,也不要顺便关闭构建隔离。
修改后重新检查构建日志中的实际解析器,而不是只升级运行应用的虚拟环境。若必须沿用旧构建栈,应在项目范围内安排有明确来源的修复或改用合适的发行源码包,不把随意复制后端文件当作正常安装。
不报错后,还要检查生成的版本
当前后端在只有有效 node、没有可用版本标签时,可走以 0.0 为基础的回退。这不等于算出了从仓库根提交以来的提交距离,也不保证它就是项目应公开发行的版本号。
正式发行应采用项目真实的版本身份:从正确的版本标签生成支持替换的归档,或者使用带有既定版本元数据的正式 sdist。不要为了让构建成功随便创建一个标签,或把 fallback_version 填成看起来合适的数字,再宣称版本来源已经恢复。
维护自己的归档流程时,.git_archival.txt 中的模板与 .gitattributes 的 export-subst 需要一起生效;已有文件应按真实 tagging 规则整理。构建完成后检查 wheel 的发行版本和元数据,再从独立环境安装、运行原入口,确认依赖解析及发布规则都接受这个身份。
保存原构建声明、约束与归档文件。回退时一起恢复依赖选择和构建输入,重新生成产物;恢复配置不会自动撤回已经发布到索引的错误版本。若实际错误是隔离环境里 No module named pip,应另查构建依赖声明。


