Repository navigation
Using the limited Python API in astropy #18163
Description
When building a Python package with C extensions, it is possible to build it against only the limited Python C API (more details at https://docs.python.org/3/c-api/stable.html), which is an API that does not change across minor versions of Python. This makes it possible to build a wheel on e.g. 3.11 and have it also work on 3.12 and 3.13. As an example, Sunpy uses this, and they only have to provide a few wheels, one per platform/architecture:
https://pypi.org/project/sunpy/6.1.1/
Extension-helpers will soon include a change that makes it possible to easily opt in to using this by just adding a single configuration item in pyproject.toml, namely:
[tool.distutils.bdist_wheel]
py-limited-api = "cp311"
This also requires using Cython 3.1.
Currently this does not work out of the box for astropy core, and there are a few errors we need to resolve:
column_mixins.pyx
It looks like Cython support may not be complete here, we should try and see if we can make a minimal example of the failure here and report it upstream.
x86_64-linux-gnu-gcc -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -DPy_LIMITED_API=0x030B0000 -DNPY_TARGET_VERSION=NPY_1_23_API_VERSION -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION -I/home/tom/python/dev/lib/python3.11/site-packages/numpy/_core/include -I/home/tom/python/dev/include -I/usr/include/python3.11 -c astropy/table/_column_mixins.c -o build/temp.linux-x86_64-cpython-311/astropy/table/_column_mixins.o
astropy/table/_column_mixins.c: In function ‘__pyx_f_7astropy_5table_14_column_mixins_column_getitem’:
astropy/table/_column_mixins.c:5217:80: error: invalid use of incomplete typedef ‘PyTypeObject’ {aka ‘struct _typeobject’}
5217 | __pyx_t_1 = ((PyTypeObject *)__pyx_mstate_global->__pyx_ptype_5numpy_ndarray)->tp_as_mapping->mp_subscript(__pyx_v_self, __pyx_v_item); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error)
| ^~
error: command '/usr/lib/ccache/x86_64-linux-gnu-gcc' failed with exit code 1
storage size unknown
There are several similar errors:
astropy/utils/xml/src/iterparse.c: At top level:
astropy/utils/xml/src/iterparse.c:1105:21: error: storage size of ‘IterParserType’ isn’t known
1105 | static PyTypeObject IterParserType =
| ^~~~~~~~~~~~~~
error: command '/usr/lib/ccache/x86_64-linux-gnu-gcc' failed with exit code 1
astropy/wcs/src/astropy_wcs.c:753:21: error: storage size of ‘WcsType’ isn’t known
753 | static PyTypeObject WcsType = {
| ^~~~~~~
astropy/wcs/src/astropy_wcs.c:753:21: error: storage size of ‘WcsType’ isn’t known
error: command '/usr/lib/ccache/x86_64-linux-gnu-gcc' failed with exit code 1
astropy/cosmology/_src/signature_deprecations.c: At top level:
astropy/cosmology/_src/signature_deprecations.c:200:21: error: storage size of ‘DeprKwsWrap’ isn’t known
200 | static PyTypeObject DeprKwsWrap = {
| ^~~~~~~~~~~
cc1: all warnings being treated as errors
error: command '/usr/lib/ccache/x86_64-linux-gnu-gcc' failed with exit code 1
Aside from these issues, everything builds fine, so it's not completely impossible to get there!
Need to investigate further what this is due to (similar to astropy.utils error above)
Linked PRs
- Enable compiling specific extensions against the Python 3.11 limited API #18211
- Include a limited API build in CI, disabling incompatible extensions #18236
- Run limited API build on Mac in addition to Linux #18250
- TST: also test building against Limited API on Windows #18252
- RFC: restrict
table._column_mixinto CPython's limited API #18227 - RFC: restrict
wcsextension modules to CPython's limited API #18231 - RFC: restrict
cosmologyextension modules to CPython's Limited API #18261 - RFC: restrict
utils.xml's extension modules to CPython's Limited API #18249 - WHL: build and distribute stable-ABI-compliant wheels #18420
Metadata
Metadata
Assignees
Type
Projects
- StatusShow more project fieldsDone
Activity
pllim commentedon May 20, 2025
astropy/table/_column_mixins.cis generated from thepyx, so that is extra layer to wade through for debugging. 🤪pllim commentedon May 20, 2025
Could the debugger be more specific on exactly what in this one isn't defined properly?
astropy/astropy/wcs/src/astropy_wcs.c
Line 753 in f442813
astrofrog commentedon May 20, 2025
For now I just wanted to make sure I opened an issue to keep track of known problems, but I'll try and dig deeper into this.
astrofrog commentedon May 20, 2025
Just a note about the failure in
_column_mixins.pyx- the problematic line is:If we use only the limited API, we can't call methods on
PyTypeObjectdirectly (it is an opaque struct). I'm not sure how we can work around this though.neutrinoceros commentedon May 22, 2025
Any idea how this option will behave in free-threaded Python (#16916) ?
At the moment, Limited API is only supported for GIL-enabled builds, so most build systems I know of (meson, maturin) will just ignore the option in a free-threaded build.
To paraphrase Sam Gross' talk at PyConUS 2025, the current goal is to define a new stable ABI (abi4) for Python 3.15 (oct 2026) that will work with both builds (compile once, install in against GIL-enabled or free-threaded Python).
neutrinoceros commentedon May 29, 2025
I wanted to take a shot a fixing the existing errors, and to my surprise, I don't seem to get the same ones your reported.
I do get the 3 following errors (alongside 10 warnings that I'll skip for brevity):
All these errors live in
astropy_wcs.c, note in Cython code.neutrinoceros commentedon May 29, 2025
Also noting as I start digging:
the root issue in
astropy_wcs.cappears to be that we rely on implementation details of thePyTypeObjectstruct, but it's actually only available, through the limited API, as an opaque struct. I'm not sure yet how to refactor these details out. More inquiry required.astrofrog commentedon May 29, 2025
Yes I realized since that the errors I posted above were not the main errors, and other errors happened higher up.
Just to make sure we don't duplicate effort, I started looking into the astropy.wcs issues and I made progress on fixing the errors but it's a bit tedious as quite a few files need fixing. Nevertheless I think it should be possible to fix. For now, the trickiest ones to fix as far as I can tell are the column_mixin.pyx one and the cosmology one, and I was a bit stuck trying to fix them.
In case it's useful, I can try and push my changes for astropy.wcs shortly.
neutrinoceros commentedon May 30, 2025
Definitely useful. And thanks for the heads up !
1 remaining item
da-woods commentedon Jun 6, 2025
The other option is
PyType_GetSlotbut be very wary of the behaviour change before 3.10 (it'll just crash though, so you'll find out pretty quickly if it's an issue).neutrinoceros commentedon Jun 6, 2025
Oh great, thanks for pointing it out !
the change in 3.10 won't affect us because we already require 3.11+
neutrinoceros commentedon Jun 6, 2025
@da-woods I tried the following patch:
but compilation fails with
I'm guessing I'm not doing it right. What's the correct way to include a constant like
Py_tp_as_mappingfromPython.hin Cython ?da-woods commentedon Jun 6, 2025
The slot is
Py_mp_subscript. You don't need to care that it's inas_mappingda-woods commentedon Jun 6, 2025
For the others e.g.
you'll need to convert them into heaptypes (i.e. define them in a
PyType_Specand then call PyType_FromSpec. Unfortunately there doesn't seem to be a hugely good tutorial on this, so you might be best browsing the Python tests for how to do it: https://github.com/python/cpython/blob/main/Modules/_testcapi/heaptype.cneutrinoceros commentedon Jun 9, 2025
@astrofrog I took the liberty to add a "Linked PRs" section to the issue.
astrofrog commentedon Jun 9, 2025
Thank you!
astrofrog commentedon Jun 9, 2025
@neutrinoceros - see #18236 for another PR, which I've added to the list.
neutrinoceros commentedon Jun 13, 2025
I think all refactor PRs are now stable and up for review !
once they're all in, we can start infrastructural changes to actually leverage
abi3wheels in the release process.astrofrog commentedon Jun 13, 2025
@neutrinoceros - thank you for all your work on this!
neutrinoceros commentedon Jul 7, 2025
We're getting there ! #18231 is the last remaining open PR to get limited-api compliance !