当前位置:首页 > 文章列表 > 文章 > python教程 > Python wheel 构建元数据和依赖声明

Python wheel 构建元数据和依赖声明

来源:17golang原创 2026-10-17 08:13:05 0浏览 收藏

Python wheel 的依赖声明应放在 [project].dependencies,构建后端及其依赖放在 [build-system],项目版本则使用静态 version 或由后端提供的动态版本。三者解决不同问题:能生成 wheel,不代表安装它时就会得到运行所需的库。

Python 打包官方指南:https://packaging.python.org/en/latest/guides/writing-pyproject-toml/

Setuptools 官方文档:https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html;build 官方文档:https://build.pypa.io/en/stable/。

从“开发机正常,安装包后缺依赖”说起

设想一个名为 parcel-note 的内部工具:源码中的 parcel_note 包需要 packaging 解析版本。开发机早已安装 packaging,于是导入正常;交付 wheel 后,同事在另一套环境中却遇到缺少该库的问题。这里是用于解释配置的原创示例场景,不是真实事故记录,也不提供实测日志。

处理这个问题时,最容易出现的误判是“wheel 文件坏了”。实际上应先区分:包自身没被包含,还是包已经安装但依赖没有被声明。本文只处理后者,以及与它相邻的构建后端、版本来源问题,不讨论扩展编译或包索引上传。

把配置变更串起来,才能看见触发条件

这个示例的变化顺序很简单:工具起初直接在开发环境运行;后来加入 pyproject.toml 并生成 wheel;最后把 wheel 交给其他环境使用。出问题的触发条件不是“换了机器”本身,而是新环境不再替项目提前安装缺失依赖。

假如配置只在 build-system.requires 中加入 packaging,它表达的是构建时需要这个库,不等于声明安装后的运行依赖。反过来,只把 setuptools 写入运行依赖,也不能正确替代后端声明。build 是构建前端,负责调用后端;示例后端是 setuptools.build_meta,两者不是同一个角色。参见 build 的职责说明。

pyproject 中构建配置与项目依赖的静态分组结构
结构说明图:构建区包含 build-system.requires 与 build-backend,项目区包含 dependencies 与 optional-dependencies;连线表达归属,不代表执行顺序。

根因是把构建依赖误当成运行依赖

先给这个示例设置一个明确目录约定:根目录放 pyproject.toml,Python 包位于 src/parcel_note/,其中已有 __init__.py。下面配置适用于这一约定;项目名与版本号仅为示例,并非要求读者注册或安装某个同名公开项目。

[build-system]
# 这一组只负责构建所需工具;版本下限沿用官方当前示例
requires = ["setuptools>=77.0.3"]
build-backend = "setuptools.build_meta"

[project]
name = "parcel-note"
version = "0.4.0"
description = "An internal parcel note helper"
# 这是本示例自行约定的支持范围,不是 wheel 格式的最低要求
requires-python = ">=3.11"
# packaging 是工具运行需要的库,应在这里声明
dependencies = ["packaging>=24"]

[project.optional-dependencies]
# 只有选择 cli 功能时才需要 rich;版本范围需结合实际支持测试决定
cli = ["rich>=13"]

[tool.setuptools.packages.find]
# 显式使用 src 布局,避免让示例依赖自动发现的隐含假设
where = ["src"]

dependencies 是安装该项目通常需要的依赖,optional-dependencies 则按功能分组。cli 在这里是 extra 的名字,不会因为写在文件中就成为所有用户的必装依赖。库名和版本范围要来自实际代码需求与兼容性测试,不能把开发机中的全部包照搬进去。字段用法见 PyPA 依赖声明指南。

再强调两个限制:运行依赖通常不会作为完整第三方库直接塞入 wheel;requires-python 也只是兼容性声明,不会自动把新语法转换成旧版本语法。把下限写低不能使代码获得兼容能力。

版本只保留一个权威来源

示例先采用静态 version,目的在于把故障范围缩小。它是 parcel-note 自身的发布版本,与 setuptools 的版本、packaging 的依赖版本不是一回事。三种数字不能相互替换,也不能仅通过重命名 wheel 文件来更改项目元数据。

