Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 780 – ABI 功能作为环境标记

作者:
Klaus Zimmermann <klaus_zimmermann at gmx.de>, Ralf Gommers <ralf.gommers at gmail.com>
发起人:
Lysandros Nikolaou <lisandrosnik at gmail.com>
讨论至:
Discourse 帖子
状态:
草案
类型:
标准跟踪
主题:
打包
创建日期:
2025年3月21日
Python 版本:
3.14
发布历史:
2024年8月5日, 2025年3月26日

目录

摘要

本PEP定义了通过一个新的 sys_abi_features 环境标记,将ABI功能用作项目依赖项的环境标记。PEP 508(后来移至依赖项指定符)引入了环境标记,以基于描述何时应使用依赖项的规则来指定依赖项。本PEP扩展了环境标记,以允许根据Python解释器的特定ABI功能来指定依赖项。为此,它定义了一组ABI功能,并指定了如何将它们作为新的标记变量 sys_abi_features 提供给环境标记

动机

2015年,PEP 508建立了环境标记,用于根据环境条件指定依赖项。自由线程CPython的开发[1]强调了需要一个环境标记来区分解释器构建时使用的不同ABI功能。例如,目前无法使用环境标记区分GIL启用和自由线程CPython解释器。这导致了自由线程的采用及其增量推广的实际问题。当一个Python包与自由线程CPython兼容时,它还需要其所有构建和运行时依赖项都兼容。目前无法在元数据中精确捕获兼容的第一个依赖项版本,并且增加GIL启用构建的依赖项的最低版本通常是不希望的,因为它不必要地限制了包之间的兼容性。

自由线程环境标记的Discourse帖子中讨论了这些具体问题的一些例子。

  • Cython仅在其主分支中对自由线程提供(实验性)支持,并且被许多已经发布 cp313t wheel的项目使用。选择错误的Cython版本会导致许多模糊的构建失败和运行时崩溃。如果元数据能够表达这一点,将会很有益处(参见为自由线程Python要求Cython预发布版)。
  • CFFI尚未支持自由线程,并且Armin Rigo(其中一位维护者)表示,分叉cffi,实现自由线程支持,然后仅在功能“经过合理测试(无论是作为测试,还是在这种情况下,通过在各种其他项目中实际使用进行测试)”后,再以一个大型PR的形式返回CFFI项目,可能是一个好主意。有许多项目依赖于cffi。它们可能乐意仅为自由线程而开始依赖于一个分叉,但是为>=3.13或所有Python版本依赖于一个分叉似乎是一个更大的要求,并且对分发打包者来说更具破坏性。

尽管这些具体示例可能会在今年晚些时候通过 Cython 和 CFFI 发布兼容版本来解决,但相同的问题将在堆栈的更高层重复出现。自由线程的推广预计将需要数年时间,而一个自由线程环境标记将使推广过程显著简化。

另一个尚未被环境标记覆盖的重要ABI特性是解释器的位数。在大多数情况下,sys_platformplatform_system 标记就足够了,因为每个平台通常只使用一种位数。然而,在 Windows 上情况并非如此:x86-64 Windows 上广泛使用 32 位和 64 位 Python 解释器。无法区分两者可能与提供编译扩展的包相关。例如,SciPy 不提供 win32 wheels(由于缺乏支持 Fortran 的合适 32 位编译器工具链而无法提供)。这些缺失的 wheels 可能会很尴尬,尤其是对于 SciPy 只是可选依赖项的项目。在这种情况下,能够指定除非解释器是 Windows 上的 32 位,否则需要 SciPy(参见除非在 32 位 win32 上,否则要求 SciPy)将很有用,以避免因缺少 wheels 而导致的从源代码安装失败。

基本原理

本PEP的目的是引入其核心功能,同时尽量减少对现有生态系统的影响。PEP 508中提出的现有语法易于直接扩展以包含新的环境标记。

对自由线程Python的展望

PEP 703,即自由线程的已接受提案,指出自由线程Python的推广应逐步进行,Python指导委员会在PEP 703接受帖子中对此进行了澄清,这意味着一个跨多个版本的三个阶段过程。因此,重要的是要确保本PEP中的机制适用于自由线程或非自由线程可能是默认或唯一选项的Python解释器。

在撰写本文时,自由线程 Python 处于第一阶段:实验阶段。在此阶段,迫切需要提出的环境标记,以帮助随着包作者逐步添加支持而向自由线程 Python 过渡。

随着支持包数量的增加,特别是在第二阶段:支持但不默认阶段,我们仍然预计对环境标记有强烈的需求,以帮助过渡。

当自由线程Python进入第三阶段:默认阶段时,对环境标记的需求将减少,尽管目前尚不清楚GIL启用的Python是否会完全淘汰(它可能仍然作为非标准构建选项可用)。如果它持续存在,可能会出现对ABI特性检测的逆向需求。

事实上,在所有三个阶段中,包作者可能都需要根据 ABI 功能选择其依赖项的特定版本,随着时间的推移,从默认启用 GIL 转移到默认自由线程。

ABI 功能的设计考虑到了这一点,以确保在不断变化的 Python 生态系统中,在可预见的未来保持有用性和简洁性。

与其他PEP的关系

本PEP扩展了带有ABI特性集语义的环境标记。PEP 751包含了一个类似的扩展,用于锁定文件特定的环境标记;尽管两者是独立开发的,但在新的集合语义方面它们是兼容的。

规范

本文档中的关键词“必须”、“不得”、“必需”、“”、“不应”、“建议”、“不建议”、“推荐”、“可以”和“可选”应按照RFC 2119中的描述进行解释。

ABI功能

ABI 特性是 Python 解释器的内在属性,表示为简单易懂的字符串。然而,并非所有特性都同样适用于所有 Python 解释器或 Python 版本。例如,自由线程解释器和 GIL 启用解释器之间的区别仅与 CPython 3.13 及更高版本相关,但解释器的位数与所有解释器都相关。

所有解释器**必须**按所述处理以下 ABI 功能。仅限于特定解释器的 ABI 功能**不得**由其他解释器提供。这些功能分为组,每个组**必须**正好存在一个功能,除非该组被标记为可选,在这种情况下,**必须**最多存在一个功能。

free-threadinggil-enabled (仅限 CPython)
如果Python解释器是自由线程的,则free-threading特性**必须**存在,并且gil-enabled特性**不得**存在。否则,gil-enabled特性**必须**存在,并且free-threading特性**不得**存在。
debug (仅限 CPython,可选)
此ABI功能保留用于CPython的--with-pydebug构建。如果解释器是具有Py_DEBUG功能的CPython解释器,则debug功能**必须**存在。在POSIX系统上,这对应于Python表达式"d" in sys.abiflags
32-bit64-bit (可选)
解释器的位数,即它是 32 位还是 64 位构建[2]。如果位数未知,或者既不是 32 位也不是 64 位,则此功能**不得**存在。

sys_abi_features 环境标记

为了使 ABI 功能在依赖项规范中可用,新的环境标记变量 sys_abi_features 将添加到依赖项指定符的格式中。

为此,我们需要扩展PEP 508中规定并在依赖项指定符中维护的语法,并记录可能的值。

语法通过如下扩充 env_var 的定义来包含 sys_abi_features 标记变量

env_var       = ('python_version' | 'python_full_version' |
                 'os_name' | 'sys_platform' | 'platform_release' |
                 'platform_system' | 'platform_version' |
                 'platform_machine' | 'platform_python_implementation' |
                 'implementation_name' | 'implementation_version' |
                 'sys_abi_features' |
                 'extra' # ONLY when defined by a containing layer
                 )

与语法一样,依赖项指定符中的环境标记概述表也进行了扩充,增加了以下一行

