DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

MANIFEST.in 已包含资源,安装 wheel 后却找不到文件

资源进入sdist,未必会安装进wheel。检查实际包目录、package-data与exclude规则,再从源码之外安装验证,避免editable掩盖漏装。

源码压缩包里能找到 JSON、模板或测试 fixture,安装 wheel 后程序却报资源路径不存在。先分别检查 sdist 和 wheel 的成员:文件被收入源码包,不等于已经被选为安装到 Python 包里的资源。

下面针对 Setuptools 构建。其他后端使用自己的文件选择规则,不能只因项目中有 MANIFEST.in,就假定它一定被当前构建入口读取。

看真正安装的产物,不只看工作目录

核对 pyproject.toml 的构建后端、包发现范围、资源的真实位置和失败路径。使用压缩包工具只读查看 sdist 与 wheel,确认缺失文件究竟在哪一步没有进入产物;不要通过执行陌生包的安装脚本来代替查看成员列表。

如果 wheel 里根本没有文件,先修构建选择。如果文件已经在 wheel 中,而程序仍找错目录,再查运行时资源读取方式。editable 安装可能直接访问源码目录中的文件,会掩盖正常 wheel 安装缺资源的问题。

根目录的 README、部署配置或独立 data/,不会只因为写进 MANIFEST.in 就自动成为某个 importable 包的运行时资源。先决定哪些文件需要随包分发,哪些应由部署流程提供;不要把整个源码目录都打进 wheel 来碰碰运气。

package-data 的路径相对于包目录

假设现有普通包是 mypkg/,已经被正确发现,资源确实位于 mypkg/tests/fixtures/test3.zip。在已有 Setuptools pyproject 配置中,可明确选择:

[tool.setuptools.package-data]
mypkg = ["tests/fixtures/*.zip"]

mypkg 是实际包名,模式相对于该包目录;src 布局下也不应把值写成 src/mypkg/tests/fixtures/*.zip。多层包名应按对应 dotted name 和真实目录确定。这里没有更改已有包发现规则,不能靠这段配置补出一个根本没被收入的包。

package-data 可以直接选择相应资源,不要求先在 MANIFEST.in 中重复列举。另一条路径是让包目录内的文件由 MANIFEST.in 或已配置的版本管理插件选入,并启用 include-package-data。两条路径要按项目现状选择,不能宣称 wheel 永远忽略 MANIFEST。

还要核对默认值与排除规则

Setuptools 从 61 起,在 pyproject 配置中默认启用 include-package-data;setup.py 和 setup.cfg 的默认值则仍为 false。旧配置迁移到 pyproject 后,别只凭习惯解释某个字段是否生效。

exclude-package-data 会排除匹配的资源,即使它已经被前面的规则选中。缺失时一起检查 include、package-data 和 exclude 的实际组合,不要只不断扩大 glob。

现代 namespace package 不一定需要 __init__.py。是否应当收入某个无该文件的目录,取决于包设计和发现配置;不能为了一个资源错误到处添加空 __init__.py,改变原来的包边界。

Setuptools 的 SOURCES.txt 和旧 build 输出也可能保存过往文件列表。先确认它们是本项目可重建的构建元数据或临时产物,再按现有清理流程刷新;保留源码、用户数据和需要回退的发行包,不照搬全目录递归删除命令。

安装后从包中读资源

资源进入 wheel 后,支持相应 API 的 Python 可以用 importlib.resources 读取。例如 mypkg 是已安装的普通包,Python 至少为 3.9:

from importlib.resources import files

data = files("mypkg").joinpath(
    "tests/fixtures/test3.zip"
).read_bytes()

这里只读取资源字节;需要实际文件路径的接口,应按资源 API 管理临时路径的生命周期。不要把当前工作目录当作安装位置,也不要默认包永远以普通目录形式存在。资源 API 同样无法找回一个未进入 wheel 的文件。

在项目的干净构建目录生成新 sdist 和 wheel,检查两份成员,再到源码目录之外的独立环境安装目标 wheel,运行真正读取资源的功能。保存原配置及产物,切换有问题时恢复匹配的版本;只恢复打包配置不会替换用户环境中已经安装的 wheel。

如果构建还没开始选资源,就报多个顶层包被发现,可以先看flat-layout 的包发现范围。