如果团队已经维护包内版本常量,可以改用后端支持的动态读取。对于 version 这种标量字段,应删除静态 version,再在 project 中声明 dynamic,并为 setuptools 配置读取位置。以下仅展示替换部分,原有 name、dependencies 等配置仍需保留:

[project]
name = "parcel-note"
# 用这一项替代静态 version,不要同时保留 version = "0.4.0"
dynamic = ["version"]

[tool.setuptools.dynamic]
# 由 setuptools 从指定属性取得项目版本
version = {attr = "parcel_note.__version__"}

对应的 src/parcel_note/__init__.py 可以只保留一个简单字符串常量:

# 使用可静态解析的值,避免版本读取依赖网络或运行环境
__version__ = "0.4.0"

不要让版本表达式执行复杂计算,也不要在包初始化中为读取版本强行导入尚未安装的运行库。动态字段如何取得值取决于后端,不能以为写了 dynamic 就自动获得 Git 标签版本。上述 attr 用法由 Setuptools 动态元数据文档支持;其他后端需要使用自己的配置。

项目声明字段与 wheel 核心元数据的对应关系
结构说明图:version、dependencies、requires-python 分别对应 Version、Requires-Dist、Requires-Python;图示是字段映射,不是某次构建产物截图。

修复落在声明层,而不是要求用户手工补包

回到示例,修复动作是补上 project.dependencies,明确后端配置,并决定项目版本的单一来源。如果临时让同事手工安装 packaging,可能解除当次导入错误,却没有修好交付契约;下一个空环境仍可能重复遇到问题。

读者可在自己的项目根目录使用以下构建命令。本文未运行这些命令,不声称生成了任何实际产物:

# 在已准备好 build 的项目环境中,仅构建 wheel
python -m build --wheel

build 会调用配置的构建后端。常规隔离构建不能依赖开发机偶然已有的库;如果后端或插件自身缺失,应处理构建依赖,而不是把它们全部塞进运行依赖。不要为了暂时绕过缺失声明就把关闭隔离当作根治办法。

配置项表达什么不表达什么
build-system.requires构建工具及插件依赖最终用户的完整运行依赖
project.dependencies运行依赖约束完整可复现环境锁定
project.version本项目版本Python 解释器或构建工具版本
project.requires-python解释器版本兼容范围自动测试或语法降级

下一次交付前,应该保留哪些判断依据

在团队自己的交付流程中,可将“配置声明”与“产物实际记录”分别留档:wheel 中 .dist-info/METADATA 的 Version 应体现项目版本,Requires-Dist 描述依赖,Requires-Python 描述解释器范围。不要只凭 wheel 文件存在就宣布依赖问题已经解决。字段含义可参考 核心元数据规范。

如果声明已经正确,安装仍缺依赖,再考虑安装命令是否禁止了依赖解析、是否选择了所需 extra,以及当前环境是否符合约束。不要在没有安装记录时直接断言是 pip 缓存或网络造成的。

requirements.txt 会自动成为 wheel 的依赖吗?

不能这样假定。只有后端的明确配置把某个文件作为元数据输入时,文件内容才可能参与依赖生成。普通 requirements 文件的用途和项目元数据不同,本文采用显式 project.dependencies,避免隐式关联。

把所有依赖写成等号固定版本就一定更稳吗?

不是。项目发布声明约束的是可接受的依赖范围,某个部署环境的精确版本集合是另一层管理问题。是否精确固定,应结合应用交付方式与兼容策略决定,不能拿开发机快照代替项目依赖设计。

换一个构建后端能直接修好缺依赖吗?

仅更换名字通常不能。需要确认新后端理解所用元数据格式、拥有匹配的构建配置,并且依赖声明本身正确。对这个示例而言,先修清楚“构建需要什么、运行需要什么、项目版本从哪里来”,比更换整套工具更直接。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python urllib.request 构造带超时的 HTTP 请求Python urllib.request 构造带超时的 HTTP 请求
上一篇
Python urllib.request 构造带超时的 HTTP 请求
Linux systemd-journald 持久化日志的配置方法
下一篇
Linux systemd-journald 持久化日志的配置方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    500次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    558次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    587次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    539次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    349次使用