Uh oh!
There was an error while loading. Please reload this page.
Publish native wheels for Python 3.9-3.14 - #10
Conversation
Published wheels were tagged cp312 only, so every other interpreter fell back to the sdist. That path requires a Rust toolchain and OpenSSL dev headers, and on Python 3.14 it cannot succeed at all because PyO3 0.23 supports at most 3.13. Declared metadata (requires-python >=3.9) invited that attempt. Build the extension against CPython's stable ABI via pyo3/abi3-py39, so one cp39-abi3 wheel per platform serves 3.9 and every later version. Verified: a wheel built on CPython 3.12 installs and runs the repository smoke orchestration to completion on 3.9.25, 3.12.13, and 3.14.7. The published 0.1.27 release resolves to "no usable wheels" on 3.9 and 3.14. The companion .github/workflows/publish.yml change (widen both smoke matrices to 3.9/3.12/3.13/3.14 and fail the build on any non-abi3 wheel) is attached to the pull request instead of committed here: this App has no GitHub Actions `workflows` permission, so the push was rejected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Verification detail for the abi3 change, since "it should work" is not evidence.
Build, from this branch's Cargo.toml on CPython 3.12.13 (maturin 1.14.1, Debian 12, cargo 1.97.1):
🐍 Found CPython 3.12 at /root/.local/bin/python3.12
🔗 Found pyo3 bindings with abi3-py3.9 support
📦 Built wheel for abi3 Python ≥ 3.9 to duroxide-0.1.27-cp39-abi3-manylinux_2_34_x86_64.whl
Wheel metadata:
Tag: cp39-abi3-manylinux_2_34_x86_64
duroxide/_duroxide.abi3.so
The extension module is _duroxide.abi3.so, not _duroxide.cpython-312-x86_64-linux-gnu.so — that filename change is the whole fix.
Consumer test. That one wheel installed into a fresh venv per interpreter, then the repository's own ci/smoke/smoke.py run unmodified — SQLite provider, registered activity, generator orchestration, started instance, awaited result:
[smoke] python=3.9.25 platform=linux arch=x86_64
[smoke] OK status=Completed output=Hello, World!
[smoke] python=3.12.13 platform=linux arch=x86_64
[smoke] OK status=Completed output=Hello, World!
[smoke] python=3.14.7 platform=linux arch=x86_64
[smoke] OK status=Completed output=Hello, World!
3.14.7 is the version from the issue report. It now works from a wheel, with no Rust toolchain in the consumer venv.
Control, same pod, same interpreters, against the currently published release:
$ pip install --only-binary :all: duroxide==0.1.27 # py3.14
× No solution found: duroxide==0.1.27 has no usable wheels
$ pip install --only-binary :all: duroxide==0.1.27 # py3.9
× No solution found: duroxide==0.1.27 has no usable wheels
Equivalence. The build tree was the 0.1.27 sdist with only the Cargo.toml pyo3 feature line changed. All seven src/*.rs files are byte-identical (sha256) to this branch's base commit 5941a8d, so the result reflects this repository's code.
Not tested here: macOS and Windows wheels, and manylinux_2_28 specifically (this build produced manylinux_2_34 from a Debian 12 container rather than the CI manylinux image). Those are exercised by the workflow matrix once the CI patch in the description is applied. abi3 tagging is a property of the pyo3 build configuration and is platform-independent.
One unrelated observation: the runtime emits retryable database is locked warnings from the SQLite provider at startup on every interpreter, including 3.12, before settling. Pre-existing, identical across versions, unrelated to this change — noted only so it isn't mistaken for abi3 fallout.
Ofek Lev (ofek)
commented
Aug 14, 2026
Why abi3 wheels? You can just continue releasing a wheel per target which would remove the need for that pyo3 bump and theoretically improve performance. |
Pino de Candia (pinodeca)
commented
Aug 14, 2026
Ofek Lev (@ofek) Thanks for challenging the ABI3 choice. I revisited the packaging design and changed this PR to native, interpreter-specific wheels. The revised branch now:
The 30 build-and-smoke jobs are running now. Would you be willing to review the revised approach, particularly whether this matrix matches what you had in mind and whether you see a better way to manage the native assets? |
@waldemort-auto[bot] please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
|
Update: native wheels instead of ABI3
Updated 2026-08-14. Following feedback from Ofek Lev (@ofek), this PR now preserves the full CPython API and interpreter-specific optimizations by building one native wheel for every supported Python/platform pair.
The native-wheel pivot is isolated in commit
0240279. If the live CI run shows that 30 wheels or the release workload is unmanageable, reverting that single commit returns the branch to the tested ABI3 implementation atd8c5741before merge.Fixes#6.
Problem
Published releases currently contain five
cp312-cp312wheels, one for each platform/architecture. Every other declared Python version falls back to the sdist, which requires a Rust toolchain and OpenSSL development headers. Python 3.14 cannot build the existing PyO3 0.23 source at all because that release supports at most Python 3.13.The package declares Python 3.9 and later, but effective binary support is Python 3.12 only. Both release smoke matrices also tested only 3.12, so CI did not catch the gap.
Approach
Publish native wheels for each supported CPython minor from 3.9 through 3.14 across the existing five platform targets:
That produces 30 native wheels plus one sdist per release. Native wheels avoid the Limited API restrictions and allow PyO3/CPython to use exact-interpreter optimizations.
Implementation
Python::with_giltoPython::attachandpy.allow_threadstopy.detach.gil_used = true; free-threaded Python builds are not included in this PR.#[pyclass]types.--only-binary :all:and runs the full SQLite orchestration smoke before uploading the artifact.CI shape
The pre-publish workflow uses 30 combined build-and-smoke jobs, not separate build and smoke matrices. A single verification job checks the complete 30-wheel artifact set. The 30 registry smoke jobs run only after a release is published.
This keeps the asset count explicit while avoiding a duplicate 30-job pre-publish smoke stage.
Local verification
Validated on CPython 3.12/Linux x86_64:
maturin build --releaseproducedduroxide-0.1.27-cp312-cp312-linux_x86_64.whl.ci/smoke/smoke.pycompleted a real orchestration withHello, World!output.cargo clippy --all-targets -- -D warningspassed.The live PR workflow is the final validation for interpreter availability, cross-platform wheel tags, runner load, and whether the 30-asset release model is operationally acceptable.
Rollback option
Before merge, the ABI3 design remains available at
d8c5741. Revert the native pivot with:That restores five
cp39-abi3platform wheels and the ABI3 smoke/tag guard without reconstructing the earlier patch.