如何用Poetry构建冻结所有依赖的Python Wheel包?
核心需求
我需要用Poetry构建Python应用包,并完全冻结所有依赖版本,生成类似Home Assistant那样的受控Wheel包——确保安装时的依赖版本和应用构建验证时完全一致,避免因外部依赖未遵循SemVer、版本冲突(如sphinx与flake8的import-resource版本矛盾)导致应用崩溃、功能异常的问题。
注:这里讨论的是终端应用,而非供其他项目依赖的可共享库(后者在PyPI发布时声明版本范围是合理的)。
当前方法的局限
目前我通过poetry export生成prod-requirements.txt,再用pip install -c prod-requirements.txt来约束版本,但这种方式无法在pipx中生效——而我习惯用pipx为每个应用创建独立虚拟环境,同时希望开发依赖也能隔离(比如sphinx和flake8各用独立环境)。
可行的组合式实现方案
以下是无需等待Poetry官方支持,可自行实现的步骤:
步骤1:生成精确锁定的依赖清单
首先确保Poetry已锁定所有依赖版本:
poetry lock --no-update
然后导出生产环境的精确依赖到requirements.txt:
poetry export --without-hashes --format=requirements.txt --output=prod-requirements.txt
(如果需要包含哈希值增强安全性,去掉--without-hashes参数)
步骤2:构建基础Wheel包
用Poetry构建应用的基础Wheel包:
poetry build --format=wheel
构建好的Wheel包会出现在dist/目录下。
步骤3:修改Wheel包嵌入冻结依赖清单
Wheel本质是zip文件,可通过手动或脚本方式将prod-requirements.txt嵌入并修改元数据:
- 将Wheel包重命名为
.zip后缀,解压到临时目录 - 将
prod-requirements.txt放入解压后的根目录 - 编辑
RECORD文件,添加prod-requirements.txt,,条目 - 修改
METADATA文件,在Requires-Dist字段后添加:Requires-Dist: -r prod-requirements.txt - 重新打包为Wheel格式(改回
.whl后缀,保持原命名规范)
步骤4:适配pipx的安装脚本
创建自定义安装脚本,自动提取嵌入的依赖清单并传入pipx:
#!/bin/bash WHEEL_FILE="$1" # 提取依赖清单到临时文件 unzip -p "$WHEEL_FILE" prod-requirements.txt > /tmp/temp-constraints.txt # 用pipx安装并指定约束 pipx install "$WHEEL_FILE" --pip-args "-c /tmp/temp-constraints.txt" # 清理临时文件 rm /tmp/temp-constraints.txt
步骤5:开发依赖的隔离方案
在pyproject.toml中定义开发依赖组:
[tool.poetry.group.docs.dependencies] sphinx = "^7.0.0" [tool.poetry.group.lint.dependencies] flake8 = "^6.0.0"
然后为每个组创建独立虚拟环境:
# 为文档构建创建独立环境 poetry install --with docs --no-root # 为代码检查创建独立环境 poetry install --with lint --no-root
理想工具设想
我希望有一个工具可以直接接收原始Wheel包和冻结的requirements.txt,自动完成嵌入依赖清单、修改元数据的操作,生成开箱即用的冻结依赖Wheel包。
内容的提问来源于stack exchange,提问作者Gaetan

