PEP 2026 – Python 的日历版本控制
- 作者:
- Hugo van Kemenade
- 讨论至:
- Discourse 帖子
- 状态:
- 已拒绝
- 类型:
- 流程
- 创建日期:
- 2024 年 6 月 11 日
- Python 版本:
- 3.26
- 发布历史:
- 2024 年 6 月 14 日
- 决议:
- Discourse 消息
摘要
此 PEP 提议更新 Python 的版本控制方案,以包含日历年份。
日历版本控制 (CalVer) 让*一切*都更容易转化为日历时间,而不是去计算版本并查找它们何时将(或已经)发布。
- 支持生命周期清晰,易于查看版本首次发布的时间。
- 弃用项对维护者和用户来说更容易管理。
- 更容易计算出版本何时将达到生命周期结束 (EOL)。
- 它有助于人们,尤其是新学习者,了解他们的安装有多旧。
- 更容易推断出哪些 Python 版本应该被库和应用程序支持。
从 Python 3.15(原本的版本号)开始,版本将是 3.YY.micro,其中 YY 是首次发布的年份。
- Python 3.26 将于 2026 年发布,而不是 Python 3.15。EOL 是自首次发布之日起五年,因此 Python 3.26 将于 2031 年达到 EOL。
- Python 3.27 将于 2027 年发布,以此类推。
动机和理由
2019 年,我们采用了年度发布周期,参考 PEP 602,这为日历版本控制打开了大门。
采用年度发布日历允许自然切换到日历版本控制,例如将 Python 3.9 称为“Python 3.20”,因为它是在 20 年 10 月发布的,以此类推(“Python 3.23” 将是 23 年 10 月发布的那个)。虽然切换到日历版本控制的便利性可以被视为年度发布周期的优势,但此 PEP 并不主张更改 Python 的版本控制方式。如果采用年度发布周期,版本控制问题将在单独的 PEP 中处理。
这就是那个 PEP。
当前方案
来自 Python 常见问题解答:Python 版本编号方案是如何工作的?
Python 版本号为“A.B.C”或“A.B”。
- A 是主版本号——仅当语言发生真正重大的更改时才会递增。
- B 是次版本号——当发生不太“惊天动地”的更改时递增。
- C 是微版本号——每次错误修复版本发布时递增。
Python 早于 SemVer
语义化版本控制 (SemVer) 是一种流行的方案,旨在传达发布的意图(尽管它并不总是成功)。
给定版本号 MAJOR.MINOR.PATCH,在进行不兼容的 API 更改时增加
- MAJOR 版本
- 在向后兼容的方式中添加功能时增加
- MINOR 版本
人们经常假设 Python 遵循 SemVer,并抱怨 在 功能 发布中的破坏性更改。但是 Python 比 SemVer 早至少 15 年:SemVer 规范于 2009 年引入,而 Python 的定制方案在 1994 年就添加到源代码控制中,用于 1.0 版本发布。
如果 Python 采用 SemVer,那么每年移除弃用项时都会导致主版本号递增。
然而,一些项目没有采用 SemVer,而是采用了另一种基于日历的版本控制方案。
日历版本控制
通过日历版本控制 (CalVer),您将日期的某个元素包含在版本号中。例如,Ubuntu 和 Black 使用年份和月份——Ubuntu 24.04 发布于 2024 年 4 月;pip 和 PyCharm 只使用年份。
Ubuntu | Black | pip | PyCharm |
---|---|---|---|
YY.0M.micro | YY.MM.micro | YY.minor.micro | YYYY.minor.micro |
23.04
23.10
24.04
24.10
|
23.12.1
24.1.0
24.1.1
24.2.0
|
23.3
23.3.1
23.3.2
24.0
|
2023.3.5
2024.1
2024.1.1
2024.1.2
|
以下是一些编程语言标准,它们都使用某种形式的年份。
Ada | Algol | C | C++ | Fortran | ECMAScript
又名 JavaScript
|
---|---|---|---|---|---|
YY / YYYY | YY | YY | YY | YY / YYYY | YYYY |
83
95
2012
2022
|
58
60
68
|
89
99
11
23
|
98
03
11
23
|
66
90
2003
2023
|
2020
2021
2022
2023
|
年度发布节奏
自 2019 年以来,我们每年都有一次发布。
- 3.15.0 将于 2026 年发布。
- 3.16.0 将于 2027 年发布。
- 3.17.0 将于 2028 年发布。
- 3.18.0 将于 2029 年发布。
- 3.19.0 将于 2030 年发布。
这在某种程度上是基于日历的,只是它偏移了 11 年。
Python 的 CalVer
最简单的 CalVer 选项是坚持主版本号 3,并将年份编码在次版本号中。
- 3.26.0 将于 2026 年发布。
- 3.27.0 将于 2027 年发布。
- 3.28.0 将于 2028 年发布。
- 3.29.0 将于 2029 年发布。
- 3.30.0 将于 2030 年发布。
例如,3.26 将于 2026 年发布。这很容易看出发布时间。
弃用移除的清晰度
弃用警告通常会提及它们将被移除的版本。例如:
DeprecationWarning: 'ctypes.SetPointerType' is deprecated and slated for removal in Python 3.15
然而,一旦了解 CalVer,警告会立即清晰地显示您有多少时间来采取行动。
DeprecationWarning: 'ctypes.SetPointerType' is deprecated and slated for removal in Python 3.26
支持生命周期的清晰度
目前,要计算出版本的生命周期结束时间有点棘手。首先需要查找它最初的发布时间,然后加上 5 年。
“Python 3.11 的 EOL 是什么时候?”“嗯,让我想想…… PEP 664 是 3.11 的发布计划,它说 3.11 是在 2022 年发布的,5 年后 EOL,所以 2022 + 5 = 2027。”
但是,如果初始发布年份就在版本号中,那就容易多了。
“Python 3.26 的 EOL 是什么时候?”“26 + 5 = [20]31”
安装年龄的清晰度
在版本号中包含年份后,更容易计算出您的安装有多旧。例如,在当前方案下,如果您在 2035 年使用 Python 3.15,那么它最初是在 2026 年发布的(并且自 2031 年以来已 EOL)这一点就不那么明显了。
了解 CalVer 后,如果您在 2035 年使用 Python 3.26,那么很明显它是在九年前发布的,并且可能该升级了。
这有助于促使人们切换到仍在安全支持下的支持版本,并帮助教授可能有旧安装的新用户。
版本支持的清晰度
CalVer 使推理支持哪些 Python 版本变得更加容易。
例如,在没有 CalVer 的情况下,将您的最低兼容 Python 版本设置为 3.19(在 2031 年),这会根据版本采用和支持情况做出过于积极的假设。
然而,使用 CalVer,如果将最低版本设置为 3.30(在 2031 年),则更为明显。为了更广泛的支持,您可能更喜欢设置为 3.26。
同样,维护所有 CPython 上游版本的库维护者需要针对五个版本(或包括预发布版本在内的六个版本)进行测试。
例如,在 2030 年,没有 CalVer 的支持版本将是
- 3.15, 3.16, 3.17, 3.18, 3.19
使用 CalVer,它们将是
- 3.26, 3.27, 3.28, 3.29, 3.30
维护者可以一目了然地看到哪些版本是当前的,需要进行测试。
非目标
与当前方案一样,只有微版本号会因错误修复和安全更新而递增,主版本号和次版本号保持不变。例如:
当前方案 | 提议的 3.YY.micro | |
---|---|---|
首次发布(26 年 10 月) | 3.15.0 | 3.26.0 |
第一次错误修复发布(26 年 12 月) | 3.15.1 | 3.26.1 |
第二次错误修复发布(27 年 2 月) | 3.15.2 | 3.26.2 |
… | … | … |
最终安全发布(31 年 10 月) | 3.15.17 | 3.26.17 |
对 PEP 602(Python 的年度发布周期)没有改变。
- 对开发功能版本的 17 个月(alpha、beta 和 release candidate)没有改变。
- 对支持期限没有改变:两年完全支持和三年安全修复。
- 对每年十月的发布节奏没有改变。
规范
Python 版本号为 3.YY.micro,其中:
- 3 是主版本号——它始终是 3。
- YY 是次版本号——它是年份的缩写:
{year} - 2000
。 - micro 是微版本号——每次错误修复或安全发布时递增。
我们将保持主版本号为 3。Python 3 是品牌;不会有 Python 4。
在 2100 年,次版本号将是 2100-2000 = 100
,因此版本将是 3.100.0。
Python 3.14 将是本次更改之前的最后一个版本,于 2025 年发布。Python 3.26 将是本次更改之后第一个版本,于 2026 年发布。将不包含 Python 3.15 至 3.25。
安全隐患
已知:无。对错误修复和安全阶段的持续时间和时间没有改变。
如何教授
我们将在博客、3.14 的发布说明、文档以及通过社区宣传来宣布这一消息。
本次更改的目标版本是 3.14 之后的版本:而不是 3.15,而是 3.26。此 PEP 于 2024 年 6 月提出。3.15/3.26 版本的开发将于 2025 年 5 月开始,第一个 alpha 版于 2025 年 10 月发布,初始版本于 2026 年 10 月发布。我们可以在 3.14 周期内更新文档。这提供了充足的通知。
我们可以发布预览版本,仅更改版本用于早期测试。
我们可以将 python3.15
命令作为 Python 3.26 的一部分发布,该命令会立即报错并告知用户改用 python3.26
。
被拒绝的想法
YY.0
例如,Python 26.0 将于 2026 年发布。
人们对 Python 4 版本没有太多兴趣。我们不想重蹈 2 到 3 的覆辙,而且 4.0 版本现在承载了很高的期望。我们不希望出现“颠覆性”的更改。
也许 Python 4 可以保留给像移除 GIL(PEP 703)这样的大事,但指导委员会已明确表示自由线程的推出必须是渐进的。我们会永远坚持 Python 3 吗?我们将永远坚持 Python 3 吗?
另一种选择是将年份放在主版本号中,并跳到 26.0。这可能意味着我们可以绕过所有 4.0 的包袱。
生态系统变化
将主版本号更改为双位数会破坏代码吗?
是的,任何对版本号的创新性更改都会这样,因为人们会做出假设,例如主版本号始终是 3,或者版本的部分始终是单位数。例如:
版本更改 | 示例 | 预期 | 实际 |
---|---|---|---|
2.7.9 → 2.7.10 | 'this is Python {}'.format(sys.version[:5])
|
2.7.10 | 2.7.1 |
3.9 → 3.10 | ".%s-%s" % (get_platform(), sys.version[0:3])
|
3.10 | 3.1 |
3 → 4 | if sys.version_info[1] >= 9:
|
4.0 | 0 |
3 → 26 | if sys.version[0] == '3':
|
26 | 2 |
最后一个与 YY.0 版本控制最相关。因此,3.YY 方案是最安全的,需要最少的更改,因为版本号的*形状*没有改变:它仍然是 3 后面跟着两位数字。
提示
使用 Ruff 的 YTT 规则或 Flake8 的 flake8-2020 插件来帮助查找此类问题。
python3
命令
PEP 394(Unix-like 系统上的“python”命令)概述了对 python
、python2
和 python3
命令的建议。python
可以映射到 python2
或 python3
。如果主版本号更改并开始每年更改,则需要重新审视这些。
在 Python 2.7 结束生命周期四年后,我们可以建议 python
只映射到最新的 Python 3+ 版本。但是,当 Python 26.0 发布时,python3
会映射到什么?这将引入额外的复杂性和成本。
CPython 变化
除了 python3
命令的变化,CPython 中至少有四个地方假定主版本号为 3,并且需要更新:
YY.0 拒绝
日历版本控制的好处与 YY.0 版本控制的综合成本相比不是那么大。因此,YY.0 版本控制被拒绝。
YY.MM
例如,Python 26.10 将于 2026 年 10 月发布。
基于 YY.0 版本控制,我们也可以像 Ubuntu 和 Black 一样,将发布月份作为次版本号。这将清楚地表明它是在一年中的*何时*发布的,以及*何时*将达到生命周期结束。
然而,YY.MM 版本控制因与 YY.0 版本控制相同的原因而被拒绝。
3.YYYY
例如,Python 3.2026 将于 2026 年发布。
使用四位数更容易看出次版本号是年份,并避免与使用 YY.MM 的 Ubuntu 版本混淆。
PY_VERSION_HEX
CPython 的 C API PY_VERSION_HEX
宏目前使用八位来编码次版本号,最多支持 255。要容纳四位数的年份,它需要扩展到 11 位以适应 2047,或者更准确地说,12 位以适应 4095。
这看起来是可行的,因为它用于数字比较,例如 #if PY_VERSION_HEX >= ...
。在排名前 8000 的 PyPI 项目中,只发现了一个位移操作的实例(hexversion >> 16 != PY_VERSION_HEX >> 16
)。
然而,3.YYYY 被拒绝,因为从两位数变为四位数仍然需要比简单的 3.YY 版本控制更多的工作并破坏更多代码。
版本
例如,Python 3.15(2026 版)将于 2026 年发布。
Rust 语言使用“版本”来引入破坏性更改。将其应用于 Python 需要对PEP 387(向后兼容性策略)进行重大更改,并且超出了此 PEP 的范围。
我们可以为发布添加年份标签,例如“Python 3.15 (2026 Edition)”,但这被拒绝,因为我们需要跟踪*两个*数字。
采用 SemVer 并跳过 4
例如,Python 5.0 将于 2026 年发布,6.0 于 2027 年发布,以此类推。
我们可以完全跳过有问题的 4.0 并采用 SemVer。由于每个功能版本都会移除弃用项,因此我们每年都会获得一个新的主版本号。
这被拒绝了,因为我们得不到日历版本控制的好处,并且离开 3.x 也会破坏代码。
3.14 周期内的变化
Python 3.14 版本必须继续,因为:π。
向后兼容性
此版本更改是所考虑的 CalVer 选项中最安全的(请参阅拒绝的设想):我们保留 3 作为主版本号,次版本号仍然是两位数。次版本号最终会变为三位数,但这可以预测,很遥远,并且可以提前计划。
我们保留 python3
可执行文件。
版本映射
将跳过 3.15 到 3.25(含)的版本。计划用于这些版本的特性、弃用和移除将被重新映射到新的版本号。
例如,最初计划在 3.16 中移除的弃用项,将改为在 3.27 中移除。
旧版本 | 新版本 | 初始发布 |
---|---|---|
3.14 | 3.14(无变化) | 2025 |
3.15 | 3.26 | 2026 |
3.16 | 3.27 | 2027 |
3.17 | 3.28 | 2028 |
3.18 | 3.29 | 2029 |
3.19 | 3.30 | 2030 |
3.20 | 3.31 | 2031 |
3.21 | 3.32 | 2032 |
3.22 | 3.33 | 2033 |
3.23 | 3.34 | 2034 |
3.24 | 3.35 | 2035 |
3.25 | 3.36 | 2036 |
向前兼容性
未来发布节奏的变化
此 PEP 提议不改变 PEP 602 中定义的年度发布节奏,该节奏为年度发布提供了许多充分的理由(例如,更小的版本,可预测的发布日历,以及与外部再分发者的同步)。尽管可能性不大,但如果我们将来决定改变发布节奏,CalVer 并不妨碍这样做。
不那么频繁
如果我们采用*每年发布少于一次*的节奏,提议的 CalVer 方案仍然有效;事实上,它甚至有助于人们知道应该在哪一年期待发布。例如,如果我们从 2036 年开始每两年发布一次:
- 3.36.0 将于 2036 年发布
- 3.38.0 将于 2038 年发布
- 以此类推。
生态系统变化在一定程度上取决于假设的发布节奏更改 PEP 如何更新PEP 387(向后兼容性策略)。例如,如果它要求弃用期至少为一个功能版本而不是当前的两个版本(以维持最短两年),那么 CalVer 相对于现状的优势在于无需更改计划中的移除版本(除了调整任何落在非发布年份的版本)。
更频繁
如果我们采用*每年发布一次以上*的节奏,这里有一些选项。例如,如果我们从 2036 年开始在 4 月和 10 月发布,接下来的四次发布可以是:
方案 | 备注 | 2036 a | 2036 b | 2037 a | 2037 b |
---|---|---|---|---|---|
YY.MM.micro | 年份为主,月份为次 | 36.04.0 | 36.10.0 | 37.04.0 | 37.10.0 |
YY.x.micro | 年份为主,序列号为次 | 36.1.0 | 36.2.0 | 37.1.0 | 37.2.0 |
3.YYMM.micro | 结合年份和月份作为次版本 | 3.3604.0 | 3.3610.0 | 3.3704.0 | 3.3710.0 |
3.YYx.micro | 结合年份和序列号作为次版本 | 3.360.0 | 3.361.0 | 3.370.0 | 3.371.0 |
3.YY.MM.micro | 添加额外的月份段 | 3.36.04.0 | 3.36.10.0 | 3.37.04.0 | 3.37.10.0 |
3.major.micro | 不再使用 CalVer:递增次版本 | 3.36.0 | 3.37.0 | 3.38.0 | 3.39.0 |
3.50.0 | 3.51.0 | 3.52.0 | 3.53.0 | ||
3.100.0 | 3.101.0 | 3.102.0 | 3.103.0 | ||
4.major.micro | 不再使用 CalVer:递增主版本 | 4.0.0 | 4.1.0 | 4.2.0 | 4.3.0 |
5.major.micro | 5.0.0 | 5.1.0 | 5.2.0 | 5.3.0 |
YY 选项将需要解决围绕平台兼容性标签、python3 命令以及假设版本始终以 3 开头的代码问题。
将主版本号保持为 3 但将次版本号更改为三位或四位数的选项也需要解决假设版本始终是两位数的代码问题。
添加额外月份段的选项是最大的改变,因为代码需要处理四部分版本而不是三部分。
放弃 CalVer 的选项是最保守的,允许主版本号和次版本号自由选择。
不再使用 CalVer
现在采用 CalVer 并不妨碍将来放弃 CalVer,例如,回到原来的方案、SemVer 或其他方案。一些选项列在上面的表格中。如果想清楚地表明次版本号不再是年份,可以将其提升到一个更高的整数(例如,3.50 或 3.100),或者提升主版本号(例如,到 4.0 或 5.0)。此外,还可以考虑使用版本 epoch。
脚注
作者在 2024 年的Python 语言峰会上提出了日历版本控制;此 PEP 是在峰会期间和 PyCon US 期间讨论的结果。
致谢
感谢 Seth Michael Larson 提供语言峰会问答记录和博客文章,以及在峰会和 PyCon US 上提供反馈的所有人。
感谢 Łukasz Langa 和 Alex Waygood 审阅此 PEP 的草稿。
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源:https://github.com/python/peps/blob/main/peps/pep-2026.rst