Skip to content

Commit f66af72

Browse files
build: Publish abi3t wheels for Python 3.15+
Signed-off-by: Edgar Ramírez Mondragón <edgarrm358@gmail.com>
1 parent 878e5d3 commit f66af72

5 files changed

Lines changed: 34 additions & 15 deletions

File tree

‎.github/actions/build-wheel/action.yml‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ inputs:
2828
required: false
2929
default: ""
3030
python-tag:
31-
description: "abi3 (covers 3.10..3.14 GIL builds) or a free-threaded interpreter such as 3.13t / 3.14t"
31+
description: "abi3 (covers 3.10..3.14 GIL builds), abi3t (covers 3.15+, GIL and free-threaded; built with 3.15t), or a version-specific free-threaded interpreter such as 3.14t"
3232
required: true
3333
build-mode:
3434
description: "release or debug"
@@ -67,6 +67,14 @@ runs:
6767
BUILD_ARGS="--features ${FEATURES}"
6868
else
6969
# Free-threaded build: disable abi3, force mimalloc back in, pin interpreter.
70+
# `abi3t` builds a PEP 803 wheel (cp315-abi3t), importable on 3.15+
71+
# GIL and free-threaded builds, using the 3.15 free-threaded
72+
# interpreter. Older free-threaded tags get version-specific wheels.
73+
ABI_FEATURE=""
74+
if [ "$TAG" = "abi3t" ]; then
75+
ABI_FEATURE="abi3t,"
76+
TAG="3.15t"
77+
fi
7078
if [ "${RUNNER_OS:-}" = "Windows" ]; then
7179
# Windows free-threaded builds ship as `python.exe` (no `tN`
7280
# suffix). Resolve sys.executable so the path is independent of
@@ -83,7 +91,7 @@ runs:
8391
else
8492
INTERP="python${TAG}"
8593
fi
86-
BUILD_ARGS="--no-default-features --features mimalloc,${FEATURES} --interpreter ${INTERP}"
94+
BUILD_ARGS="--no-default-features --features mimalloc,${ABI_FEATURE}${FEATURES} --interpreter ${INTERP}"
8795
fi
8896
if [ "${{ inputs.build-mode }}" = "release" ]; then
8997
BUILD_ARGS="--release --strip ${BUILD_ARGS}"
@@ -98,7 +106,7 @@ runs:
98106
with:
99107
target: ${{ inputs.target }}
100108
manylinux: ${{ inputs.manylinux }}
101-
maturin-version: "1.13.3"
109+
maturin-version: "1.15.0"
102110
args: ${{ steps.args.outputs.args }}
103111
rustup-components: rust-std
104112

@@ -107,4 +115,4 @@ runs:
107115
shell: bash
108116
# Use `uvx` so maturin is available even when `uv sync` was skipped
109117
# (free-threaded matrix entries don't pre-populate the project venv).
110-
run: uvx maturin@1.13.3 build ${{ steps.args.outputs.args }}
118+
run: uvx maturin@1.15.0 build ${{ steps.args.outputs.args }}

‎.github/workflows/build.yml‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ jobs:
144144
strategy:
145145
fail-fast: false
146146
matrix:
147-
python-tag: ["abi3", "3.14t"]
147+
python-tag: ["abi3", "3.14t", "abi3t"]
148148
steps:
149149
- uses: actions/checkout@v7
150150

@@ -235,7 +235,7 @@ jobs:
235235
strategy:
236236
fail-fast: false
237237
matrix:
238-
python-tag: ["abi3", "3.14t"]
238+
python-tag: ["abi3", "3.14t", "abi3t"]
239239
steps:
240240
- uses: actions/checkout@v7
241241

@@ -298,7 +298,7 @@ jobs:
298298
fail-fast: false
299299
matrix:
300300
os: [macos-latest, windows-latest]
301-
python-tag: ["abi3", "3.14t"]
301+
python-tag: ["abi3", "3.14t", "abi3t"]
302302
steps:
303303
- uses: actions/checkout@v7
304304

@@ -321,7 +321,8 @@ jobs:
321321
if: matrix.python-tag != 'abi3'
322322
uses: actions/setup-python@v7
323323
with:
324-
python-version: ${{ matrix.python-tag }}
324+
# abi3t wheels are built with the 3.15 free-threaded interpreter.
325+
python-version: ${{ matrix.python-tag == 'abi3t' && '3.15' || matrix.python-tag }}
325326
freethreaded: true
326327

327328
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7
@@ -381,7 +382,7 @@ jobs:
381382
strategy:
382383
fail-fast: false
383384
matrix:
384-
python-tag: ["abi3", "3.14t"]
385+
python-tag: ["abi3", "3.14t", "abi3t"]
385386
steps:
386387
- uses: actions/checkout@v7
387388

@@ -404,7 +405,8 @@ jobs:
404405
if: matrix.python-tag != 'abi3'
405406
uses: actions/setup-python@v7
406407
with:
407-
python-version: ${{ matrix.python-tag }}
408+
# abi3t wheels are built with the 3.15 free-threaded interpreter.
409+
python-version: ${{ matrix.python-tag == 'abi3t' && '3.15' || matrix.python-tag }}
408410
freethreaded: true
409411

410412
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7

‎.github/workflows/test.yml‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
# under the License.
1717

1818
# Reusable workflow for running tests.
19-
# Single matrix covers both GIL (abi3 wheel) and free-threaded
20-
# (per-interpreter wheels) builds.
19+
# Single matrix covers GIL (abi3 wheel), free-threaded (per-interpreter
20+
# wheels) and 3.15+ (abi3t wheel, loadable on both GIL and free-threaded
21+
# builds) interpreters.
2122

2223
name: Test
2324

@@ -43,8 +44,12 @@ jobs:
4344
- { python-version: "3.12", wheel-tag: "abi3", freethreaded: false }
4445
- { python-version: "3.13", wheel-tag: "abi3", freethreaded: false }
4546
- { python-version: "3.14", wheel-tag: "abi3", freethreaded: false }
46-
# Free-threaded builds — one wheel per interpreter.
47+
- { python-version: "3.15", wheel-tag: "abi3", freethreaded: false }
48+
# The abi3t wheel (PEP 803) loads on both GIL and free-threaded 3.15+.
49+
- { python-version: "3.15", wheel-tag: "abi3t", freethreaded: false }
50+
# Free-threaded builds — one wheel per interpreter (abi3t covers 3.15+).
4751
- { python-version: "3.14t", wheel-tag: "3.14t", freethreaded: true }
52+
- { python-version: "3.15t", wheel-tag: "abi3t", freethreaded: true }
4853
steps:
4954
- uses: actions/checkout@v7
5055

‎crates/core/Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ default = ["mimalloc", "abi3"]
8181
# Mutually exclusive with free-threaded interpreters (cp313t / cp314t); the
8282
# free-threaded wheel build must pass --no-default-features.
8383
abi3 = ["pyo3/abi3", "pyo3/abi3-py310"]
84+
# PEP 803 stable ABI — single wheel covers Python 3.15+ on both GIL and
85+
# free-threaded builds. Requires a 3.15+ host interpreter and maturin >= 1.14.
86+
# Enable via `--no-default-features` so it is not combined with `abi3`.
87+
abi3t = ["pyo3/abi3t", "pyo3/abi3t-py315"]
8488
protoc = ["datafusion-substrait/protoc"]
8589
substrait = ["dep:datafusion-substrait"]
8690

‎pyproject.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# under the License.
1717

1818
[build-system]
19-
requires = ["maturin>=1.8.1"]
19+
requires = ["maturin>=1.14.0"]
2020
build-backend = "maturin"
2121

2222
[project]
@@ -217,7 +217,7 @@ constraint-dependencies = ["typing-extensions>=4.15.0"]
217217
dev = [
218218
"arro3-core==0.6.5",
219219
"codespell==2.4.1",
220-
"maturin>=1.8.1",
220+
"maturin>=1.14.0",
221221
"nanoarrow==0.8.0",
222222
"numpy>1.25.0;python_version<'3.14'",
223223
"numpy>=2.3.2;python_version>='3.14'",

0 commit comments

Comments
 (0)