Repository navigation
Free-threaded Python 3.14t/3.15t; Python 3.10-3.15 and wheels as in BinPackage - #10
Merged
Merged
Conversation
The free-threaded build doesn't support the limited API, so it gets a regular (non-abi3) extension. cffi 2.x marks the module as free-threading safe, so the GIL stays off. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Eight threads query one Ngrams, including its lazily computed sentence count, and compare the results with serial ones. A value published before it is final, planted in that lazy computation, fails the test on 3.14t. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
cibuildwheel builds cp314t wheels next to the abi3 wheel, and every wheel is checked to import, keeping the GIL off on free-threaded Python. The test matrix runs 3.14t, also with every test in eight threads at once. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Gentoo's Python records no -O flag for extension builds, so a source build outside Portage ran trie.cpp at -O0: 2.6x slower trigram lookups. Add -O2 unless the interpreter's flags or CFLAGS/CXXFLAGS already set a level, so builds that use -O3 keep it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The abi3 wheel already covers 3.15; free-threaded 3.15 gets its own cp315t wheel. The test matrix gains 3.15 and 3.15t. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Python 3.9 reached its end of life in October 2025; cffi 2.1 and setup-python on Ubuntu 26.04 no longer support it. The abi3 wheel becomes cp310-abi3. cffi 2.0 is the first version that runs free-threaded Python without the GIL; on PyPy, whose cffi is built in, the requirement installs only metadata. The test matrix is BinPackage's: CPython 3.10-3.15, 3.14t, 3.15t, PyPy 3.11 and 3.12. Adds the Free Threading classifier. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
cibuildwheel is pinned: 4.3.1 builds the abi3, cp314t, cp315t and PyPy 8.0 (pp311, pp312) wheels, and 4.2.1 builds pp311 for PyPy 7.3, whose users would otherwise get source builds. ubuntu-26.04-arm builds the Linux aarch64 wheels. A last step checks that every expected wheel was built for every architecture, since cibuildwheel only fails when a selector matches nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
pyproject.toml already declares the packages, package data and
dependencies; setup.py's install_requires was overridden ("install_requires
overwritten in pyproject.toml") and setup_requires is unused under PEP 517.
The cffi requirement now lives in pyproject.toml alone, as in
mideind/BinPackage. The sdist and wheel contents are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cffi releases the GIL around every C call, and a query makes several, so with the GIL more threads only add hand-offs: the 8 threads took 21 s on CPython 3.14 against 3.4 s on 3.14t, most of the suite's run time in the GIL and PyPy jobs. It now takes about 3 s there; free-threaded Python still runs 8 threads over all the queries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On CPython, mmap.close() raises BufferError while any view of the map is alive, and a running query holds such views: close() then failed halfway, with the store's attributes already cleared. It now succeeds, and CPython unmaps the file when the last view is released, so the running query completes correctly. PyPy unmaps at close() regardless, so there a query that is still running can crash: the docstring says so, and close() must still be called only when no other thread is using the instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Prerequisites paragraph now lists the platforms that get wheels (including the new Linux aarch64 ones) instead of the old ARMhf test. The 2.1.0 entry is marked unreleased; the version bump and the date come with the release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pushes to other branches were tested twice, once for the push and once for their pull request; they are now tested through the pull request only. Ruff runs in the 3.10 job only, as in mideind/BinPackage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…queries cffi releases the GIL around every C call and a query makes several, so on Python with the GIL busy threads mostly hand the GIL to each other: 8 threads took 25 times as long as one thread for the same queries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vthorsteinsson
approved these changes
Oct 16, 2026
vthorsteinsson
left a comment
Member
There was a problem hiding this comment.
Reviewed against mideind/BinPackage's free-threading setup; parity confirmed, wheels dry run (2.1.0-test1) green on all platforms. Thanks!
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the problem?
Icegrams didn't build on free-threaded Python. Its supported versions and wheels had also drifted from mideind/BinPackage:
What is the solution?
abi3. cffi 2.x keeps the GIL off.test_threads.pyhas threads query oneNgramsand compares the results with serial ones: 8 threads over all queries on free-threaded Python, 2 threads with half the queries each when the GIL is on.-O2safeguard:trie.cppis built with-O2when the interpreter records no optimization level. Gentoo's Python records none, sotrie.cppran at-O0, 2.6× slower.cp310-abi3wheel. Python 3.9 has been end of life since October 2025.cffi>=2.0.0, declared inpyproject.tomlonly:setup.pykeeps just what pyproject can't express (cffi_modules,zip_safe, the abi3 option).cp314t,cp315t, PyPy 7.3 (pp73), PyPy 3.12 and Linux aarch64 wheels.close(): on CPython it no longer fails halfway withBufferErrorwhen a query in another thread still holds the memory map; the map is unmapped when that query is done. PyPy unmaps atclose()regardless, soclose()must still be called only when no other thread uses the instance.masteronly (other branches through their pull requests, so jobs no longer run twice), and ruff runs once, in the 3.10 job.Ngramscan be shared by threads. Callclose()only when no other thread is using it.No locks were needed. The C++ trie only reads the memory map, and the one lazily computed value is computed the same way by any thread.
How was this tested?
wheels.ymlon the test tag2.1.0-test1built all 30 expected wheels (6 kinds × Linux x86_64 and aarch64, macOS x86_64 and arm64, Windows), and each passed its import and GIL test. The publish job was skipped. The Linux x86_64 build was also reproduced locally with the same cibuildwheel versions.setup.pybuilds the same sdist and wheel contents as before.close()failure on CPython without the fix.logprobon real text, 8 threads sharing oneNgramson 3.14t, against 8 processes on the GIL build: 139k lookups/s each. One worker does 26k.The
pypienvironment now only accepts tags of the form*.*.*, as in BinPackage.Releasing this should be 2.1.0, since it drops Python 3.9; the version bump and the changelog date come with the release, possibly together with #11. Users on 3.9 keep 2.0.0.
🤖 Generated with Claude Code