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