PEP 426 – Python 软件包元数据 2.0
- 作者:
- Alyssa Coghlan <ncoghlan at gmail.com>,Daniel Holth <dholth at gmail.com>,Donald Stufft <donald at stufft.io>
- BDFL 代表:
- Donald Stufft <donald at stufft.io>
- 讨论列表:
- Distutils-SIG 列表
- 状态:
- 已撤回
- 类型:
- 信息性
- 主题:
- 打包
- 依赖:
- 440, 508, 518
- 创建:
- 2012 年 8 月 30 日
- 更新历史:
- 2012 年 11 月 14 日,2013 年 2 月 5 日,2013 年 2 月 7 日,2013 年 2 月 9 日,2013 年 5 月 27 日,2013 年 6 月 20 日,2013 年 6 月 23 日,2013 年 7 月 14 日,2013 年 12 月 21 日
- 替换:
- 345
摘要
本 PEP 描述了一种发布和交换与 Python 分发相关的元数据的机制。它包括字段名称的具体信息,以及它们的语义和用法。
本文档指定了从未发布的元数据格式版本 2.0。
版本 1.0 在 PEP 241 中指定。版本 1.1 在 PEP 314 中指定。版本 1.2 在 PEP 345 中指定。
元数据格式版本 2.0 提案从直接定义自定义键值文件格式迁移到定义 JSON 兼容的内存表示,该表示可用于在其他上下文中定义元数据表示(例如 API 和存档格式定义)。
此版本还定义了一种正式的扩展机制,允许为特定目的添加新字段,而无需更新核心元数据格式。
关于 PEP 历史的说明
此 PEP 最初被延迟了很长一段时间,从 2013 年 12 月到 2017 年 3 月,因为 distutils-sig 处理了许多其他更改。这些更改包括
- 在 PEP 425 中定义二进制兼容性标记格式
- 在 PEP 427 中定义二进制存档格式(
wheel
) - 在 PEP 440 中明确定义版本控制和版本比较
- 在 PEP 503 中明确定义 PyPI “简单” API
- 在 PEP 508 中明确定义依赖关系说明符和额外功能系统
- 在 PEP 518 中声明静态构建系统依赖关系(
pyproject.toml
) - 将 PyPI 托管迁移到 Rackspace,并将其置于 Fastly CDN 后面
- 在 PEP 453 中默认情况下随 CPython 一起发布
pip
,并在 PEP 477 中将此添加内容移植到 Python 2.7 - 建立 packaging.python.org 作为 Python 打包生态系统文档的公共访问点
- 迁移到使用 packaging.python.org 的 规范 部分作为跟踪与打包相关的 PEP 的中心位置
花费时间进行这些更改提供了关于哪些元数据格式更改是真正需要的以及哪些可以从修订规范中省略(仅仅是“为了更改而更改”)的额外视角。
它还允许将许多对软件发布和分发的核心活动不重要的功能移至 PEP 459,这是一个关于许多标准元数据扩展的单独提案,这些扩展提供了有关版本的其他可选信息。
截至 2017 年 9 月,它再次被延迟,理由是它实际上并没有帮助解决任何特别紧迫的问题
- JSON 表示最好通过定义现有元数据 1.2 字段的转换来处理
- 过去几年中定义的附加字段的说明以及与规范管理流程相关的更改最好在 较小的规范版本更新 中介绍
最后,此 PEP 于 2018 年 2 月被撤回,转而采用 PEP 566(该 PEP 采用了更渐进的策略)。
目的
本 PEP 的目的是为 Python 生态系统中软件发布工具和软件集成工具之间的通信定义一种通用的元数据交换格式。一个关键目标是在该生态系统中支持完整的依赖关系分析,而无需执行那些进行分析的人员执行任意 Python 代码。另一个目标是默认情况下鼓励良好的软件分发实践,同时继续支持 Python 包索引(发布者和集成者)几乎所有现有用户的当前实践。最后,目标是支持从当前使用的元数据格式到对最终用户透明的升级路径。
该设计借鉴了 Python 社区近 20 年使用基于 distutils 的软件分发的经验,并结合了其他分发系统中的想法和概念,包括 Python 的 setuptools、pip 和其他项目、Ruby 的 gems、Perl 的 CPAN、Node.js 的 npm、PHP 的 composer 和 Linux 打包系统(如 RPM 和 APT)。
虽然此格式的细节针对 Python 生态系统,但其中的一些想法在未来其他依赖关系管理生态系统的演变中也可能有用。
Python 软件的开发、分发和部署
此 PEP 中的元数据设计基于软件开发和分发过程的特定概念模型。此模型包含以下阶段
- 软件开发:此阶段涉及使用特定应用程序的源代码检出进行工作,以添加功能和修复错误。预计此阶段的开发人员需要能够构建软件、运行软件的自动化测试套件、运行项目特定的实用程序脚本并发布软件。
- 软件发布:此阶段涉及获取开发的软件并使其可供软件集成者使用。这包括创建此 PEP 中定义的描述性元数据,以及使软件可用(通常是将其上传到索引服务器)。
- 软件集成:此阶段涉及获取已发布的软件组件并将它们组合成一个连贯的集成系统。这可以通过直接使用 Python 特定的跨平台工具来完成,也可以通过转换为与开发语言无关的平台特定打包系统来处理。
- 软件部署:此阶段涉及获取已集成的软件组件并将其部署到软件实际执行的目标系统上。
发布和集成阶段统称为分发阶段,在此阶段分发的各个软件组件正式称为“分发包”,但在口语中更常被称为“包”(依靠上下文来区分它们与“具有子模块的模块”类型的 Python 包)。
对于特定用例,这些阶段的确切细节将有很大差异。将 Web 应用程序部署到公共平台即服务提供商、发布 Web 框架或科学库的新版本、创建集成 Linux 发行版或升级在安全 enclave 中运行的自定义应用程序,所有这些情况都应能够使用此元数据设计来处理。
因此,此 PEP 中描述的元数据的复杂性直接源于与各种场景中软件开发、分发和部署相关的实际复杂性。
支持性定义
本文档中的关键词“必须”、“不得”、“需要”、“应该”、“不应该”、“建议”、“可以”和“可选”应按 RFC 2119 中所述进行解释。
“项目”是可以用于集成的软件组件。项目包括 Python 库、框架、脚本、插件、应用程序、数据集合或其他资源,以及它们的各种组合。公共 Python 项目通常在 Python 包索引 上注册。
“版本”是项目的唯一标识的快照。
“分发包”是用于发布和分发版本的打包文件。
根据上下文,“package”(包)可以指代发布版(distribution),也可以指代一个可导入的 Python 模块,该模块具有 __path__
属性,因此也可能包含可导入的子模块。
“Source archive”(源代码归档)和“VCS checkout”(版本控制系统检出)都指代发布版的原始源代码,在创建 sdist 或二进制归档文件之前。
“sdist”(源代码发布版)是一种发布格式,提供发布版元数据和创建二进制归档文件所需的任何源文件。从 sdist 创建二进制归档文件需要系统上存在相应的构建工具。
“Binary archives”(二进制归档文件)只需要将预构建的文件移动到目标系统上的正确位置即可。由于 Python 是一种动态绑定的跨平台语言,因此许多所谓的“二进制”归档文件仅包含纯 Python 源代码。
“Contributors”(贡献者)是指共同开发软件组件的个人和组织。
“Publishers”(发布者)是指使软件组件可供集成的个人和组织(通常是将发布版上传到索引服务器)。
“Integrators”(集成者)是指将已发布的发布版作为应用程序或更大系统组件的个人和组织。
“Build tools”(构建工具)是在开发系统上运行的自动化工具,用于生成源代码和二进制发布版归档文件。构建工具也可以由集成工具调用,以便构建作为 sdist 分发的软件,而不是预构建的二进制归档文件。
“Index servers”(索引服务器)是活跃的发布版注册表,发布版本和依赖项元数据,并对允许的元数据施加约束。
“Public index servers”(公共索引服务器)是允许来自不受信任的第三方的发布版上传的索引服务器。Python 包索引 是一个公共索引服务器。
“Publication tools”(发布工具)是在开发系统上运行的自动化工具,用于将源代码和二进制发布版归档文件上传到索引服务器。
“Integration tools”(集成工具)是自动化工具,它使用索引服务器或其他指定来源发布的元数据和发布版归档文件,并以某种方式使用它们,例如安装它们或将它们转换为特定于平台的打包格式。
“Installation tools”(安装工具)是专门用于在部署目标上运行的集成工具,从索引服务器或其他指定位置使用源代码和二进制发布版归档文件,并将它们部署到目标系统。
“Automated tools”(自动化工具)是一个统称,涵盖构建工具、索引服务器、发布工具、集成工具以及任何其他生成或使用发布版版本和依赖项元数据的软件。
“Legacy metadata”(旧版元数据)指代此元数据规范的早期版本,以及由 setuptools
项目定义的支持元数据文件格式。
“Distro”(发行版)用作 Linux 发行版的首选术语,以帮助避免与 Python 特定的“distribution package”(发布包)术语混淆。
“Qualified name”(限定名称)是指带点的 Python 标识符。对于导入的模块和包,限定名称可作为 __name__
属性使用,而对于函数和类,则可作为 __qualname__
属性使用。
“Fully qualified name”(完全限定名称)在 Python 模块命名空间中唯一地定位一个对象。对于导入的模块和包,它与限定名称相同。对于其他 Python 对象,完全限定名称由包含模块或包的限定名称、一个冒号 (:
) 以及相对于包含模块或包的对象的限定名称组成。
“Prefixed name”(前缀名称)以限定名称开头,但不一定是限定名称——它可能包含其他用点分隔的段,这些段不是有效的标识符。
分发的集成和部署
发布版元数据的主要目的是支持将发布版作为更大应用程序和系统的一部分进行集成和部署。
集成和部署又可以进一步细分为子步骤。
- 构建:构建步骤是将 VCS 检出、源代码归档或 sdist 转换为二进制归档文件的过程。为了构建和创建发布版的二进制归档文件(包括在目标系统上安装的任何文档),必须使用依赖项。
- 安装:安装步骤包括将发布版及其所有运行时依赖项获取到目标系统上。在此步骤中,发布版可能已存在于系统上(升级或重新安装时),或者也可能是一个全新的安装。
- 运行时:这是在发布版安装到目标系统上之后对其进行正常使用的过程。
这三个步骤都可能直接在目标系统上发生。或者,可以通过使用发布者提供的二进制归档文件或在部署之前在单独的系统上创建二进制归档文件来将构建步骤分离出来。后一种方法的优点是最大程度地减少了需要在部署目标上安装的依赖项(因为构建依赖项仅在构建系统上需要)。
发布版包的发布元数据**应该**允许集成者在构建和集成工具的帮助下
- 获取用于创建发布版的原始源代码
- 识别和检索使用发布版所需的依赖项(如果有)
- 识别和检索从源代码构建发布版所需的依赖项(如果有)
- 识别和检索运行发布版测试套件所需的依赖项(如果有)
分发的开发和发布
发布版元数据的次要目的是在开发阶段支持软件贡献者和发布者之间的有效协作。
发布版的发布元数据**应该**允许贡献者和发布者在构建和发布工具的帮助下
- 执行有效集成和部署发布版所需的所有相同活动
- 识别和检索开发和发布发布版所需的额外依赖项
- 指定使用发布版所需的依赖项(如果有)
- 指定从源代码构建发布版所需的依赖项(如果有)
- 指定运行发布版测试套件所需的依赖项(如果有)
- 指定开发和发布发布版所需的额外依赖项(如果有)
元数据格式
本 PEP 中定义的格式是 Python 发布版元数据作为字符串键字典的内存表示形式。各个条目的允许值包括字符串、字符串列表以及其他嵌套的字符串键字典。
除非另有说明,否则发布版元数据中的字典键**必须**是有效的 Python 标识符,以便支持基于属性的元数据访问 API。
各个字段描述显示了键名称和值的示例,它们将作为 JSON 映射的一部分进行序列化。
除非另有说明,否则被标识为核心元数据的字段是必需的。自动化工具**不得**接受缺少核心元数据的发布版作为有效的 Python 发布版。
所有其他字段都是可选的。除非那些专门需要省略字段的操作,否则自动化工具**必须**在发布版不提供这些字段的情况下正常运行。
自动化工具**不得**为缺少的字段插入虚拟数据。如果未为必需字段提供有效值,则**必须**拒绝元数据和关联的发布版作为无效。如果未为可选字段提供有效值,则**必须**完全省略该字段。自动化工具**可以**从其他信息源(例如版本控制系统)自动派生有效值。
自动化工具,尤其是公共索引服务器,**可以**对元数据施加超出本 PEP 中列出的其他长度限制。此类限制**应该**在必要时实施,以保护服务的完整性,并根据可用资源和服务提供商对合理元数据容量要求的判断。
元数据文件
本 PEP 中定义的信息被序列化为 pysdist.json
文件以供某些用例使用。这些文件包含 UTF-8 编码的 JSON 元数据。
每个元数据文件都包含一个序列化的映射,字段如本 PEP 中所述。在序列化元数据时,自动化工具**应该**按词法对任何键和列表元素进行排序,以便简化对任何更改的审查。
这些元数据文件预计有三个标准位置
- 作为
{distribution}-{version}.dist-info/pysdist.json
文件位于sdist
源代码发布版归档文件中 - 作为
{distribution}-{version}.dist-info/pysdist.json
文件位于wheel
二进制发布版归档文件中 - 作为
{distribution}-{version}.dist-info/pysdist.json
文件位于本地 Python 安装数据库中
预计此文件在这三个位置都相同——它是在从源代码树创建源代码归档或二进制归档文件时生成的,然后在安装时或从源代码归档文件构建二进制归档文件时保持不变。
注意
这些位置需要确认,因为它们取决于 sdist 2.0 的定义和修订的安装数据库标准。在本 PEP 批准后,还将进行 wheel 1.1 格式更新,该更新要求提供 2.0+ 元数据。
请注意,即使包含位置的版本过低而无法指示这些元数据文件有效,也**可以**处理这些元数据文件。具体来说,未版本化的 sdist
归档文件、未版本化的安装数据库目录和 wheel
规范的版本 1.0 仍然可以提供 pysdist.json
文件。
注意
在正式将此规范标记为“活跃”之前,建议遵循草稿格式的工具使用替代文件名,例如 metadata.json
或 pep426-20131213.json
,以避免与最终标准化的文件冲突。
参与 Python 发布版的其他工具也**可以**使用此格式。
请注意,这些元数据文件是由构建工具根据其他输入格式(例如 setup.py
和 pyproject.toml
)生成的,而不是直接用作数据输入格式。在发布过程中生成元数据还有助于处理特定于版本的字段(包括源 URL 和版本字段本身)。
为了与旧版安装工具向后兼容,元数据 2.0 文件**可以**与旧版元数据一起分发。
索引服务器**可以**允许上传发布版,安装工具**可以**允许仅使用旧版元数据安装发布版。
自动化工具**可以**尝试自动将旧版元数据转换为本 PEP 中描述的格式。附录 A 中提供了有效执行此操作的建议。
元数据验证
发布版元数据的 jsonschema 描述可用。
此模式**目前**不处理某些更复杂的字符串字段的验证(而是将其视为不透明字符串)。
除非另有说明,元数据中的所有 URL 字段**必须**符合RFC 3986。
注意
当前版本的模式文件涵盖了 PEP 的先前草案,尚未针对拆分为基本依赖项解析元数据和多个标准扩展进行更新,也没有针对当前草案与早期草案之间其他各种差异进行更新。
核心元数据
本节指定每个 Python 发行版所需的核心元数据字段。
发布工具**必须**确保在发布发行版时至少存在这些字段。
索引服务器**必须**确保在上传发行版时元数据中至少存在这些字段。
安装工具**必须**默认拒绝安装缺少一个或多个这些字段的发行版,但**可以**允许用户强制执行此类安装。
元数据版本
文件格式的版本;"2.0"
是唯一合法的值。
使用元数据的自动化工具**应该**在metadata_version
大于它们支持的最高版本时发出警告,并且如果metadata_version
的主版本大于它们支持的最高版本(如PEP 440中所述,主版本是第一个点之前的数值),则**必须**失败。
为了更广泛的兼容性,构建工具**可以**选择使用包含所有所需字段的最低元数据版本来生成发行版元数据。
示例
"metadata_version": "2.0"
生成器
生成文件的程序的名称(和可选版本),如果有。手动生成的文件将省略此字段。
示例
"generator": "flit"
"generator": "setuptools (34.3.1)"
名称
发行版的名称,如PEP 508中所定义。
由于发行版名称用作 URL、文件名、命令行参数的一部分,并且还必须与其他打包系统互操作,因此允许的字符受到限制,
- ASCII 字母(
[a-zA-Z]
) - ASCII 数字(
[0-9]
) - 下划线(
_
) - 连字符(
-
) - 句点(
.
)
发行版名称**必须**以 ASCII 字母或数字开头和结尾。
自动化工具**必须**拒绝不符合规范的名称。用于执行这些约束的正则表达式(在使用re.IGNORECASE
运行时)是
^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$
所有发行版名称的比较**必须**不区分大小写,并且**必须**将连字符和下划线视为等效。
索引服务器**可以**将“可混淆”字符(如 Unicode Consortium 在TR39:Unicode 安全机制中定义)视为等效。
允许从不受信任的来源进行任意发行版名称注册的索引服务器**应该**在注册新发行版时(因此将其拒绝为重复项)将可混淆字符视为等效。
集成工具**绝不**应静默地接受可混淆的替代拼写与请求的发行版名称匹配。
在撰写本文时,Unicode Consortium 指定为可混淆的 ASCII 子集中的字符是
1
(数字一)、l
(拉丁文小写字母 L)和I
(拉丁文大写字母 I)0
(数字零)和O
(拉丁文大写字母 O)
示例
"name": "ComfyChair"
版本
发行版的公共或本地版本标识符,如PEP 440中所定义。版本标识符旨在供自动化工具使用,并支持各种灵活的版本规范机制(有关详细信息,请参阅PEP 440)。
版本标识符**必须**符合PEP 440中定义的格式。
版本标识符**必须**在每个项目中都是唯一的。
索引服务器**可以**对本地版本标识符的使用施加限制,如PEP 440中所述。
示例
"version": "1.0a2"
摘要
对发行版功能的简要概述。
此字段**应该**包含少于 512 个字符,并且**必须**包含少于 2048 个字符。
此字段**不应**包含任何换行符。
更完整的描述**应该**作为发行版 sdist 中的单独文件包含在内。有关更多信息,请参阅PEP 459中的python-details
扩展。
示例
"summary": "A module that is more fiendish than soft cushions."
源代码元数据
本节指定提供用于生成此发行版的源代码的识别详细信息的字段。
所有这些字段都是可选的。如果发行版未提供这些字段,则自动化工具**必须**能够正确运行,包括在请求依赖于这些字段之一的操作时干净地失败。
源标签
源标签是具有最少定义语义的文本字符串。它们旨在允许明确识别原始源代码,即使集成者已对特定发行版应用了其他本地修改。
为了确保源标签可以轻松地作为文件名和 URL 的一部分合并,并避免十六进制哈希表示中的格式不一致,它们**必须**限于以下允许的字符集
- 小写 ASCII 字母(
[a-z]
) - ASCII 数字(
[0-9]
) - 下划线(
_
) - 连字符(
-
) - 句点(
.
) - 加号(
+
)
源标签**必须**以 ASCII 字母或数字开头和结尾。
用于增强这些约束的正则表达式(在使用re.IGNORECASE
运行时)是
^([A-Z0-9]|[A-Z0-9][A-Z0-9._-+]*[A-Z0-9])$
项目的源标签**绝不**应与该项目的任何已定义版本匹配。此限制可确保版本标识符和源标签之间不存在歧义。
示例
"source_label": "1.0.0-alpha.1"
"source_label": "1.3.7+build.11.e0f985a"
"source_label": "v1.8.1.301.ga0df26f"
"source_label": "2013.02.17.dev123"
源 URL
包含完整 URL 的字符串,可在其中下载此特定版本的发行版的源代码。
源 URL**必须**在每个项目中都是唯一的。这意味着 URL 不能像"https://github.com/pypa/pip/archive/main.zip"
那样,而必须是"https://github.com/pypa/pip/archive/1.3.1.zip"
。
源 URL**必须**引用源归档文件或在线版本控制系统中的标签或特定提交,该系统允许创建合适的 VCS 检出。它主要用于希望从原始源表单重新创建发行版的集成者。
所有源 URL 引用**应该**指定安全传输机制(例如https
)**并且**出于验证目的在 URL 中包含预期的哈希值。如果指定的源 URL 没有任何哈希信息,或者具有工具不理解的哈希信息,或者具有工具认为过于弱而不可信的选择的哈希算法,则自动化工具**应该**至少发出警告,并且**可以**拒绝依赖于该 URL。如果此类源 URL 还使用不安全的传输,则自动化工具**不应**依赖于该 URL。
对于源归档文件引用,可以通过在 URL 片段中包含<hash-algorithm>=<expected-hash>
条目来指定预期的哈希值。
截至 2017 年,**建议**使用'sha256'
哈希用于源 URL,因为此哈希尚不清楚容易受到恶意冲突生成的攻击,同时在客户端系统上也广泛可用。
对于版本控制引用,**应该**使用VCS+protocol
方案来识别版本控制系统和安全传输,并且**应该**使用具有基于哈希的提交标识符的版本控制系统。对于不提供基于哈希的提交标识符的版本控制系统,自动化工具**可以**省略有关缺少哈希的警告。
为了处理不支持直接在 URL 中包含提交或标签引用的版本控制系统,可以使用@<commit-hash>
或@<tag>#<commit-hash>
表示法将这些信息附加到 URL 的末尾。
注意
这与 pip 支持的现有 VCS 引用表示法**不完全**相同。首先,发行版名称是单独的字段,而不是嵌入为 URL 的一部分。其次,即使基于标签检索,也会包含提交哈希,以满足上述要求,即每个链接都应包含一个哈希以使伪造变得更加困难(创建具有特定标签的恶意存储库很容易,创建具有特定哈希的存储库则不那么容易)。
示例
"source_url": "https://github.com/pypa/pip/archive/1.3.1.zip#sha256=2dc6b5a470a1bde68946f263f1af1515a2574a150a30d6ce02c6ff742fcc0db8
"source_url": "git+https://github.com/pypa/pip.git@1.3.1#7921be1537eac1e97bc40179a57f0349c2aee67d"
"source_url": "git+https://github.com/pypa/pip.git@7921be1537eac1e97bc40179a57f0349c2aee67d"
语义依赖
依赖项元数据允许已发布的项目使用其他已发布项目提供的功能,而无需捆绑这些项目的特定版本的副本。
语义依赖项允许发布者不仅指示需要哪些其他项目,还指示**为什么**需要它们。此附加信息允许集成者仅安装特定活动所需的依赖项,从而更轻松地最小化受限环境中的安装占用空间(无论这些限制的原因是什么)。
默认情况下,依赖项声明假定为“运行时依赖项”:实际使用已发布版本所需的其他人版。
发行版还可以声明四种不同类型的可选依赖项
test
依赖项:运行此版本自动测试套件所需的其他人版,但仅使用它不需要(例如nose2
或pytest
)build
依赖项:从源代码构建此版本的可部署二进制版本的其他人版(例如flit
或setuptools
)doc
依赖项:构建此发行版文档所需的其他人版(例如sphinx
构建工具)dev
依赖项:在处理此发行版时所需的其他人版,但不完全属于其他可选依赖项类别中的任何一个(例如pylint
、flake8
)。dev
依赖项也被有效地视为组合的test
、build
和doc
依赖项,而无需列出三次
这些可选类别称为Extras。除了四个标准类别外,项目还可以在Extras字段中声明自己的自定义类别。
还有两个标准的额外类别暗示对其他额外内容的依赖关系
alldev
:表示包含test
、build
、doc
和dev
扩展。all
:如果未明确定义,则表示所有声明的扩展。
依赖管理严重依赖于 PEP 440 中定义的版本识别和规范方案,以及 PEP 508 中定义的依赖规范、扩展和环境标记方案。
所有这些字段都是可选的。如果发行版未提供这些字段,自动化工具**必须**能够正常运行,并假定缺少的字段表示“此发行版不适用”。
将依赖关系映射到开发和分发活动
依赖的不同类别基于上面标识的各种发行版和开发活动,并规定应为指定的活动安装哪些依赖项。
- 必需的运行时依赖项
- 无条件依赖项
- 必需的构建依赖项
build
扩展dev
扩展- 如果在构建过程中运行发行版的测试套件,还需要安装无条件依赖项和
test
扩展。
- 必需的开发和发布依赖项
- 无条件依赖项
test
扩展build
扩展doc
扩展dev
扩展
扩展(可选依赖项) 中描述的表示法**应该**用于确定为各种操作安装的确切内容。
安装工具**应该**在无法满足依赖项时报告错误,**必须**至少发出警告,并且**可以**允许用户强制继续安装。
有关将这些依赖项映射到 RPM 规范文件概述,请参阅附录 B。
额外功能
可选的依赖项集列表,可用于在依赖项字段中定义条件依赖项。有关详细信息,请参阅 扩展(可选依赖项)。
扩展名称**必须**遵守与发行版名称相同的限制。
以下扩展名称默认可用,**不得**在此字段中显式声明
all
alldev
build
dev
doc
test
示例
"extras": ["warmup", "tea"]
依赖关系
实际运行此发行版所需的发布要求列表。
公共索引服务器**可以**禁止在此字段中使用严格的版本匹配子句或直接引用。
示例
"dependencies":
{
"requires": ["SciPy", "PasteDeploy", "zope.interface > 3.5.0"]
},
{
"requires": ["pywin32 > 1.0"],
"environment": "sys_platform == 'win32'"
},
{
"requires": ["SoftCushions"],
"extra": "warmup"
}
]
虽然许多依赖项对于使用项目发布版都是必需的,但其他一些依赖项仅在特定平台上或仅在需要发布版的特定可选功能时才需要。
为了处理这种情况,发布依赖项规范符是具有以下子字段的映射
requires
:满足依赖项所需的要求列表extra
:请求并一起安装的一组可选依赖项的名称。有关详细信息,请参阅 扩展(可选依赖项)environment
:定义需要这些依赖项的环境的环境标记。环境标记的语法和功能在 PEP 508 中定义。
requires
列表中的各个条目是使用 PEP 508 中定义的依赖项声明格式的字符串,但例外情况是**不得**在各个依赖项声明中包含环境标记,而是在单独的 environment
字段中提供。
requires
是唯一必需的子字段。当它是唯一子字段时,依赖项被称为无条件依赖项。如果指定了 extra
或 environment
,则依赖项为条件依赖项。
可以提供所有三个字段,表示仅在特定环境中请求指定的扩展时才需要这些依赖项。
自动化工具**必须**将相关的依赖项规范符(具有 extra
和 environment
的公共值)组合成一个列出多个要求的规范符,以便在序列化元数据时使用。
尽管需要这种规范化,但相同的扩展名称或环境标记**可以**出现在多个条件依赖项中。例如,如果扩展本身仅在特定环境中需要其某些依赖项,则可能会发生这种情况。在依赖项规范符列表中,仅要求扩展和环境标记的组合是唯一的。
除了六个标准扩展类别之外,从依赖项规范符引用的任何扩展**必须**在此发行版的 扩展 字段中命名。这有助于避免打字错误,并且还可以轻松识别可用的扩展,而无需扫描完整的依赖项集。
为了将扩展定义重用为另一个扩展的一部分,项目发布版**可以**声明对自身的依赖项。为了避免在这些情况下出现无限递归,自动化工具**必须**将项目对自身的依赖项作为特殊情况处理。
元数据扩展
元数据的扩展**可以**以 extensions
键下的映射形式存在。键**必须**是有效的带前缀的名称,而值本身**必须**是嵌套映射。
两个键名是保留的,**不得**由扩展使用,除非如下所述
extension_version
installer_must_handle
以下示例显示了来自 PEP 459 的 python.details
和 python.commands
标准扩展。
"extensions" : {
"python.details": {
"license": "GPL version 3, excluding DRM provisions",
"keywords": [
"comfy", "chair", "cushions", "too silly", "monty python"
],
"classifiers": [
"Development Status :: 4 - Beta",
"Environment :: Console (Text Based)",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)"
],
"document_names": {
"description": "README.rst",
"license": "LICENSE.rst",
"changelog": "NEWS"
}
},
"python.commands": {
"wrap_console": [{"chair": "chair:run_cli"}],
"wrap_gui": [{"chair-gui": "chair:run_gui"}],
"prebuilt": ["reduniforms"]
},
}
扩展名称由发行版定义,然后这些发行版将以某种方式利用发布的附加元数据。
为了减少名称冲突的可能性,扩展名称**应该**使用与定义扩展含义的发行版中的模块名称相对应的前缀。此做法还有助于更轻松地查找元数据扩展的权威文档。
元数据扩展允许开发工具在元数据中记录可能在发行版的后续阶段有用的信息,但这对于依赖项解析或构建软件来说不是必需的。
扩展版本控制
扩展**必须**使用 extension_version
键进行版本控制。但是,如果省略此键,则隐含版本为 1.0
。
使用扩展元数据的自动化工具**应该**在 extension_version
大于它们支持的最高版本时发出警告,并且**必须**在 extension_version
的主版本大于它们支持的最高版本时失败(如 PEP 440 中所述,主版本是第一个点之前的数值)。
为了获得更广泛的兼容性,构建工具**可以**选择使用包含所有必需字段的最低元数据版本来生成扩展元数据。
必需扩展处理
项目可能会认为某些扩展的正确处理对于软件的正确安装至关重要。这可以通过将 installer_must_handle
字段设置为 true
来指示。将其设置为 false
或完全省略表示开发人员不认为在安装发行版时处理扩展是强制性的。
如果 installer_must_handle
对于某个扩展设置为 true
,并且工具无法处理该特定扩展(无论是直接处理还是通过工具特定的插件系统处理),则安装工具**必须**失败。
如果安装工具在尝试从轮子存档安装时遇到它不理解的必需扩展,它**可以**回退到尝试从源代码安装,而不是完全失败。
额外功能(可选依赖关系)
如 PEP 508 中所定义,扩展是启用项目发布版可选方面的其他依赖项,通常对应于代码中的 try: import optional_dependency ...
块。它们还用于指示除正常运行时使用之外的其他活动的语义依赖项(例如测试、构建或处理组件)。
为了支持在有或没有可选依赖项的情况下使用发布版,它们与发布版的核心运行时依赖项分开列出,并且必须显式请求,无论是在另一个项目的依赖项规范中,还是在向安装工具发出命令时。
具有可选依赖项的发行版的示例
"name": "ComfyChair",
"extras": ["warmup"]
"dependencies": [
{
"requires": ["SoftCushions"],
"extra": "warmup"
},
{
"requires": ["cython"],
"extra": "build"
}
]
其他发行版通过在指定依赖项时将相关的扩展名称放在发行版名称后面的方括号内来要求这些附加依赖项。可以通过放置两个扩展来请求来自依赖项的多个扩展。
如果标准 all
扩展没有显式声明的条目,则集成工具**应该**隐式地将其定义为对项目显式声明的所有扩展的依赖项。
如果标准 alldev
扩展没有显式声明的条目,则集成工具**应该**隐式地将其定义为对标准 test
、build
、doc
和 dev
扩展的依赖项。
然后,完整的依赖项要求集基于无条件依赖项以及任何请求的扩展的依赖项。
依赖项示例(仅显示 requires
子字段)
"requires": ["ComfyChair"]
-> requires ``ComfyChair`` only
"requires": ["ComfyChair[warmup]"]
-> requires ``ComfyChair`` and ``SoftCushions``
"requires": ["ComfyChair[all]"]
-> requires ``ComfyChair`` and ``SoftCushions``, but will also
pick up any new extras defined in later versions
更新元数据规范
元数据规范可以通过澄清进行更新,而无需新的 PEP 或更改元数据版本。
更改现有字段的含义或添加新功能(扩展机制除外)需要在新的 PEP 中定义新的元数据版本。
附录 A:旧元数据的转换说明
从旧版元数据转换为元数据 2.0 的参考实现是
- wheel 项目,它将
bdist_wheel
命令添加到setuptools
中 - Warehouse 项目,最终将迁移到 Python 打包机构,作为下一代 Python 包索引的实现。
- 源自于
distutils2
项目创建的核心打包基础设施的 distlib 项目
注意
这些工具尚未更新,以适应多个字段切换到标准扩展。
虽然预计在某些极端情况下可能需要手动干预才能完成干净的转换,但该规范的设计旨在允许完全自动转换 PyPI 上几乎所有项目。
元数据转换(尤其是在索引服务器方面)是必要的步骤,以便安装和分析工具能够开始受益于新的元数据格式,而无需等待开发人员升级到更新的构建系统。
附录 B:将依赖关系声明映射到 RPM SPEC 文件
例如,将此 PEP 映射到 Linux 发行版软件包,假设一个没有定义任何额外内容的示例项目在 SPEC 文件中被拆分为 2 个 RPM:example
和 example-devel
。
无条件依赖项将映射到“example”RPM 的 Requires 依赖项(从与 Linux 相关的环境标记到 SPEC 文件条件的映射也将允许正确处理这些依赖项)。
build
和 dev
额外依赖项将映射到“example”RPM 的 BuildRequires 依赖项。根据 RPM 中 %check
部分的定义方式,test
额外依赖项也可能映射到 RPM 的 BuildRequires 声明。
在 dev
、test
、build
和 doc
额外内容中定义的所有与 Linux 相关的依赖项都将成为“example-devel”RPM 的 Requires 依赖项。
像 Sphinx 这样的文档工具链依赖项要么放在 build
额外内容中(例如,如果手册页包含在构建的发行版中),要么放在 doc
额外内容中(例如,如果文档仅通过 Read the Docs 或项目网站发布)。这足以允许自动转换器将其映射到规范文件中的相应依赖项。
如果项目确实定义了任何额外内容,则可以根据依赖项规范的详细信息将其映射到具有相应 BuildRequires 和 Requires 条目的其他虚拟 RPM。或者,可以将其映射到其他系统软件包管理器功能(例如弱依赖项)。
元数据扩展格式还应提供一种方法,以便在不需在特定于发行版的格式中手动复制任何上游元数据的情况下,将特定于发行版的提示包含在上游项目元数据中。
附录 C:与 PEP 345 的差异总结
- Metadata-Version 现在是 2.0,并指定了处理版本更改的语义。
- 越来越复杂的临时“键:值”格式已被更结构化的 JSON 兼容格式取代,该格式可以轻松地表示为 Python 字典、字符串、列表。
- 大多数字段现在都是可选的,并且明确禁止为省略的字段填充虚拟数据。
- 明确允许进行就地澄清,而无需发布规范的新版本。
- PEP 现在尝试更多地解释字段存在的原因以及它们的使用目的,而不是简单地描述允许的内容。
- 将版本方案更改为基于 PEP 440 而不是 PEP 386。
- 添加了 PEP 440 中描述的源标签机制。
- 在 PEP 508 中正式定义了依赖项声明、额外内容和环境标记。
- 通过其他保留的额外名称支持不同类型的依赖项。
- 更新了过时机制。
- 一个定义明确的元数据扩展机制,以及将任何不需要进行依赖项解析的字段迁移到标准扩展。
- 对查尔斯·舒尔茨和花生漫画表示敬意,许多示例已更新为在主题上更适合 Python;)
主要更改的基本原理在以下部分中给出。
Metadata-Version 语义
主要版本和次要版本增量的语义现在已指定,并遵循与 PEP 427 中为 wheel 格式指定的格式版本语义相同的模型:次要版本增量在由仅理解具有相同主要版本的早期元数据版本的工具处理时必须表现合理,而主要版本增量可能包含与现有工具不兼容的更改。
规范的主要版本号已相应递增,因为解释 PEP 426 元数据显然无法根据早期元数据规范进行解释。
每当规范的主要版本号递增时,预计部署将需要一些时间,因为要么必须更新元数据使用工具才能使其他工具安全地开始生成新格式,要么必须更新 sdist 和 wheel 格式以及安装数据库定义以支持并行提供多个版本的元数据。
现有的工具在更新为支持新的元数据标准之前不会遵守此准则,因此新的语义将首先对假设的 2.x -> 3.0 过渡生效。对于 1.x -> 2.x 过渡,我们将使用一种方法,即工具继续生成现有的补充文件(例如 entry_points.txt
),以及使用标准元数据格式的新功能(包括正式扩展机制)指定的任何等效文件。
切换到 JSON 兼容格式
旧的“键:值”格式变得越来越受限,存在各种复杂性,例如解析器需要知道哪些字段允许出现多次,哪些字段支持环境标记语法(可选的 ";"
用于分隔值和标记)以及最终甚至是在特定子字段中嵌入任意 JSON 的选项。
旧的序列化格式也不适合轻松转换为标准 Python 数据结构,以便在任何新的安装钩子 API 中使用,或者在将来扩展运行时导入程序 API 以便它们提供信息以包含在安装数据库中。
因此,我们已采取措施切换到 JSON 兼容的元数据格式。这更适合 API,并且工具更容易正确解析和生成。更改元数据文件的名称还可以轻松并行分发 1.x 和 2.x 元数据,从而简化迁移到新元数据格式的多个方面。
选择 pydist.json
作为首选文件名,是因为这些文件中描述的元数据适用于整个发行版,而不是任何特定构建。将来可能会定义其他元数据格式以保存仅在为特定目标环境构建二进制发行版后才能确定的信息。
更改版本方案
有关对版本控制方案所做的各种更改的详细基本原理,请参阅 PEP 440。
源标签
新的源标签支持旨在更清楚地表明对公共版本标识符的约束主要在于帮助创建可靠的自动化依赖项分析工具。项目可以自由地使用任何他们喜欢的内部版本控制方案,只要他们能够将其转换为依赖项分析工具可以理解的内容即可。
源标签还可以轻松记录版本的具体细节,例如哈希或标签名称,这些细节允许从项目版本控制系统重建发行版。
支持分发的可选依赖关系
新的额外内容系统允许发行版声明可选行为,并使用依赖项字段指示何时仅需要特定依赖项来支持该行为。它源自等效系统,该系统已作为 setuptools
的一部分被广泛使用,并允许在新元数据格式中准确表示旧版 setuptools
元数据的这一方面。
相对于 setuptools 的额外内容语法的添加旨在更轻松地表达各种可能的依赖项组合,特别是与构建系统(可选地支持运行测试套件)和开发系统相关的依赖项组合。
支持不同类型的语义依赖关系
通过额外内容系统将五种不同类型的依赖项分开,允许项目选择性地指示是否需要特定依赖项来开发、构建、测试或使用发行版。
在上游 Python 特定元数据中支持这些区别的优势在于,即使项目本身不关心这些区别,它们也可能更容易接受来自下游重新分发者的修补程序,这些修补程序适当地分隔字段。随着时间的推移,这应该允许对特定依赖项在何处以及何时安装有更大的控制权。
支持元数据扩展
新的扩展实际上允许将元数据命名空间的部分委托给其他项目,同时保留标准的整体格式元数据格式,以便于不支持特定扩展的发行版工具进行处理。
它也与新的 build
额外内容一起很好地工作,允许发行版依赖于确实知道如何处理所选扩展的工具,以及通常的新额外内容机制,允许将对特定扩展的支持作为可选功能提供。
扩展的未来用途包括声明其他项目的插件以及自动转换为 Linux 系统软件包的提示。
声明扩展为必需的功能主要包含在内,以便允许将元数据钩子扩展的定义推迟到元数据 2.0 规范最初采用后的某个时间。如果发行版需要运行 postinstall
钩子才能成功完成安装,则早期版本的工具应回退到从源代码安装,而不是从 wheel 文件安装,然后未能运行预期的 postinstall 钩子。
附录 D:延迟功能
为了更好地优先考虑我们迁移到新的元数据标准的努力,一些潜在的有用功能已被故意推迟。这些都反映了在新元数据中可能需要的信息,但可以通过元数据扩展或在元数据 2.1 中轻松添加,而不会破坏元数据 2.0 已支持的任何用例。
一旦 pypi
、setuptools
、pip
、wheel
和 distlib
项目支持创建和使用元数据 2.0,那么我们可能会重新审视使用部分或所有这些附加功能创建元数据 2.1。
标准扩展
旧元数据系统提供的一些信息已移至 PEP 459 中定义的标准扩展。
这允许在更易于使用的格式中发布核心依赖项元数据,即使在这些扩展的完整细节得到解决之前。
改进项目过时、重命名和合并的处理
此 PEP 的早期草案包含新的 Provides
和 Obsoleted-By
字段,用于更强大的自动化通知和项目过时、重命名和合并的跟踪。
这不是依赖项管理系统必不可少的功能,并且已被无限期推迟作为未来可能的元数据扩展。
MIME 类型注册
在 PEP 接受后,我们可能会向 IANA 提交以下 MIME 类型注册请求
application/vnd.python.pydist+json
我们甚至可能能够在 PSF 的旗帜下仅注册 vnd.python
命名空间,而无需注册各个子格式。
环境标记中的字符串方法
在环境标记中支持至少“.startswith”和“.endswith”字符串方法将允许更自然地编写某些条件。例如,"sys.platform.startswith('win')"
是一种标记 Windows 特定依赖项的更直观的方式,因为 "'win' in sys.platform"
由于 cygwin
而不正确,并且 64 位 Windows 仍然显示为 win32
这一点有点奇怪。
附录 E:已拒绝的功能
以下功能已被明确考虑并拒绝,因为引入的额外复杂性过多,而表达能力的提升却很小。
分别列出条件和无条件依赖关系
此 PEP 的早期版本使用单独的列表来表示条件依赖项和无条件依赖项。事实证明,在自动化工具中处理这一点很麻烦,并且删除它也使 PEP 和元数据模式大大缩短,这表明它实际上也更难解释。
分别列出语义依赖关系
此 PEP 的早期版本使用单独的字段而不是 extras 系统来表示测试、构建、文档和开发依赖项。事实证明,在自动化工具中处理这一点很麻烦,并且删除它也使 PEP 和元数据模式大大缩短,这表明它实际上也更难解释。
对过于精确的依赖关系声明引入摩擦
此 PEP 的早期版本试图在发布版本中不适当地使用过于严格的依赖项声明时引入摩擦。distutils-sig 上的讨论得出结论,这不是一个需要在互操作性规范层直接解决的严重问题,如果它将来确实成为一个问题,最好在将项目上传到公共 Python 包索引时解决。
不允许在分发名称中使用下划线
Debian 实际上不允许在名称中使用下划线,但鉴于使用有效的 Python 标识符作为 Python 发行版名称的常见做法,对于此规范来说,这似乎过于严格。Debian 端将下划线转换为连字符的策略似乎很容易实现(并且需要将连字符和下划线视为等效的条件确保这样做不会引入任何名称冲突)。
允许在分发名称中使用 Unicode
此 PEP 故意避免遵循 Python 3 走向任意 Unicode 标识符的道路,因为这样做在软件分发用例中的安全隐患要严重得多(它打开了比仅仅代码混淆更有趣的攻击向量)。
此外,现有的工具只有在将名称限制为 ASCII 时才能正常工作,而更改这一点将需要对链中所有自动化工具进行大量工作。
在将来的某个(遥远)时间重新审视这个问题可能是合理的,但在设置更可靠的软件分发系统时,在混合中添加更通用的 Unicode 标识符支持已经足够具有挑战性了。
依赖于源标签
没有机制来表达对源标签的依赖关系 - 它们仅包含在元数据中用于内部项目引用。相反,必须根据公共版本或直接 URL 引用来表达依赖关系。
替代依赖关系
此 PEP 的早期草案考虑允许在依赖项规范中使用列表代替通常的字符串,以表明有多种方法可以满足依赖项。
如果至少一个单独的依赖项已经可用,则整个依赖项将被视为已满足,否则第一个条目将添加到依赖项集中。
替代依赖项规范示例
["Pillow", "PIL"]
["mysql", "psycopg2 >= 4", "sqlite3"]
但是,这两个给定的示例都没有特别引人注目,因为 Pillow/PIL 风格的分支并不常见,并且数据库驱动程序用例可以说最好由 SQL Alchemy 定义的“受支持的数据库驱动程序”元数据扩展来提供服务,其中一个项目依赖于 SQL Alchemy,然后在扩展中声明上游项目检查哪些数据库驱动程序的兼容性。
环境标记中的兼容版本比较
PEP 440 定义了用于版本比较的丰富语法,这在环境标记中与 python_version
和 python_full_version
结合使用时可能很有用。但是,允许使用完整语法意味着环境标记不再是 Python 子集,而仅允许某些比较将引入另一个需要处理的特殊情况。
鉴于环境标记仅在元数据结构隐含更高层次“或”的情况下使用,因此对于很少需要这种情况的案例,要求使用针对特定 Python 版本的多个比较似乎更容易。
条件提供
在修订后的元数据设计中,基于运行时功能或环境的条件“provides”将位于单独的“may_provide”字段中。但是,目前尚不清楚这样做有任何用例,因此该想法被拒绝,除非有人能够提出一个令人信服的用例(即使那样,该想法也至少要到元数据 2.1 才会重新考虑)。
参考文献
本文档指定了元数据格式的 2.0 版。1.0 版在 PEP 241 中指定。1.1 版在 PEP 314 中指定。1.2 版在 PEP 345 中指定。
标准化版本方案的初始尝试,以及需要此类标准的理由,可以在 PEP 386 中找到。
版权
本文档已放置在公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0426.rst
上次修改时间:2024-04-14 20:08:31 GMT