Skip to content

Publish native wheels for Python 3.9-3.14 - #10

Open
waldemort-auto[bot] wants to merge 3 commits into
mainfrom
waldemort/abi3-wheels-py39
Open

Publish native wheels for Python 3.9-3.14#10
waldemort-auto[bot] wants to merge 3 commits into
mainfrom
waldemort/abi3-wheels-py39

Conversation

@waldemort-auto

@waldemort-autowaldemort-autoBot commented Aug 13, 2026

Copy link
Copy Markdown

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 at d8c5741 before merge.

Fixes#6.

Problem

Published releases currently contain five cp312-cp312 wheels, 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:

PlatformArchitecture
macOSarm64
macOSx86_64
Linux manylinux 2.28aarch64
Linux manylinux 2.28x86_64
Windowsx86_64

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

  • Upgraded PyO3 from 0.23 to 0.29.2 for native Python 3.14 support.
  • Migrated Python::with_gil to Python::attach and py.allow_threads to py.detach.
  • Declared gil_used = true; free-threaded Python builds are not included in this PR.
  • Added explicit PyO3 conversion policy to cloned #[pyclass] types.
  • Expanded release builds to the 30 Python/platform combinations.
  • Each build job installs its own wheel with --only-binary :all: and runs the full SQLite orchestration smoke before uploading the artifact.
  • Added a verifier requiring exactly one native wheel for every expected CPython ABI/platform tuple before publication.
  • Expanded post-publish registry smoke to all 30 combinations.
  • Removed sdist fallback from local and registry smoke tests so a missing wheel fails closed.
  • Updated architecture and contributor guidance for PyO3 0.29.

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 --release produced duroxide-0.1.27-cp312-cp312-linux_x86_64.whl.
  • The built wheel imported successfully outside the repository.
  • ci/smoke/smoke.py completed a real orchestration with Hello, World! output.
  • cargo clippy --all-targets -- -D warnings passed.
  • actionlint 1.7.12 passed against the release workflow.
  • The workflow expands to 12 macOS builds, 12 Linux builds, 6 Windows builds, and 30 release-only registry smoke jobs.
  • The artifact verifier accepts the exact 30-wheel set and rejects incomplete sets.

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:

git revert 0240279

That restores five cp39-abi3 platform wheels and the ABI3 smoke/tag guard without reconstructing the earlier patch.

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>

@waldemort-autowaldemort-autoBot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown

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.

@pinodecaPino de Candia (pinodeca) changed the title Build abi3 wheels so the SDK installs on Python 3.9+Publish native wheels for Python 3.9-3.14Aug 14, 2026
@pinodeca

Copy link
Copy Markdown
Contributor

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:

  • upgrades PyO3 to 0.29.2 and removes abi3-py39;
  • builds cp39-cp39 through cp314-cp314 for all five existing platform/architecture targets (30 wheels total);
  • runs the full orchestration smoke in each build job with --only-binary :all:;
  • verifies the exact 30-wheel ABI/platform set before publishing; and
  • keeps the whole native pivot in one commit so we can revert to the prior ABI3 implementation if the asset count or CI load proves unreasonable.

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?

@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

@waldemort-auto[bot] please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"
Contributor License Agreement

Contribution License Agreement

This Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
and conveys certain license rights to Microsoft Corporation and its affiliates (“Microsoft”) for Your
contributions to Microsoft open source projects. This Agreement is effective as of the latest signature
date below.

  1. Definitions.
    “Code” means the computer software code, whether in human-readable or machine-executable form,
    that is delivered by You to Microsoft under this Agreement.
    “Project” means any of the projects owned or managed by Microsoft and offered under a license
    approved by the Open Source Initiative (www.opensource.org).
    “Submit” is the act of uploading, submitting, transmitting, or distributing code or other content to any
    Project, including but not limited to communication on electronic mailing lists, source code control
    systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of
    discussing and improving that Project, but excluding communication that is conspicuously marked or
    otherwise designated in writing by You as “Not a Submission.”
    “Submission” means the Code and any other copyrightable material Submitted by You, including any
    associated comments and documentation.
  2. Your Submission. You must agree to the terms of this Agreement before making a Submission to any
    Project. This Agreement covers any and all Submissions that You, now or in the future (except as
    described in Section 4 below), Submit to any Project.
  3. Originality of Work. You represent that each of Your Submissions is entirely Your original work.
    Should You wish to Submit materials that are not Your original work, You may Submit them separately
    to the Project if You (a) retain all copyright and license information that was in the materials as You
    received them, (b) in the description accompanying Your Submission, include the phrase “Submission
    containing materials of a third party:” followed by the names of the third party and any licenses or other
    restrictions of which You are aware, and (c) follow any other instructions in the Project’s written
    guidelines concerning Submissions.
  4. Your Employer. References to “employer” in this Agreement include Your employer or anyone else
    for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. If Your
    Submission is made in the course of Your work for an employer or Your employer has intellectual
    property rights in Your Submission by contract or applicable law, You must secure permission from Your
    employer to make the Submission before signing this Agreement. In that case, the term “You” in this
    Agreement will refer to You and the employer collectively. If You change employers in the future and
    desire to Submit additional Submissions for the new employer, then You agree to sign a new Agreement
    and secure permission from the new employer before Submitting those Submissions.
  5. Licenses.
  • Copyright License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license in the
    Submission to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute
    the Submission and such derivative works, and to sublicense any or all of the foregoing rights to third
    parties.
  • Patent License. You grant Microsoft, and those who receive the Submission directly or
    indirectly from Microsoft, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license under
    Your patent claims that are necessarily infringed by the Submission or the combination of the
    Submission with the Project to which it was Submitted to make, have made, use, offer to sell, sell and
    import or otherwise dispose of the Submission alone or with the Project.
  • Other Rights Reserved. Each party reserves all rights not expressly granted in this Agreement.
    No additional licenses or rights whatsoever (including, without limitation, any implied licenses) are
    granted by implication, exhaustion, estoppel or otherwise.
  1. Representations and Warranties. You represent that You are legally entitled to grant the above
    licenses. You represent that each of Your Submissions is entirely Your original work (except as You may
    have disclosed under Section 3). You represent that You have secured permission from Your employer to
    make the Submission in cases where Your Submission is made in the course of Your work for Your
    employer or Your employer has intellectual property rights in Your Submission by contract or applicable
    law. If You are signing this Agreement on behalf of Your employer, You represent and warrant that You
    have the necessary authority to bind the listed employer to the obligations contained in this Agreement.
    You are not expected to provide support for Your Submission, unless You choose to do so. UNLESS
    REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, AND EXCEPT FOR THE WARRANTIES
    EXPRESSLY STATED IN SECTIONS 3, 4, AND 6, THE SUBMISSION PROVIDED UNDER THIS AGREEMENT IS
    PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
    NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
  2. Notice to Microsoft. You agree to notify Microsoft in writing of any facts or circumstances of which
    You later become aware that would make Your representations in this Agreement inaccurate in any
    respect.
  3. Information about Submissions. You agree that contributions to Projects and information about
    contributions may be maintained indefinitely and disclosed publicly, including Your name and other
    information that You submit with Your Submission.
  4. Governing Law/Jurisdiction. This Agreement is governed by the laws of the State of Washington, and
    the parties consent to exclusive jurisdiction and venue in the federal courts sitting in King County,
    Washington, unless no federal subject matter jurisdiction exists, in which case the parties consent to
    exclusive jurisdiction and venue in the Superior Court of King County, Washington. The parties waive all
    defenses of lack of personal jurisdiction and forum non-conveniens.
  5. Entire Agreement/Assignment. This Agreement is the entire agreement between the parties, and
    supersedes any and all prior agreements, understandings or communications, written or oral, between
    the parties relating to the subject matter hereof. This Agreement may be assigned by Microsoft.

Sign up for freeto 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.

Provide wheels compatible with non-3.12 versions of Python

3 participants

@ofek@pinodeca