CEP 20 - Support for abi3
Python packages
Title | Support for abi3 Python packages |
Status | Approved |
Author(s) | Isuru Fernando <ifernando@quansight.com> |
Created | July 01, 2024 |
Updated | Dec 19, 2024 |
Discussion | https://github.com/conda/ceps/pull/86 |
Implementation | https://github.com/conda/conda-build/pull/5456 |
Abstract
This CEP specifies how abi3
Python packages are supported in conda install tools
(conda/mamba/micromamba/pixi) and how they are built in conda build tools
(conda-build/rattler-build).
Motivation
When building extensions for Python, they might use Python minor version
specific symbols. This results in the extension being usable only on that minor
version. These extensions are identified by the extension suffix.
For example, foo.cpython-310-x86_64-linux-gnu.so
is an extension that
supports only CPython 3.10 on the x86_64-linux-gnu
platform.
However, some symbols are available in all Python major.minor versions with some
lower bound on the Python version. These symbols are part of the
limited C API. It is guaranteed that the symbols in limited C API
introduced in Python 3.X are available in Python 3.Y for any Y >= X
.
Extensions using only these symbols are identified by the extension suffix
abi3.so
. For example, foo.abi3.so
.
These extensions only support the platform it was built for (e.g.
x86_64-linux-gnu
), but this is not specified in the extension suffix.
Note that the stable ABI is only specific to CPython and is not compatible with PyPy or other Python implementations. For a Python implementation independent ABI, see the HPy project.
The motivation for building abi3
packages is that we only need to build the
extension for one Python version and the extension will work for any Python
later version. This reduces the build matrix from 4-5 Python minor versions to one
Python minor version and reduces the maintenance burden of package builders.
noarch: Python packages
abi3
packages are Python version independent and we will first look at
noarch: python
packages that are also Python version independent and in addition
are arch-independent.
noarch: python
packages have several attributes to them:
-
A1: They have
subdir: noarch
ininfo/index.json
. -
A2: They have
noarch: python
ininfo/index.json
. -
A3: Python files are in
<PREFIX>/site-packages
. -
A4: Entry points are recorded in
info/link.json
.
A conda install tool does four things to support them:
-
B1: Files in
<PREFIX>/site-packages
are moved to the correct location. Eg:<PREFIX>/lib/python3.10/site-packages
. -
B2: Python files (files ending with
*.py
) are compiled to.pyc
files. Eg:<PREFIX>/lib/python3.10/site-packages/foo.py
is compiled to<PREFIX>/lib/python3.10/site-packages/__pycache__/foo.cpython-310.pyc
. -
B3:
.pyc
files created are recorded in<PREFIX>/conda-meta/<pkg>.json
so that they are removed properly when the package is uninstalled. -
B4: Entry points in
info/link.json
are materialized.
info/link.json file
An example info/link.json
for noarch: python
looks like
{
"noarch": {
"entry_points": [
"isympy = isympy:main"
],
"type": "python"
},
"package_metadata_version": 1,
"preferred_env": "foo"
}
An example for info/link.json
for noarch: generic
looks like
{
"noarch": {
"type": "generic"
},
"package_metadata_version": 1
}
Here preferred_env
is ignored by conda since 2017 and is not supported by
other conda install tools. Therefore info/link.json
is used exclusively
for noarch
packages and out of the two types, noarch: generic
packages
do not require any special action.
info/index.json file
An example of a noarch: python
recipe.
{
"arch": null,
"build": "pyh2585a3b_103",
"build_number": 103,
"depends": [
"mpmath >=0.19",
"python >=3.8"
],
"license": "BSD-3-Clause",
"license_family": "BSD",
"name": "sympy",
"noarch": "python",
"platform": null,
"subdir": "noarch",
"timestamp": 1718625708903,
"version": "1.12.1"
}
Current behavior in solver tools
Conda package upload tools like anaconda-client
use A1
to upload
the package to the noarch
subdir.
Conda install tools have slightly different behavior.
Conda:
- Actions
B1, B2, B3
are applied for packages withA3
. - Action
B4
is applied for packages withA4
.
Micromamba:
- Actions
B1, B2, B3
are applied for packages with bothA2, A3
. - Action
B4
is applied for packages with bothA2, A4
.
Implementation for abi3
packages
Support in install tools
We require the following attributes in abi3
packages:
-
C1: They have
subdir: <platform>
where<platform>
is the subdir that the package was built for. -
C2: They have
noarch: python
. -
C3:
A2, A3, A4
are applied.
This is compatible with conda/mamba/micromamba
install tools
currently.
Support in build tools
This requires support from build tools to set subdir: <platform>
.
In particular recipe authors would set
build:
python_version_independent: true
requirements:
host:
- python
- python-abi3
which would make the build tool
- D1:
Set
noarch: python
ininfo/index.json
.
Note that python-abi3
would set the runtime requirements.
This is explicitly required from recipe authors so that we do not
restrict this CEP to abi3
packages and allow the possibility for abi4
etc.
An example python-abi3=3.8
package would set itself in its
run_exports
entry and will have the following requirements:
requirements:
run:
- cpython >=3.8
- python-gil
Alternatives considered
Apply all actions in a post-link.sh
script.
A draft work provided at python-feedstock This was suggested by @mbargull, but some community members (@baszalmstra, @wolfv) does not prefer post-link scripts as they can be used for arbitrary code execution. However, in the author's opinion, this attack vector is not a new one since the install tool uses the Python executable in the host environment to compile the Python files.
noarch: python
packages with __linux, __osx, __win
constrains.
This suggestion by @wolfv
is not ideal as this clutters noarch
subdir
repodata.json
file with packages that are useless for the platform in question.
A new package_metadata_version
Since we can work within the constraints of the current install tools we do not need to require extra support from install tools.
Copyright
All CEPs are explicitly CC0 1.0 Universal.