如何从符合pyproject规范的Python项目构建pex或shiv包
核心结论
shiv 和 Pex 目前都没有原生提供符合 PEP 517 规范的构建后端实现,不存在你预期的类似shiv.build_xxx的可直接填入build-backend字段的入口,没法直接把二者设为独立构建后端,单靠配置[build-system]段就实现python -m build直接输出自包含包。
落地方案
方案1:基于现有setuptools后端加自定义构建步骤(推荐,零迁移成本)
这个方案完全兼容你现在用pipenv管依赖、setuptools做构建后端的流程,不需要改现有项目结构,只需要加少量配置和脚本,就能实现执行python -m build自动输出shiv/pex自包含包。
- 先修改根目录的
pyproject.toml,把shiv(或pex)加入构建依赖,绑定自定义构建命令:
[build-system] requires = ["setuptools>=61.0", "wheel", "shiv"] build-backend = "setuptools.build_meta" [tool.setuptools.cmdclass] build_py = "build_shiv.ShivBuild"
- 在项目根目录新建
build_shiv.py文件,写入自动打包逻辑,替代你手动敲的导出requirements、调用shiv的步骤:
import os import subprocess import tempfile from setuptools.command.build_py import build_py class ShivBuild(build_py): def run(self): # 先走标准的源码、wheel构建流程 super().run() # 自动从pipenv导出依赖清单,不用手动生成requirements.txt req_file = tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) req_path = req_file.name req_file.close() subprocess.run( ["pipenv", "requirements", "-o", req_path], check=True ) # 自动创建输出目录、调用shiv打包 os.makedirs("app", exist_ok=True) out_path = "app/myappfile.pyz" subprocess.run( [ "shiv", "--console-script", "myapp", "-o", out_path, "-r", req_path, "." ], check=True ) os.unlink(req_path) print(f"自包含可执行包构建完成,输出路径:{out_path}")
配置完成后,直接在pipenv虚拟环境里执行python -m build,就会自动走完所有流程,直接生成你要的app/myappfile.pyz,不需要额外敲其他命令。如果要打Pex格式的包,只需要把构建依赖换成pex,把脚本里调用shiv的部分换成对应pex命令参数即可。
方案2:使用带shiv/pex封装的第三方构建后端
如果不想写自定义脚本,可以选择已经封装了shiv/pex打包逻辑的PEP517构建后端,比如部分Hatch、Poetry的构建插件支持直接配置输出shiv/pex包,但这类方案需要你把现有依赖管理从pipenv迁移到对应的工具,迁移成本较高,不推荐你当前场景使用。
避坑说明
- 不要直接把shiv或pex的模块路径填入
build-backend字段:二者的代码没有实现PEP517要求的构建接口(比如构建wheel、sdist的标准方法、构建依赖查询接口等),直接填写会直接报构建后端无效的错误。 - zipapps确实不满足你的需求:它本身没有依赖解析、自动打包第三方库的能力,需要手动提前整理所有依赖文件,不适合有第三方依赖的项目。
- 如果你后续不想依赖pipenv导出依赖,可以直接在
pyproject.toml的[project]段写全dependencies依赖清单,自定义脚本直接读取该字段生成requirements即可,不需要调用pipenv命令。
内容的提问来源于stack exchange,提问作者Jim DeLaHunt
相关产品推荐
相关产品推荐

