在24 的隔离环境里,PYTHONPATH=src 能运行任务,但这并不测试安装。现在从项目 pyproject.toml 构建 wheel 与 sdist,再把 wheel 装进另一个没有 pip、也不把源码目录加入 PYTHONPATH 的 venv;从仓库外运行生成的 tasklab 命令,先提交,再通过另一个进程执行和查询同一 SQLite 文件,最后验证重复执行被拒绝。安装后 tasklab.__file__ 位于新环境的 site-packages,不是工作树的 src。

这次新增的是分发边界,不是新任务引擎。21 篇的数据库合同和取消逻辑仍由原模块执行。发布到 PyPI、跨平台兼容性和非信任网络输入不在本章验收范围。

分清三个文件和三种角色

pyproject.toml 的 [build-system] 选择 setuptools.build_meta,将后端 setuptools==80.9.0、构建 wheel 所需 wheel==0.45.1 固定;[project] 保留 name=tasklab、version=0.1.0、requires-python>=3.12 与空运行依赖。[project.scripts] 把 tasklab 入口指到 tasklab.db_cli:main;[tool.setuptools.packages.find] 从 src 查找真正的包。构建前端选择 build==1.3.0,它不是应用运行依赖;前端、后端、运行依赖各在不同阶段起作用。

这次在受控工具环境用 python -m build --no-isolation --outdir artifacts,因为工具环境已安装固定的前端、后端及传递依赖;禁用构建隔离不是绕过依赖冻结。build-requirements.lock 钉住五个构建工具包(包括传递依赖 packaging、pyproject_hooks),附官方 wheel SHA-256,另用 pip download --require-hashes 实际验证这五项哈希。安装器 pip 固定在 25.2,见 24 的单独引导证据;这些是构建工具锁,不是“所有未来平台的运行依赖锁”。本项目此时运行依赖声明与解析结果均为空,已安装构建环境的 pip freeze --all 单独保留,不能把三层混成一份列表。

tools/inspect_dist.py 打开真实 wheel 和 sdist:确认 wheel 内有数据库、CLI、JSON 模块与 tasklab = tasklab.db_cli:main,没有测试夹具;确认 sdist 内有 pyproject.toml、README 与源代码。两个制品的 SHA-256 记录在 examples/python-language/evidence/25/20261007-wheel/artifacts.sha256,制品本体保存在 examples/python-language/artifacts/。检查内容目录不证明跨机器构建出的压缩包逐字节相同;这一次的 SHA-256 对应实际安装验证的那一对制品。

新环境不含构建工具也能运行

用系统 /usr/bin/python3.12 -m venv --without-pip 建立第二个空环境,再从外部工具环境调用 pip --python 第二环境/bin/python install --no-deps tasklab-0.1.0-py3-none-any.whl。pip 不必安装进目标环境,目标安装列表只看到 tasklab==0.1.0;本项目无第三方运行依赖,因此这里的 --no-deps 不会掩盖声明中的额外包。验证脚本在仓库外工作目录启动,以目标环境 bin/tasklab 先后执行 submit、run、query、cancel 和重复执行的失败场景,保留每个独立进程的标准流和退出码。若轮到有运行依赖的版本,单凭 --no-deps 安装成功不能证明依赖完整。

1
2
3
4
5
cd examples/python-language
/tmp/tasklab24-clean-INVHXp/bin/python -m build --no-isolation --outdir artifacts
/usr/bin/python3.12 tools/inspect_dist.py artifacts
cd /tmp
/tmp/tasklab25-install-Ac9pzR/bin/python /home/admin/workspace/my-blogs/examples/python-language/tools/check_installed.py

路径是本次执行留下的临时环境,不应作为跨机器固定路径;可复现的版本、锁与真实命令在 examples/python-language/evidence/25/20261007-wheel/。原有累计测试仍需重跑;不能把 24 的源码测试冒充 25 的制品安装测试。此时没有执行 PyPI 上传或安装 sdist:sdist 只检查内容,25 的安装结论仅关于 wheel。

预测题

删掉 [project.scripts],python -m tasklab.db_cli 在源码目录还能运行吗?这能证明从 wheel 安装后的 tasklab 命令存在吗?

答案:模块入口仍可能通过 python -m 启动,但安装器不会凭它自动创建控制台脚本。tools/inspect_dist.py 检查 wheel 的 entry_points.txt,目标 venv 还要实际启动 bin/tasklab;缺少声明就会在至少一处被抓到。这里没有真的删去并重新打包该变式。

变更题

将打包发现路径从 src 改成一个不存在的目录,再只运行原来设置 PYTHONPATH=src 的测试,能发现什么?应追加哪项制品验收?

答案:源码测试可能照旧通过,无法证明 wheel 带有任务模块。需要实际构建、查看 wheel 文件表并在干净环境安装后从仓库外导入和运行命令;本章的制品清单及无源码路径安装正是对这个缺口的检查。不同操作系统、Python 3.14 和发布索引未测。

26 将核验版本、兼容约束、制品哈希及本地发布材料,但不得实际上传包索引。系列导航只列已验收文章。

参考资料