Skip to content

Avoid .abi3t extension suffixes on Python 3.13t and 3.14t - #5363

Merged
jaraco merged 3 commits into
pypa:mainfrom
ngoldbaum:fix-3.14t
Oct 20, 2026
Merged

jaraco merged 3 commits into
pypa:mainfrom
ngoldbaum:fix-3.14t

Conversation

@ngoldbaum

Copy link
Copy Markdown
Contributor

Summary of changes

Just before the 84.2.0 release #5193 and #5352 were merged. As a consequence of #5352 and the new capability in #5193, setuptools began naming py_limited_api=True extensions .abi3t.so on Python 3.13t and 3.14t. Those interpreters cannot import that suffix: on 3.14t, import probe fails for a version-specific wheel containing probe.abi3t.so.

Use the interpreter-specific extension suffix instead, such as probe.cpython-314t-darwin.so, so these builds remain importable without claiming stable-ABI support. This also fixes the old behavior, which incorrectly labeled these as .abi3.so extensions.

Pull Request Checklist

  • Changes have tests
  • News fragment added in newsfragments/

@jameshilliard jameshilliard left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The version-specific fallback looks correct. I reproduced the original import failure on 3.14t without this guard, then verified the PR with 79 passing tests (2 skipped) across test_build_ext.py and test_bdist_wheel.py on 3.14t, plus 48 focused tests on 3.15t.

There is one integration detail with #5362: its cross-build filename assertion currently expects .abi3t.so for a 3.14t target. When these changes are combined, that expectation needs to use the target EXT_SUFFIX instead. The version-specific fallback here is the correct behavior.

Two inline suggestions below: a fix for the Cygwin test failure and an optional simplification of the guard.

Comment thread setuptools/tests/test_bdist_wheel.py Outdated
Comment on lines +547 to +548
with ZipFile(wheel_path) as archive:
archive.extractall(installed)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ZipFile.extractall() does not restore the executable permissions recorded in the wheel, which Cygwin needs to load the extension DLL. Both parameterizations are failing with ImportError: Permission denied in the Cygwin job.

Could this use unpack_zipfile from setuptools.archive_util instead? That existing helper preserves permissions. We made the same change in #5362. With that import added, this block becomes:

Suggested change
with ZipFile(wheel_path) as archive:
archive.extractall(installed)
unpack_zipfile(wheel_path, installed)

Comment thread setuptools/command/build_ext.py Outdated
Comment on lines +90 to +95
abi = '.abi3'
if get_config_var('Py_GIL_DISABLED'):
# The 3.13t and 3.14t loaders cannot import .abi3t files.
if suffix.startswith(('.cpython-313t', '.cpython-314t')):
return None
abi = '.abi3t'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Optional simplification: the t in these target suffixes already identifies the free-threaded builds we need to exclude, so this could be another early return alongside the existing unsupported-platform checks. That preserves the existing ABI-selection expression and avoids the extra nesting:

Suggested change
abi = '.abi3'
if get_config_var('Py_GIL_DISABLED'):
# The 3.13t and 3.14t loaders cannot import .abi3t files.
if suffix.startswith(('.cpython-313t', '.cpython-314t')):
return None
abi = '.abi3t'
# The 3.13t and 3.14t loaders cannot import .abi3t files.
if suffix.startswith(('.cpython-313t', '.cpython-314t')):
return None
abi = '.abi3t' if get_config_var('Py_GIL_DISABLED') else '.abi3'

I also checked this form against the extension tests and the limited-/version-specific wheel tests on 3.14t and 3.15t: 48 passed on each.

@ngoldbaum

Copy link
Copy Markdown
Contributor Author

Applied suggestions from @jameshilliard and I made a comment on #5362 with a suggestion for the tests there to resolve conflicts with this PR.

@ngoldbaum

Copy link
Copy Markdown
Contributor Author

I think the pypy test failure is unrelated but please let me know if you want me to take a closer look.

@tipabu

tipabu commented Oct 20, 2026

Copy link
Copy Markdown

This also fixes the old behavior, which incorrectly labeled these as .abi3.so extensions.

Note that the old behavior did at least result in useable extensions, though -- importlib.machinery.EXTENSION_SUFFIXES on py314t does include .abi3.so. Looks like I need to pin setuptools to 84.1.0 to continue building useful py314t wheels.

@ngoldbaum

Copy link
Copy Markdown
Contributor Author

Looks like I need to pin setuptools to 84.1.0 to continue building useful py314t wheels.

I think it was harmless before because they are importable. Unfortunately the abi3.so issue in EXTENSION_SUFFIXES was not fixed in CPython until 3.15...

@jaraco
jaraco merged commit 873b29c into pypa:main Oct 20, 2026
25 of 26 checks passed
@jameshilliard

Copy link
Copy Markdown
Contributor

The previous .abi3.so naming worked on 3.14t, and our change in #5352 introduced a regression in 84.2.0.

#5363 addresses that regression by using the normal version-specific extension suffix on 3.13t and 3.14t instead of .abi3t.so. The description should clarify that the previous filenames were importable despite the misleading ABI label.

Could you confirm whether building with this PR resolves the issue? The added regression test builds and imports the extension with py_limited_api=True.

@tipabu

tipabu commented Oct 20, 2026

Copy link
Copy Markdown

Building with main (now that this has merged) does resolve my issue, thanks. And sure enough, it produced an extension ending with .cpython-314t-x86_64-linux-gnu.so

yabirgb added a commit to rotki/rotki that referenced this pull request Oct 27, 2026
The nightly backend tests failed at collection on Linux and macOS:
https://github.com/rotki/rotki/actions/runs/40451047174/job/122013590635

    OSError: Cannot load native module 'Crypto.Util._cpuid_c': Not found
    '_cpuid_c.cpython-314t-x86_64-linux-gnu.so', Not found
    '_cpuid_c.abi3.so', Not found '_cpuid_c.so'

On Python 3.14t pycryptodome and pycryptodomex only have abi3 wheels,
which uv will not use, so they are built from the sdist with an
unpinned setuptools. The 1 week exclude-newer cooldown resolved that
build environment to setuptools 84.2.0, which names free-threaded
limited-API extensions `.abi3t.so`. The pycryptodome loader does not
look for that suffix. setuptools 84.2.1 (pypa/setuptools#5363) goes
back to the regular `.cpython-314t-*.so` name.

Pin setuptools to 84.2.1 for every build environment with
build-constraint-dependencies, and use the same version for the
rotkehlchen build backend and the docs and packaging groups so they
agree. The exclude-newer-package entry only exists to let 84.2.1
through the cooldown window.

Checked with `uv sync --locked` on Linux x86_64, Python 3.14.4
free-threaded. macOS, Windows, the docs build and the packaged
binaries are left to CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants