This PEP defines using ABI features as environment markers for projectdependencies, through a newsys_abi_features environment marker.PEP 508(later moved toDependency specifiers) introduced environmentmarkers to specify dependencies based on rules that describe when thedependency should be used. This PEP extends the environment markers to allowspecifying dependencies based on specific ABI features of the Pythoninterpreter. For this, it defines a set ofABI Features and specifies howthey are made available forenvironment markersas a new marker variable,sys_abi_features.
In 2015,PEP 508 established environment markers to specify dependenciesbased on environment conditions. The development of free-threaded CPython[1] has underlined the need for an environment marker todiscriminate between different ABI features that the interpreter was builtwith. For example, currently there is no way to distinguish between aGIL-enabled and a free-threaded CPython interpreter with an environment marker.This leads to real world issues for the adoption of free-threading and itsincremental rollout. When a Python package is being made compatible withfree-threaded CPython, it also needs all its build and runtime dependencies tobe compatible. Capturing the first version of a dependency that is compatibleprecisely in metadata is currently not possible, and increasing the minimumversion of a dependency also for the GIL-enabled build is usually undesirablesince it unnecessarily limits compatibility between packages.
Some concrete examples of such issues have been discussed in theEnvironmentmarker for free-threading Discourse thread:
cp313twheels. Picking up the wrong Cython version is causing a lot of obscure buildfailures and runtime crashes. It would be beneficial if the metadata couldexpress that (c.f.Require Cython Pre-release for Free-Threaded Python).cffi, implement support forfree-threading, and only come back to the CFFI project with a single large PRthat adds support after the functionality “is reasonably well-tested (eitheras tests or, better in this case, tested by being in use in various otherprojects)”. There are a lot of projects that depend oncffi. They arelikely fine to start depending on a fork for free-threading only, howeverdepending on a fork for >=3.13 or for all Python versions seems like a muchlarger ask, and more disruptive for distribution packagers.While these concrete examples may be addressed later this year by Cython andCFFI making compatible releases, the same issue is going to repeat further upthe stack. The free-threading rollout is expected to take several years, and anenvironment marker for free-threading will make that rollout significantlyeasier.
Another important ABI feature that is not yet covered by environment markers isthe bitness of the interpreter. In most cases, thesys_platform orplatform_system markers are enough, because there is only a single bitnessin use per platform. This is not the case on Windows however: both 32-bit and64-bit Python interpreters are widely used on x86-64 Windows. Not being able todistinguish between the two may be relevant for packages that provide compiledextensions. For example, SciPy does not providewin32 wheels (it isn’t ableto due to the lack of a suitable 32-bit compiler toolchain with Fortransupport). Those wheels lacking can be awkward especially for projects whereSciPy is an optional dependency only. In that case, it would be useful to beable to specify that SciPy is requiredunless the interpreter is a 32-bit oneon Windows (c.f.Require SciPy Unless on 32-bit win32), to avoid failedfrom-source installations due to the missing wheels.
The intention of this PEP is to introduce its core features with minimal impacton the existing ecosystem. The existing grammar proposed inPEP 508 lendsitself to a straightforward extension to include the new environment marker.
PEP 703, the accepted proposal for free threading, states that the rolloutof free-threaded Python should be gradual, which has been clarified by thePython Steering Council inthe PEP 703 acceptance post to mean a three stageprocess over multiple releases. It is therefore important to make sure that themechanisms in this PEP are useable for Python interpreters where eitherfree-threading or non-free-threading could be the default or the only option.
At the time of writing, free-threaded Python is in Phase I: experimental phase.In this phase, there is an acute need for the proposed environment markers tohelp with the transition to free-threaded Python as package authors graduallyadd support.
As the number of packages with support increases, and particularly duringPhase II: Supported-but-not-default phase, we still anticipate a strong needfor the environment markers to help with the transition.
As free-threaded Python enters into Phase III: Default phase, the need for theenvironment markers will decrease, though at this point it is not clear thatthe GIL-enabled Python will be completely phased out (it may remain availableas a non standard build option). If it persists, the inverse need for the ABIfeature detection may arise.
Indeed, in all three phases it may be necessary for package authors to choosespecific versions of their dependencies based on the ABI features, with a shiftfrom GIL-enabled as default to free-threading as default over time.
The ABI features are designed with this in mind to guarantee usefulness andsimplicity for the foreseeable future in a changing Python ecosystem.
This PEP extends environment markers with set semantics for ABI features.PEP 751 includes a similar extensionfor lock file specific environment markers; although the two have beendeveloped indepedently, they are compatible where they overlap in terms of thenew set semantics.
The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”,“SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”,and “OPTIONAL”” in this document are to be interpreted as described inRFC 2119.
ABI features are intrinsic properties of the Python interpreter, expressed assimple, understandable strings. However, not all features are equallyapplicable to all Python interpreters or Python versions. For example, thedistinction between free-threaded and GIL-enabled interpreters is only relevantfor CPython 3.13 onwards, but the bitness of the interpreter is relevant forall interpreters.
All interpreters MUST handle the following ABI features as stated. ABI featuresthat are restricted to particular interpreters MUST NOT be provided by otherinterpreters. The features are subdivided into groups and for each group thereMUST be exactly one feature present, except when the group is marked asoptional, in which case there MUST be at most one feature present.
free-threading orgil-enabled (only CPython)free-threading featureMUST be present and thegil-enabled feature MUST NOT be present.Otherwise, thegil-enabled feature MUST be present and thefree-threading feature MUST NOT be present.debug (only CPython, optional)--with-pydebug build of CPython.If the interpreter is a CPython interpreter withPy_DEBUG capabilities,thedebug feature MUST be present. On POSIX systems, this correspondsto the Python expression"d"insys.abiflags.32-bit or64-bit (optional)sys_abi_features Environment MarkerTo make ABI features available in dependency specifications, a new environmentmarker variable,sys_abi_features, is added to the format of dependencyspecifiers.
To do this, we need to extend the grammar laid out inPEP 508 and maintainedin theDependency specifiers and document the possible values.
The grammar is extended to include thesys_abi_features marker variable byaugmenting the definition ofenv_var as follows:
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)
Like the grammar, also the overview table of environment markers inDependency specifiers is augmented to add the following row:
| Marker | Python equivalent | Sample values |
|---|---|---|
sys_abi_features | no direct equivalent available | {'free-threading','64-bit'},{'gil-enabled','debug','32-bit'} |
With these additions, ABI features can be used in dependency specifications viathein operator to test for the presence of a feature, or thenotinoperator to test for the absence of a feature.
To require a pre-release of Cython only for a free-threaded Python interpreter,the following dependency specification can be used:
cython>3.1.0a1;"free-threading"insys_abi_featurescython==3.0.*;"free-threading"notinsys_abi_features
win32To require SciPy unless on a 32-bit interpreter on Windows, the followingdependency specification can be used:
scipy;platform_system!="Windows"or"32-bit"notinsys_abi_features
To require NumPy only for a free-threaded interpreter with debuggingcapabilities, the following dependency can be used:
numpy;"free-threading"insys_abi_featuresand"debug"insys_abi_features
This is a pure extension to the existing environment markers and does notaffect existing environment markers or dependency specifications, hence thereare no direct backwards compatibility concerns.
However, the introduction of the feature has implications for a number ofecosystem tools, especially those which attempt to support examination of datainpyproject.toml andrequirements.txt.
A wide range of tools understand Python dependency data as expressed inrequirements.txt files. (e.g., Dependabot, Tidelift, etc)
Such tools inspect dependency data and, in some cases, offer tool-assisted orfully automated updates. It is our expectation that no such tools would supportthe new environment markers at first, and broad ecosystem support could takemany months or even some number of years to arrive.
As a result, users of the new environment markers would experience adegradation in their workflows and tool support at the time that they startusing them. This is true of any new standard for where and how dependency dataare encoded.
This PEP introduces new syntax for specifying dependency information inprojects. However, it does not introduce newly specified mechanisms forhandling or resolving dependencies.
It therefore does not carry security concerns other than those inherent in anytools which may already be used to install dependencies—i.e. maliciousdependencies may be specified here, just as they may be specified inrequirements.txt files.
The use of environment markers is well established and communicated chiefly inDependency specifiers. The new environment marker can beintroduced in the same document. Additionally, both for package authors andusers, free-threading specific guidance can be provided at thePython free-threading guide.
The reference implementation for the environment markers is available in a forkof thepackaging library atEnvironment markers for ABI features.
A demonstration package isalso available.
Sincepip uses a vendored copy ofpackaging internally, we also providea patched version of pip, which replaces the vendoredpackaging withthe reference implementation linked above.
In an early discussion of the topic (Environment marker for free-threading),the idea of a general extension mechanism for environment markers was broughtup. While it is appealing to forego a whole PEP process should the need fornew environment markers arise in the future, there are two main challenges.
First, a completely dynamic mechanism would present difficulties for tools thatrely on static analysis of dependency specifications.
This means that even if a dynamic mechanism were to be adopted, new environmentmarkers would likely still need to be spelled out in a PEP.
Second, the introduction of a dynamic mechanism would require a more compleximplementation in the packaging library, which would be a significant departurefrom the current approach.
If other environment markers are needed right now, this PEP could be extendedto include them.
The reference implementation is based on thepackaging library andpip.We have confirmed that this allows for building and installing packages withseveral build backends. It is possible that other tools should be added to thereference implementation.
platform_machine andplatform_python_implementation, these arenot sufficient to reliably determine the bitness of the interpreter,particularly on platforms that allow the execution of either kind of binary.Thanks to Filipe Laíns for the suggestion of theabi_features attribute andto Stephen Rosen for the Backwards Compatibility section ofPEP 735, whichserved as a template for the corresponding section in this PEP.
This document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.
Source:https://github.com/python/peps/blob/main/peps/pep-0780.rst
Last modified:2025-04-17 09:38:03 GMT