标记 Python 等效项 示例值
sys_abi_features 没有直接等效项 {'free-threading', '64-bit'}, {'gil-enabled', 'debug', '32-bit'}

通过这些补充,ABI 功能可以在依赖项规范中通过 in 运算符测试功能的存在,或者通过 not in 运算符测试功能的缺失。

示例

为自由线程Python要求Cython预发布版

若要仅为自由线程Python解释器要求Cython的预发布版本,可以使用以下依赖项规范

cython >3.1.0a1; "free-threading" in sys_abi_features
cython ==3.0.*; "free-threading" not in sys_abi_features

除非在32位 win32 上,否则要求SciPy

若要要求 SciPy,除非在 Windows 上的 32 位解释器上,可以使用以下依赖项规范

scipy; platform_system != "Windows" or "32-bit" not in sys_abi_features

为具有调试功能的自由线程解释器要求NumPy

若要仅为具有调试功能的自由线程解释器要求 NumPy,可以使用以下依赖项

numpy; "free-threading" in sys_abi_features and "debug" in sys_abi_features

向后兼容性

这是对现有环境标记的纯粹扩展,不影响现有环境标记或依赖规范,因此没有直接的向后兼容性问题。

然而,这项功能的引入对许多生态系统工具产生了影响,尤其是那些试图支持检查 pyproject.tomlrequirements.txt 中数据的工具。

审计和更新工具

各种工具都理解以 requirements.txt 文件形式表示的 Python 依赖数据。(例如,Dependabot、Tidelift 等)

此类工具检查依赖数据,并在某些情况下提供工具辅助或完全自动化的更新。我们预计,起初没有任何此类工具会支持新的环境标记,广泛的生态系统支持可能需要数月甚至数年才能实现。

因此,新环境标记的用户在开始使用它们时,其工作流程和工具支持将有所下降。任何新的依赖数据编码位置和方式标准都是如此。

安全隐患

本PEP引入了在项目中指定依赖信息的新语法。然而,它并未引入新的机制来处理或解决依赖关系。

因此,除了任何可能已经用于安装依赖项的工具所固有的安全问题之外,它不带来其他安全问题——即,此处可以指定恶意依赖项,就像它们可以在 requirements.txt 文件中指定一样。

如何教授此内容

环境标记的使用已得到充分确立和主要通过依赖项指定符进行传达。新的环境标记可以在同一文档中引入。此外,对于包作者和用户,可以在Python自由线程指南中提供特定于自由线程的指导。

参考实现

环境标记的参考实现在 packaging 库的一个分支中提供,位于 ABI 功能的环境标记

一个演示包也已提供。

由于pip内部使用了packaging的内嵌副本,我们还提供了一个打补丁版本的pip,它将内嵌的packaging替换为上面链接的参考实现。

被拒绝的想法

扩展机制

在早期关于该主题的讨论中(自由线程的环境标记),提出了环境标记的通用扩展机制的想法。虽然如果将来出现新的环境标记需求时,可以避免整个PEP流程很吸引人,但存在两个主要挑战。

首先,一个完全动态的机制将给依赖于依赖规范静态分析的工具带来困难。

这意味着,即使采用动态机制,新的环境标记仍可能需要在PEP中明确说明。

其次,引入动态机制将要求打包库中实现更复杂,这将与当前方法有显著不同。

未解决的问题

其他环境标记

如果现在需要其他环境标记,则本 PEP 可以扩展以包含它们。

其他工具

参考实现基于 packaging 库和 pip。我们已经确认这允许使用多个构建后端构建和安装包。可能应该将其他工具添加到参考实现中。

脚注

致谢

感谢 Filipe Laíns 提出 abi_features 属性的建议,并感谢 Stephen Rosen 提供了 PEP 735 的向后兼容性部分,该部分作为本 PEP 相应部分的模板。


来源:https://github.com/python/peps/blob/main/peps/pep-0780.rst

最后修改:2025-04-17 09:38:03 GMT