PEP 714 – 在Simple API中重命名dist-info-metadata
- 作者:
- Donald Stufft <donald at stufft.io>
- PEP 代理人:
- Paul Moore <p.f.moore at gmail.com>
- 讨论至:
- Discourse 帖子
- 状态:
- 已接受
- 类型:
- 标准跟踪
- 主题:
- 打包
- 创建日期:
- 2023年6月6日
- 发布历史:
- 2023年6月6日
- 决议:
- 2023年6月27日
摘要
本PEP重命名了 PEP 658 在Simple API的HTML和JSON格式中提供的元数据,并为客户端和服务器如何处理重命名提供了指导。
动机
PEP 658 规定了一种机制,用于通过Simple API托管工件的核心元数据文件,以便客户端可以获取元数据并在不下载整个工件的情况下使用它。后来编写了 PEP 691,以增加在Simple API上使用JSON而非HTML的功能,其中包括对 PEP 658 元数据的支持。
不幸的是,PyPI直到 最近 才支持 PEP 658,发布的版本中包含一个 bug,其中 PEP 658 中的 dist-info-metadata 键在JSON表示中被错误地命名为 data-dist-info-metadata。然而,在尝试修复该bug时,发现pip 也 有一个bug,即JSON表示中任何使用 dist-info-metadata 的情况都会导致pip因异常而硬性失败。
pip中的这个bug至少从 v22.3 版本开始就存在了,这意味着它已经发布了大约8个月,足够长时间被纳入Python版本、下游Linux版本、集成到容器、虚拟环境等中。
这使我们陷入了一个尴尬的境地:PyPI上存在一个由于pip中的bug而无法在不破坏pip的情况下修复的bug,但pip的该版本已经广泛部署。更糟糕的是,一旦PyPI修复了它的bug,以这种方式损坏的pip版本将无法从PyPI安装 任何 东西,包括安装新的、已修复的pip版本。
基本原理
修复这些bug有3个主要选择
- 不修改规范,修复pip中的bug,等待一段时间,然后修复PyPI中的bug,这会使得任何使用未修复的pip的人无法从PyPI安装新的pip。
- 与 (1) 相同,但特殊处理PyPI,使其即使在可用时也不为pip发出 PEP 658 元数据。这允许用户在版本损坏时升级pip,但不能做其他事情。
- 修改规范以避免pip目前无法处理的键,允许PyPI发出该键,并发布新版本的pip以利用该键。
本PEP选择了 (3),但更进一步,同时重命名了HTML表示中的键。
通常我们不会因为仅影响特定实现的bug而更改规范,除非规范本身存在问题,但此处并非如此:规范没有问题,这些只是pip和PyPI中的真实bug。
然而,我们选择这样做有4个原因
- 同时影响pip和PyPI的bug,与任何其他客户端或仓库组合相比,造成了巨大的影响。
- 损坏的影响是安装完全无法工作,而不是以某种方式优雅地降级。
- 这些bug所阻碍的功能对于使用pip快速高效地从PyPI解析依赖关系至关重要,而不得不长时间延迟它,等待损坏的pip版本淘汰,将对整个生态系统造成损害。
- 更改规范的缺点相当有限,因为我们不认为这种支持是广泛的,因此它只影响有限数量的项目。
规范
本文档中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“建议”、“不建议”、“推荐”、“可以”和“可选”应按照 RFC 2119 中的描述进行解释。
服务器
当 PEP 658 元数据在Simple API的HTML表示中使用时,必须 使用属性名 data-core-metadata 发出,支持的值保持不变。
当 PEP 658 元数据在 PEP 691 Simple API的JSON表示中使用时,必须 使用键 core-metadata 发出,支持的值保持不变。
为了支持使用旧键名的客户端,HTML表示 可以 也使用 data-dist-info-metadata 发出,如果这样做,它 必须 与 data-core-metadata 的值匹配。
客户端
消费任何Simple API的HTML表示的客户端,如果存在 data-core-metadata,则 必须 从键 data-core-metadata 读取 PEP 658 元数据。如果存在旧的 data-dist-info-metadata 但不存在 data-core-metadata,它们 可以 选择使用它。
消费Simple API的JSON表示的客户端,如果存在 core-metadata,则 必须 从键 core-metadata 读取 PEP 658 元数据。如果存在旧的 dist-info-metadata 键但不存在 core-metadata,它们 可以 选择使用它。
向后兼容性
本PEP存在一个轻微的兼容性问题,即目前正确处理现有元数据键的客户端不会自动理解新的元数据键,但它们应该优雅地降级,并简单地表现为 PEP 658 元数据不存在。
除此之外,本PEP应该没有兼容性问题。
被拒绝的想法
保持规范不变,并尝试在PyPI和/或pip中进行修复
我们相信 PEP 658 带来的改进对于提高从PyPI解析依赖项的性能非常重要,并希望能够尽快部署它。
不幸的是,这些bug的性质决定了我们无法原样部署它们,否则会破坏广泛部署和使用的pip版本。在这种情况下,破坏将非常严重,受影响的用户甚至无法直接升级其pip版本来修复它,而必须首先手动通过其他方式获取pip(例如 get-pip.py)。
这是PyPI在没有某种方式来缓解这些用户所面临的破坏的情况下不愿做的事情。如果没有合理的缓解策略,我们将不得不等到那些pip版本不再在PyPI上使用,这可能需要5年或更长时间。
我们可以使用几种可能的缓解策略,但我们也拒绝了它们。
缓解措施:特殊处理pip
这种破坏特别严重,因为它阻止用户甚至升级pip以获取未损坏的pip版本,因此像 pip install --upgrade pip 这样的命令会失败。我们可以通过让PyPI特殊处理pip本身来缓解这个问题,这样JSON端点永远不会返回 PEP 658 元数据,并且上述操作仍然有效。
本PEP拒绝了这个想法,因为虽然只升级pip的简单命令会起作用,但如果用户在该命令中包含 任何 其他要升级的内容,则该命令将再次失败,我们认为这仍然是太大的破坏。
此外,尽管这个bug恰好现在在PyPI上暴露出来,但它实际上是任何正确暴露 PEP 658 元数据的 PEP 691 仓库都会发生的bug。这意味着每个仓库都必须为pip进行这种特殊处理。
缓解措施:让服务器使用User-Agent检测
pip将其版本号放入其 User-Agent 中,这意味着服务器可以检测版本号并根据该版本号提供不同的响应,这样我们就不会向损坏的pip版本提供 PEP 658 元数据。
本PEP拒绝了这个想法,因为以合理的方式实现 User-Agent 检测太困难了。
- 在PyPI上,我们严重依赖CDN中的Simple API缓存。如果根据
User-Agent改变响应,我们的CDN缓存将为相同的内容产生大量缓存键,这会使任何特定请求更有可能未被缓存并回退到我们的后端服务器,这将需要更高的扩展性来支持负载。 - PyPI 可以 通过修改请求的
Accept头来支持User-Agent检测,这样这些版本就似乎只接受HTML版本,从而使我们能够维护CDN的缓存键。但这不会影响PyPI的任何下游缓存,包括pip的HTTP缓存,它可能会为这些请求缓存JSON版本,而且我们不会在User-Agent上发出Vary,让他们知道共享这些缓存是不可接受的,为下游缓存添加Vary: User-Agent会出现与 (1) 相同的问题,但影响的是下游缓存而不是我们的CDN缓存。 - pip中的bug最终不是PyPI特有的,它影响任何同时实现 PEP 691 和 PEP 658 的仓库。这意味着依赖于特定于实现的修复的变通方法必须为实现这两者的每个仓库复制,这在所有情况下可能不容易或不可能(例如,静态镜像可能无法进行
User-Agent检测)。
只修改JSON键
pip中的bug仅影响Simple API的JSON表示,所以我们只 需要 实际更改JSON中的键,我们可以保留现有的HTML键不动。
本PEP拒绝这样做,因为我们认为从长远来看,HTML和JSON键名不一致会使此类错误更有可能发生,并使实现和理解规范更加混乱。
我们不想更改HTML键的主要原因是,为了避免在任何可能已经支持它的仅HTML客户端或仓库中失去对 PEP 658 的支持。本PEP通过允许客户端和服务器继续支持这两个键,并提供了何时以及如何这样做的建议,从而减轻了这种破坏。
建议
本节中的建议,除了本通知本身,都是非规范性的,代表了PEP作者认为实现本PEP的最佳默认实现决策,但它不代表任何与这些决策匹配的要求。
服务器
我们建议服务器 只 发出较新的键,特别是对于Simple API的JSON表示,因为bug本身只影响JSON。
希望在客户端中使用HTML并已实现 PEP 658 的服务器,可以安全地 只 在HTML中发出这两个键。
除非服务器知道没有损坏的pip版本会用于访问它们的服务器,否则不应在JSON中发出旧的键。
客户端
我们建议客户端支持HTML和JSON的两个键,并优先使用较新的键,正如本PEP所要求的那样。这将使客户端能够支持已经正确实现 PEP 658 和 PEP 691 但尚未实现本PEP的仓库。
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源: https://github.com/python/peps/blob/main/peps/pep-0714.rst
最后修改: 2025-02-01 08:55:40 GMT