PEP 792 – 简单索引中的项目状态标记
- 作者:
- William Woodruff <william at yossarian.net>, Facundo Tuesca <facundo.tuesca at trailofbits.com>
- 发起人:
- Donald Stufft <donald at stufft.io>
- PEP 代理人:
- Donald Stufft <donald at stufft.io>
- 讨论至:
- Discourse 帖子
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 主题:
- 打包
- 创建日期:
- 2025年5月21日
- 发布历史:
- 2025年2月3日, 2025年6月9日
- 决议:
- 2025年7月8日
摘要
本 PEP 提出了一套标准化的索引提供的项目状态标记,以及在 HTML 和 JSON 简单索引中传达这些标记的机制。
原理与动机
项目的“状态”是一项重要的元数据,随着 Python 打包生态系统规模和复杂性的增长,其重要性也随之增加。了解项目状态(或最近活动等代理信息)对于确定项目是否得到维护或是否适合使用非常有用。
Python 打包至少有三种不同的机制来传达项目的“状态”:
- 分发包可以在其元数据中包含 Trove 分类器,最初在 PEP 301 中指定。支持的分类器列表由 PyPA 维护,其中包括
Development Status
层次结构。例如,一个分发包可以包含Development Status :: 7 - Inactive
分类器,以表示该分发包的项目处于非活跃状态。Trove 分类器很灵活,但也存在明显的局限性:它们是机器可读的,并在 PyPI 等索引上渲染,但它们也要求维护者每次希望更新其项目的开发状态时,都要推送一个或多个新的分发。此外,由于分发在 Python 打包生态系统中是事实上的不可变的,旧的分发无法更新其分类器以反映项目的当前状态。
- 索引可以将分发和发布标记为“已下架”,最初在 PEP 592 中指定。已下架的分发不被认为是符合依赖解析条件的。
当一个分发被下架时,它在 HTML 索引中被标记为
data-yanked
,在 JSON 索引中被标记为yanked: bool | str
。此外,像 PyPI 这样的索引默认会隐藏已下架的分发,并且当用户直接导航到它们时,会以通知的形式渲染它们。下架像 Trove 分类器一样是机器可读的,但它是单一用途而不是通用用途的:用户可以为下架给定的分发包指定自由文本的原因,但下架的语义是固定的,并且机器无法根据该自由文本原因对项目状态进行可靠的推断。
- PyPI 本身有项目状态,适用于整个项目(即所有发布和分发)。项目状态具有维护者和索引管理员可控的状态:
- PyPI 管理员可以“隔离”一个项目。隔离的行为类似于加强的下架:整个项目在隔离期间仍无法安装,并且只有管理员才能解除隔离。
- 项目所有者可以“存档”一个项目。存档项目会禁用对该项目的新发布和分发上传,但除此之外,对下载项目的能力没有影响。
项目状态原则上是机器可读的,但目前未通过 PyPI 的任何 API 公开。相反,PyPI 在每个项目的用户界面(即非索引)网页上渲染项目状态。
总而言之,在 Python 打包中有多种方式来传达项目的“状态”。然而,它们都不能满足我们期望的四个特征。目前没有一个项目状态指标是机器可读的、通用的(即传达不止一种可能的状态)、与索引无关的,并且适用于整个项目,而不是针对每个发布或每个分发。
机制 | 机器可读 | 通用 | 与索引无关 | 项目范围 |
---|---|---|---|---|
Trove 分类器 | ✅ | ✅ | ✅ | ❌ |
下架 | ✅ | ❌ | ✅ | ✅ |
PyPI 项目状态 | ✅ | ✅ | ❌ | ✅ |
本 PEP 提议采用 PyPI 的项目状态作为与索引无关的机制,以满足所有四个条件。
规范
本 PEP 规定了两个方面:一套项目状态标记,以及它们在标准 HTML 和 JSON 索引中的呈现方式。
项目状态标记
本 PEP 提议以下项目状态标记。
一个项目始终只有一个状态。如果没有明确指明状态,则该项目被视为处于 active
状态。
索引 可以 根据其需求实现本 PEP 中指定的任何状态标记子集。
本 PEP 不规定 哪些 主体(即项目维护者、索引管理员等)被允许设置和取消设置哪些状态。
活跃
描述:项目处于活跃状态。这是项目的默认状态。
索引语义
- 托管项目的索引 必须 允许上传新的分发到该项目。
- 索引 必须 提供该项目现有的分发供下载。
安装程序语义:无。
已存档
描述:该项目预计未来不会再更新。
索引语义
- 托管项目的索引 不得 允许上传新的分发到该项目。
- 索引 必须 提供该项目现有的分发供下载。
安装程序语义
- 安装程序 可以 对项目的存档发出警告。
已隔离
描述:该项目被认为通常不安全,例如由于恶意软件。
索引语义
- 托管项目的索引 不得 允许上传新的分发到该项目。
- 索引 不得 提供该项目的任何分发供下载。
安装程序语义
- 安装程序 可以 对项目的隔离发出警告,尽管这样做实际上是多余的(因为索引不会提供任何分发进行安装)。
已弃用
描述:该项目被认为是过时的,并且可能已被另一个项目取代。
索引语义
- 此状态与
active
具有相同的语义。
安装程序语义
- 安装程序 可以 对项目的弃用发出警告。
索引 API 中的状态标记
本 PEP 定义了索引 API 的版本 1.4。
下面对 HTML 和 JSON 简单索引的所有更改都发生在项目级别,即在每个项目的索引响应中,而不是根索引响应中。本 PEP 没有提出任何根索引响应的更改。
HTML 索引
以下更改适用于简单存储库 API
- 每个项目的索引 必须 将
pypi:repository-version
定义为1.4
。 - 每个项目的索引 应该 添加一个适当的
pypi:project-status
元标签,其content
为项目的状态标记。如果项目被标记为active
,索引 可以 选择省略pypi:project-status
元标签。 - 每个项目的索引 可以 包含一个
pypi:project-status-reason
元标签,其content
为自由格式文本,用于说明项目的状态。如果项目被标记为active
或未提供理由,索引 可以 选择省略pypi:project-status-reason
元标签。
例如,当 sampleproject
被标记为 quarantined
后,以下是一个有效的 HTML 索引响应:
<!DOCTYPE html>
<html>
<head>
<meta name="pypi:repository-version" content="1.4">
<meta name="pypi:project-status" content="quarantined">
<meta name="pypi:project-status-reason" content="the project is haunted">
<title>Links for sampleproject</title>
</head>
<body>
<h1>Links for sampleproject</h1>
</body>
</html>
请注意,根据上述 quarantined
语义,索引响应不包含该项目的任何分发链接。
JSON 索引
以下更改适用于JSON 简单索引
- 每个项目的索引 必须 将
meta.api-version
定义为1.4
。 - 每个项目的索引 应该 在 JSON 响应中包含一个
project-status.state
键,其值为项目状态标记。如果项目被标记为active
,索引 可以 选择省略project-status.state
键。 - 每个项目的索引 可以 在 JSON 响应中包含一个
project-status.reason
键,其值为自由格式文本,用于说明项目的状态。如果项目被标记为active
或未提供理由,索引 可以 选择省略project-status.reason
键。
例如,当 sampleproject
被标记为 quarantined
后,以下是一个有效的 JSON 索引响应:
{
"meta": {
"api-version": "1.4"
},
"project-status": {
"status": "quarantined",
"reason": "the project is haunted"
},
"alternate-locations": [],
"files": [],
"name": "sampleproject",
"versions": [
"1.2.0",
"1.3.0",
"1.3.1",
"2.0.0",
"3.0.0",
"4.0.0"
]
}
请注意,与 HTML 索引一样,JSON 响应不包含 quarantined
项目的任何分发链接。
未来考量
本 PEP 只定义了四个项目状态标记:active
、archived
、quarantined
和 deprecated
。
未来的 PEP(或 PyPA 标准流程)可能会根据需要定义额外的项目状态标记。任何未来的状态标记可能需要元数据版本升级,除非未来的元数据更改允许“开放式”状态标记(即索引和安装程序不一定共享一个共同的允许状态列表)。
如本 PEP 所述,项目状态标记是“裸露的”,即它们不传达额外的用户控制元数据(例如项目存档的解释)。
未来的 PEP 可能会选择扩展项目状态机制,以包含用户控制的元数据,其方式类似于发布下架时允许的自由格式文本。
安全隐患
本 PEP 未发现与添加项目状态标记相关的任何积极或消极安全影响。
如何教授此内容
向 Python 社区宣传本 PEP 有两个方面:
- 普通的包维护者需要被告知他们设置项目状态标记的能力,例如通知其下游项目已被存档或弃用。
如果本 PEP 被接受,本 PEP 的作者将与 PyPI 协调,制定适当的面向维护者的文档和沟通,包括功能发布博客文章和对 PyPI 用户文档的更新。
- 安装程序和索引维护者需要了解新的项目状态标记以及如何解释它们。
如果本 PEP 被接受,本 PEP 的作者将在 PyPI 上进行实现,作为其他索引的参考实现。
本 PEP 不强制更改安装程序行为。但是,如果本 PEP 被接受,本 PEP 的作者将与流行安装程序(例如
pip
)的维护者协调,帮助他们确定希望在多大程度上展示项目状态。
被拒绝的想法
使用“保留”键
本 PEP 的一个替代方案是避免直接标准化项目状态标记,而是利用标准中现有的机制以非标准方式传达它们。
例如,JSON 简单索引中指出:
带有前导下划线的键(在任何级别)被保留为索引服务器专用。未来的标准不会为任何此类键分配含义。
实际上,这意味着以下内容将符合标准:
{
"meta": {
"api-version": "1.4"
},
"_project-status": "quarantined",
"alternate-locations": [],
"files": [],
"name": "sampleproject",
"versions": [
"1.2.0",
"1.3.0",
"1.3.1",
"2.0.0",
"3.0.0",
"4.0.0"
]
}
然而,这种方法有几个缺点:
- 符合标准的工具(例如
pip
、pip-audit
和uv
)可能会发现使用“保留”键是不可接受的,因为该键没有标准语义或兼容性属性。 - “保留”方法仅适用于 JSON 简单索引;HTML 简单索引没有等效机制。这将不利于 HTML 简单索引的消费者,以及可能消费 JSON 索引但只暴露 HTML 索引的镜像实现。
PyPI 非标准 JSON API 中的项目标记
另一种避免标准化的替代方案是暴露项目状态标记,但仅限于 PyPI 的非标准 JSON API。PyPI 对此 API 的布局拥有完全控制权,可以包含 project-status
或类似的键,而无需 PEP 或下划线前缀。
这与上述“保留”键方法有类似的缺点,并且更普遍地加深了标准和非标准 API 之间的差异。
同时使用多个项目状态标记
本 PEP 的早期版本曾考虑支持同时使用多个项目标记。例如,一个项目可以同时被标记为 archived
和 quarantined
。
经考虑,由于复杂性原因,这一提议被拒绝:拥有多个项目状态标记要求 PEP 指定合并其语义时的冲突解决机制,以及哪些标记是互斥的状态机(例如,active
在概念上与所有其他标记互斥,而 archived
和 quarantined
在概念上是兼容的)。
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源:https://github.com/python/peps/blob/main/peps/pep-0792.rst