Skip to content

CI: Update CI to validate Limited API in debug job builds - #32130

Merged
rgommers merged 1 commit into
numpy:mainfrom
prathamhole14:limited_api_ci
Aug 4, 2026
Merged

rgommers merged 1 commit into
numpy:mainfrom
prathamhole14:limited_api_ci

Conversation

@prathamhole14

@prathamhole14 prathamhole14 commented Jul 28, 2026 •

Copy link
Copy Markdown
Member

PR summary

JOB: Check that the extension modules ported to the Limited C API were built against it.

To check if each ported module has its own abi3.so file, in this CI each ported module is to be added in the list for m in _pocketfft_umath; do, I will do it manually when I add the limited_api for each extension module.

Note: I think the regex would unnecessarily complicate things for temporary stage that's why I am going with manually adding approach
Once everything is shifted this can be easily automated as we will use limited-api = true in global meson build or complete all extended module checks.

Reference: #31913 (comment) and #31913 (comment)

Updated: The debug interpreter doesn't produce .abi3.so named exenstion files at all, because it means this job proves the ported modules compile under Py_LIMITED_API so therefore they must have produced .abi3.so files.

AI Disclosure

For bash syntax

@ngoldbaum

Copy link
Copy Markdown
Member

I will do it manually when I add the limited_api for each extension module.

Can we get explicit checks for this as part of a CI job?

@prathamhole14

Copy link
Copy Markdown
Member Author

Three ways it fails the CI job:

  1. a listed module wasn't built at all
  2. a listed module was built without the flag (the allow_limited_api option silently didn't apply)
  3. a module was built with the flag but isn't listed (someone ported one and forgot the list)

@prathamhole14
prathamhole14 marked this pull request as draft July 29, 2026 16:53
@prathamhole14
prathamhole14 marked this pull request as ready for review July 29, 2026 19:06

@ngoldbaum ngoldbaum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, I spotted a couple issues below though.

@rgommers @andyfaff can I get one of you to look at this as the local CI experts?

Comment thread tools/ci/check_limited_api.py Resolved
Comment thread tools/ci/check_limited_api.py Resolved
Comment thread tools/ci/check_limited_api.py Resolved
@rgommers

Copy link
Copy Markdown
Member

Question @prathamhole14: why do we need this script at all? I was just expecting a -Dpython.allow_limited_api=true addition, so the extension module becomes .abi3 and that gets exercised when regular CI runs to ensure it's all functional. When you proposed adding CI you pointed at PyWavelets/pywt#828 as a reference, and that doesn't do anything like this script.

@prathamhole14

Copy link
Copy Markdown
Member Author

Question @prathamhole14: why do we need this script at all? I was just expecting a -Dpython.allow_limited_api=true addition, so the extension module becomes .abi3 and that gets exercised when regular CI runs to ensure it's all functional. When you proposed adding CI you pointed at PyWavelets/pywt#828 as a reference, and that doesn't do anything like this script.

Fair, dropping the script. I only wanted to catch the flag silently becoming a no-op, and a grep for Py_LIMITED_API in build/*/compile_commands.json covers that in one line. Happy to leave even that out if you'd rather just have the flag.

@rgommers

Copy link
Copy Markdown
Member

I'd prefer just the flag, yes. That should suffice, so let's try to keep it as clean as possible.

@andyfaff

andyfaff commented Jul 31, 2026 •

Copy link
Copy Markdown
Member

Perhaps I'm missing something. Why don't we just use the abi3audit package? Make a wheel as part of the job and audit that.

On looking in more detail the PR seems like a ratchet to ensure that extension modules that have been ported don't slide back. It may be possible to just use abi3audit against each known extension.

@rgommers

rgommers commented Aug 1, 2026

Copy link
Copy Markdown
Member

Why don't we just use the abi3audit package? Make a wheel as part of the job and audit that.

That's indeed a good idea, but only after all of numpy builds as an abi3 wheel. Right now only part of the extension modules build.

On looking in more detail the PR seems like a ratchet to ensure that extension modules that have been ported don't slide back.

They won't slide back, no special check is needed - if something is used that isn't in the Limited API, it will cause a build failure as soon as -Dpython.allow_limited_api=true is called.

@andyfaff

andyfaff commented Aug 1, 2026 •

Copy link
Copy Markdown
Member

That's indeed a good idea, but only after all of numpy builds as an abi3 wheel. Right now only part of the extension modules build.

One can run the tool against individual extension modules. e.g.

e.g.

# after building with:
# spin build -- -Dbuildtype=debug -Dallow-noblas=true -Dpython.allow_limited_api=true

(dev3) nelly:random andrew$ abi3audit --assume-minimum-abi3 3.11 _sfc64.cpython-314-darwin.so -S -v
[07:50:25] 👎 : _sfc64.cpython-314-darwin.so has non-ABI3 symbols                                                                                    
           👎 : _sfc64.cpython-314-darwin.so uses the Python 3.15 ABI, but is tagged for the Python 3.11 ABI                                         
           ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓                                                                                   
           ┃ Symbol                                   ┃ Version  ┃                                                                                   
           ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩                                                                                   
           │ PyUnstable_Object_EnableDeferredRefcount │ not ABI3 │                                                                                   
           │ PyCode_NewEmpty                          │ not ABI3 │                                                                                   
           │ PyDict_SetDefault                        │ not ABI3 │                                                                                   
           │ PyUnicode_AsUTF8                         │ not ABI3 │                                                                                   
           │ PyFrame_New                              │ not ABI3 │                                                                                   
           │ PyObject_CallFinalizerFromDealloc        │ not ABI3 │                                                                                   
           │ PyObject_ClearManagedDict                │ not ABI3 │                                                                                   
           │ PyMethod_New                             │ not ABI3 │                                                                                   
           │ PyMethod_Type                            │ not ABI3 │                                                                                   
           │ PyObject_VectorcallDict                  │ not ABI3 │                                                                                   
           │ _PyType_Lookup                           │ not ABI3 │                                                                                   
           │ PyObject_VisitManagedDict                │ not ABI3 │                                                                                   
           │ PyDict_Pop                               │ not ABI3 │                                                                                   
           │ PyUnstable_Code_NewWithPosOnlyArgs       │ not ABI3 │                                                                                   
           │ PyThreadState_GetUnchecked               │ not ABI3 │                                                                                   
           │ _PyDict_GetItem_KnownHash                │ not ABI3 │                                                                                   
           │ PyDict_SetDefaultRef                     │ 3.15     │                                                                                   
           │ PyObject_Vectorcall                      │ 3.12     │                                                                                   
           │ PyDict_GetItemRef                        │ 3.13     │                                                                                   
           │ PyDict_GetItemStringRef                  │ 3.13     │                                                                                   
           │ PyObject_GetOptionalAttr                 │ 3.13     │                                                                                   
           │ PyType_FromMetaclass                     │ 3.12     │                                                                                   
           │ PyImport_AddModuleRef                    │ 3.13     │                                                                                   
           │ PyObject_HasAttrWithError                │ 3.13     │                                                                                   
           │ PyObject_VectorcallMethod                │ 3.12     │                                                                                   
           └──────────────────────────────────────────┴──────────┘                                                                                   
           💁 _sfc64.cpython-314-darwin.so: 1 extensions scanned; 1 ABI version mismatches and 16 ABI violations found  

@rgommers

rgommers commented Aug 4, 2026

Copy link
Copy Markdown
Member

One can run the tool against individual extension modules. e.g.

Thanks. I knew that, my argument was more that it's essentially free once we have a wheel, and we don't want to complicate CI for this now. This whole exercise for seeing how far moving to the limited API is experimental, it might run into a hard blocker, or yield performance-related regressions that are of a size we care about. Until we figure that out, we want to merge only the minimal diffs (same reason as not merging the separate script that was in this PR). This kind of auditing is easy enough to do locally, and isn't on the critical path right now.

@rgommers rgommers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's give this a go, thanks @prathamhole14 and reviewers.

@rgommers
rgommers merged commit 702a259 into numpy:main Aug 4, 2026
89 checks passed
@rgommers rgommers added this to the 2.6.0 Release milestone Aug 4, 2026
@prathamhole14
prathamhole14 deleted the limited_api_ci branch August 4, 2026 06:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants