From 293401d8cecdf9f46c6f05e84d718395667f9a2c Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 21:27:13 +0900 Subject: [PATCH 1/8] ci(release): unblock v0.23 release workflows Two release-blocker fixes that surfaced when tagging v0.23.1rc0: 1. node-release.yml: napi-rs/cli v3 (which we adopted in #2034) renamed the cross-compile flag from `--zig` to `--cross-compile` (or `-x`). The build steps still passed `--zig`, so every linux-musl / linux-aarch64 / armv7 entry failed with Unknown Syntax Error: Unsupported option name ("--zig"). Replace `--zig` with `--cross-compile` everywhere (build commands + the `contains(...)` gate on the zig setup step). 2. python-release.yml: drop 3.14t from the windows-11-arm matrix entry. actions/python-versions currently ships a broken `python-3.14.4-win32-arm64-freethreaded` package (0-byte python.exe, pip install fails with `ModuleNotFoundError: encodings`). Keep the regular 3.14 arm64 build; 3.14t arm64 windows can return when the upstream package is fixed. --- .github/workflows/node-release.yml | 12 ++++++------ .github/workflows/python-release.yml | 10 ++++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index 8ef097d5b..c6c1db1dc 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -46,16 +46,16 @@ jobs: strip *.node - host: ubuntu-latest target: x86_64-unknown-linux-musl - build: yarn build --target x86_64-unknown-linux-musl --zig + build: yarn build --target x86_64-unknown-linux-musl --cross-compile - host: ubuntu-latest target: aarch64-unknown-linux-gnu - build: yarn build --target aarch64-unknown-linux-gnu --zig + build: yarn build --target aarch64-unknown-linux-gnu --cross-compile - host: ubuntu-latest target: aarch64-unknown-linux-musl - build: yarn build --target aarch64-unknown-linux-musl --zig + build: yarn build --target aarch64-unknown-linux-musl --cross-compile - host: ubuntu-latest target: armv7-unknown-linux-gnueabihf - build: yarn build --target armv7-unknown-linux-gnueabihf --zig + build: yarn build --target armv7-unknown-linux-gnueabihf --cross-compile - host: ubuntu-latest target: aarch64-linux-android build: yarn build --target aarch64-linux-android @@ -88,7 +88,7 @@ jobs: run: yarn install --immutable - name: Setup zig - if: ${{ !matrix.settings.docker && contains(matrix.settings.build, '--zig') }} + if: ${{ !matrix.settings.docker && contains(matrix.settings.build, '--cross-compile') }} uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1 with: # Pin — without a version the action installs zig master (nightly) @@ -98,7 +98,7 @@ jobs: version: 0.16.0 - name: Verify zig - if: ${{ !matrix.settings.docker && contains(matrix.settings.build, '--zig') }} + if: ${{ !matrix.settings.docker && contains(matrix.settings.build, '--cross-compile') }} run: zig version && which zig - name: Build native (host) diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index 772e857c1..88b9ecc34 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -55,10 +55,12 @@ jobs: ls: dir target: aarch64 python-architecture: arm64 - python-install: | - 3.14 - 3.14t - interpreter: 3.14 3.14t + # 3.14t arm64-freethreaded is currently broken upstream: + # actions/python-versions ships a 0-byte python.exe so pip + # install fails with `ModuleNotFoundError: encodings`. Drop + # 3.14t here until the upstream package is fixed. + python-install: "3.14" + interpreter: "3.14" # - os: windows # ls: dir # target: aarch64 From 47f126f0c9a07985f74ac6b461aaea14617e9c0a Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 21:36:23 +0900 Subject: [PATCH 2/8] ci(python-release): build proper non-abi3 wheels for 3.14t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pre-existing matrix had `interpreter: "3.14 3.14t"` on most entries, which made maturin build a single wheel per cell intended to serve both interpreters. With the project's `abi3` cargo feature enabled by default that wheel was abi3-compiled — fine for 3.14, but 3.14t can't load abi3 extensions (no limited API on free-threaded Python), so the published cp314t wheels would fail to import. Split into two flavors via a discriminator: - All existing entries set `interpreter: "3.14"` only (so the abi3 wheel they produce serves 3.10–3.14 cleanly). - New `flavor: ft` include: entries for the platforms we want 3.14t wheels on (linux x86_64/aarch64 manylinux+musllinux, macos x86_64/ aarch64, windows x86_64). Each passes `extra-build-args: --no-default-features --features pyo3/extension-module` which drops the abi3 cargo feature so maturin produces a proper cp314t-tagged, non-abi3 wheel that actually loads on free-threaded Python. - Base matrix gets `flavor: [abi3]` so the `flavor: ft` includes create new matrix cells instead of merging with the abi3 combos. - Artifact name suffixed with `${{ matrix.flavor || 'abi3' }}` so the abi3 and ft wheels for the same os/target/manylinux don't collide on upload-artifact. - Skipped 3.14t for windows-11-arm because the upstream 3.14t arm64 package is currently broken (0-byte python.exe). Skipped for the niche linux targets (i686, armv7, ppc64le, s390x) too — easy to add later. Job name now includes the interpreter for log readability. --- .github/workflows/python-release.yml | 91 +++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 16 deletions(-) diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index 88b9ecc34..9b4e9f8ce 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -19,7 +19,7 @@ jobs: working-directory: ./bindings/python build: - name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }}) + name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }} - ${{ matrix.interpreter || '3.14' }}) # only run on push to main and on release needs: [lock_exists] if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'Full Build') @@ -29,28 +29,29 @@ jobs: os: [ubuntu, macos, windows] target: [x86_64, aarch64] manylinux: [auto] + # `flavor` discriminates regular abi3 wheels from free-threaded + # (3.14t, non-abi3) wheels so the include: entries below for + # 3.14t create new matrix cells instead of merging with the abi3 + # combos. + flavor: [abi3] include: - os: ubuntu platform: linux - os: windows ls: dir - interpreter: 3.14 3.14t + interpreter: "3.14" - os: windows ls: dir target: x86_64 python-architecture: x64 - python-install: | - 3.14 - 3.14t - interpreter: 3.14 3.14t + python-install: "3.14" + interpreter: "3.14" - os: windows ls: dir target: i686 python-architecture: x86 - python-install: | - 3.14 - 3.14t - interpreter: 3.14 3.14t + python-install: "3.14" + interpreter: "3.14" - os: windows-11-arm ls: dir target: aarch64 @@ -67,7 +68,7 @@ jobs: # interpreter: 3.11 3.12 - os: macos target: aarch64 - interpreter: 3.14 3.14t + interpreter: "3.14" - os: ubuntu platform: linux target: i686 @@ -78,7 +79,7 @@ jobs: - os: ubuntu platform: linux target: armv7 - interpreter: 3.14 3.14t + interpreter: "3.14" # musllinux - os: ubuntu platform: linux @@ -91,11 +92,69 @@ jobs: - os: ubuntu platform: linux target: ppc64le - interpreter: 3.14 3.14t + interpreter: "3.14" - os: ubuntu platform: linux target: s390x - interpreter: 3.14 3.14t + interpreter: "3.14" + + # --- Free-threaded Python 3.14t wheels ------------------------- + # Build without the abi3 cargo feature; 3.14t can't load + # stable-ABI extensions. The `flavor: ft` discriminator forces + # include: to create new matrix cells instead of merging with + # the abi3 entries above. + # windows-11-arm 3.14t is intentionally absent — actions/python- + # versions ships a broken 3.14t arm64 package (see comment on + # the abi3 windows-11-arm entry above). + - os: ubuntu + platform: linux + target: x86_64 + manylinux: auto + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module + - os: ubuntu + platform: linux + target: aarch64 + manylinux: auto + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module + - os: ubuntu + platform: linux + target: x86_64 + manylinux: musllinux_1_1 + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module + - os: ubuntu + platform: linux + target: aarch64 + manylinux: musllinux_1_1 + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module + - os: macos + target: x86_64 + manylinux: auto + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module + - os: macos + target: aarch64 + manylinux: auto + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module + - os: windows + target: x86_64 + manylinux: auto + ls: dir + python-architecture: x64 + python-install: "3.14t" + flavor: ft + interpreter: "3.14t" + extra-build-args: --no-default-features --features pyo3/extension-module exclude: - os: windows target: aarch64 @@ -130,7 +189,7 @@ jobs: working-directory: ./bindings/python manylinux: ${{ matrix.manylinux || 'auto' }} container: ${{ matrix.container }} - args: --release --out dist --interpreter ${{ matrix.interpreter || '3.14 3.14t' }} ${{ matrix.extra-build-args }} + args: --release --out dist --interpreter ${{ matrix.interpreter || '3.14' }} ${{ matrix.extra-build-args }} rust-toolchain: stable sccache: false docker-options: -e CI @@ -143,7 +202,7 @@ jobs: - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: pypi_files-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux }} + name: pypi_files-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux }}-${{ matrix.flavor || 'abi3' }} path: ./bindings/python/dist build-sdist: name: build sdist From 8f9e0ebf513905802914eb5b151b5cbc94eb697e Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 21:38:21 +0900 Subject: [PATCH 3/8] ci(python-release): collapse 3.14t entries to one line each MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 3.14t matrix cells only differ from their abi3 siblings on three fields: `flavor`, `interpreter`, and `extra-build-args`. The latter two are fully determined by the first, so derive them in the maturin invocation: args: >- --release --out dist --interpreter ${{ matrix.flavor == 'ft' && '3.14t' || matrix.interpreter || '3.14' }} ${{ matrix.flavor == 'ft' && '--no-default-features --features pyo3/extension-module' || '' }} Each 3.14t cell is now a single-line YAML flow entry — the only thing the matrix says about it is `flavor: ft`. Drops ~30 lines of repetition without changing behaviour. --- .github/workflows/python-release.yml | 77 ++++++++-------------------- 1 file changed, 20 insertions(+), 57 deletions(-) diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index 9b4e9f8ce..cc7a20e31 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -99,62 +99,19 @@ jobs: interpreter: "3.14" # --- Free-threaded Python 3.14t wheels ------------------------- - # Build without the abi3 cargo feature; 3.14t can't load - # stable-ABI extensions. The `flavor: ft` discriminator forces - # include: to create new matrix cells instead of merging with - # the abi3 entries above. - # windows-11-arm 3.14t is intentionally absent — actions/python- - # versions ships a broken 3.14t arm64 package (see comment on - # the abi3 windows-11-arm entry above). - - os: ubuntu - platform: linux - target: x86_64 - manylinux: auto - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module - - os: ubuntu - platform: linux - target: aarch64 - manylinux: auto - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module - - os: ubuntu - platform: linux - target: x86_64 - manylinux: musllinux_1_1 - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module - - os: ubuntu - platform: linux - target: aarch64 - manylinux: musllinux_1_1 - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module - - os: macos - target: x86_64 - manylinux: auto - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module - - os: macos - target: aarch64 - manylinux: auto - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module - - os: windows - target: x86_64 - manylinux: auto - ls: dir - python-architecture: x64 - python-install: "3.14t" - flavor: ft - interpreter: "3.14t" - extra-build-args: --no-default-features --features pyo3/extension-module + # The `flavor: ft` field is the only thing that varies — the + # 3.14t-specific `interpreter` and `--no-default-features + # --features pyo3/extension-module` (drop abi3, since 3.14t + # can't load limited-API extensions) are derived from `flavor` + # in the maturin invocation below. windows-11-arm 3.14t is + # intentionally absent — see the abi3 windows-11-arm entry. + - { os: ubuntu, platform: linux, target: x86_64, manylinux: auto, flavor: ft } + - { os: ubuntu, platform: linux, target: aarch64, manylinux: auto, flavor: ft } + - { os: ubuntu, platform: linux, target: x86_64, manylinux: musllinux_1_1, flavor: ft } + - { os: ubuntu, platform: linux, target: aarch64, manylinux: musllinux_1_1, flavor: ft } + - { os: macos, target: x86_64, manylinux: auto, flavor: ft } + - { os: macos, target: aarch64, manylinux: auto, flavor: ft } + - { os: windows, ls: dir, target: x86_64, manylinux: auto, python-architecture: x64, python-install: "3.14t", flavor: ft } exclude: - os: windows target: aarch64 @@ -189,7 +146,13 @@ jobs: working-directory: ./bindings/python manylinux: ${{ matrix.manylinux || 'auto' }} container: ${{ matrix.container }} - args: --release --out dist --interpreter ${{ matrix.interpreter || '3.14' }} ${{ matrix.extra-build-args }} + # `flavor=ft` builds drop the abi3 cargo feature so the resulting + # wheel is non-abi3 (free-threaded Python can't load limited-API + # extensions). `flavor=abi3` builds use defaults. + args: >- + --release --out dist + --interpreter ${{ matrix.flavor == 'ft' && '3.14t' || matrix.interpreter || '3.14' }} + ${{ matrix.flavor == 'ft' && '--no-default-features --features pyo3/extension-module' || '' }} rust-toolchain: stable sccache: false docker-options: -e CI From 852cfd7fc87122b923221caf5f58aaacb35b4dcc Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 21:56:35 +0900 Subject: [PATCH 4/8] ci(node-release): use lipo directly for the universal macOS binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit napi-rs/cli v3 renamed `napi universal` -> `napi universalize` and dropped the `--dir` flag — it now expects per-target .node files in the standard `npm//` layout that `napi artifacts` produces, not in a flat directory. Rather than insert a `napi artifacts` step + reorganize, just call `lipo` directly. The two darwin .node files we already download into ./artifacts have known names; combining them into the universal binary is one line. That's exactly what `napi universal` was wrapping internally. --- .github/workflows/node-release.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index c6c1db1dc..ab877edcc 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -155,7 +155,14 @@ jobs: path: ./bindings/node/artifacts - name: Combine into universal binary working-directory: ./bindings/node - run: npx napi universal --dir ./artifacts + # napi-rs/cli v3 renamed `napi universal` -> `napi universalize` + # and dropped `--dir`; it now expects the npm// layout + # populated by `napi artifacts`. Cheaper to lipo directly — that's + # exactly what the wrapper does internally. + run: | + lipo -create -output ${{ env.APP_NAME }}.darwin-universal.node \ + artifacts/${{ env.APP_NAME }}.darwin-x64.node \ + artifacts/${{ env.APP_NAME }}.darwin-arm64.node - name: Upload universal artifact uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 with: From c953a670725d0b6c3643b1d14013b627f674cf3c Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 22:00:56 +0900 Subject: [PATCH 5/8] bindings/python: align Python version metadata with abi3-py310 baseline The crate is built with `abi3-py310`, so 3.10 is the actual minimum the wheels can load on. Update the PyPI metadata accordingly: - requires-python: ">=3.9" -> ">=3.10" - drop the "Python :: 3.9" trove classifier - add the "Python :: 3.14" trove classifier This stops pip from offering the wheel to 3.9 users (where it would fail to import) and makes the PyPI page accurate. --- bindings/python/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index c4354c9e4..e21434a02 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "tokenizers" -requires-python = ">=3.9" +requires-python = ">=3.10" authors = [ { name = "Nicolas Patry", email = "patry.nicolas@protonmail.com" }, { name = "Anthony Moi", email = "anthony@huggingface.co" }, @@ -13,11 +13,11 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3 :: Only", "Topic :: Scientific/Engineering :: Artificial Intelligence", ] From 0fe840d91af0ea0ce82924148652254e6ff38d62 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 22:07:02 +0900 Subject: [PATCH 6/8] ci(node-release): create missing npm/ dirs before artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `yarn artifacts` (napi-cli v3 `napi artifacts`) writes each per-target .node file into `npm//`. The repo has hand-written templates for most triples but darwin-universal was added to `napi.targets` without one, so the publish step failed with: ENOENT: no such file or directory, open '.../bindings/node/npm/darwin-universal/tokenizers.darwin-universal.node' Add `napi create-npm-dirs` before `yarn artifacts` — it scans `napi.targets` and creates any missing dirs (with a generated package.json) from scratch. Idempotent for triples that already have hand-written templates. --- .github/workflows/node-release.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index ab877edcc..67a76207e 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -195,6 +195,15 @@ jobs: uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: path: ./bindings/node/artifacts + - name: Create missing npm/ dirs + # `yarn artifacts` (napi artifacts) writes each `.node` file into + # `npm//`. Some triples (e.g. darwin-universal) have no + # checked-in template dir, so without this step the artifacts + # command fails with ENOENT. `create-npm-dirs` populates anything + # missing from `napi.targets` in package.json. + working-directory: ./bindings/node + run: npx napi create-npm-dirs + - name: Move artifacts working-directory: ./bindings/node run: yarn artifacts From ae74b5cf586daf85a92d11f4c10229a06a86d5bf Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 22:15:24 +0900 Subject: [PATCH 7/8] ci(node-release): skip publish on rc tags + grant contents=write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues stacked when v0.23.1rc0 hit the publish job: 1. `napi prepublish` POSTs to /repos/.../releases to create a GitHub Release and got 403 — the workflow's default GITHUB_TOKEN has only `contents: read`, but creating a release needs `contents: write`. Bump the publish-job permission. 2. `napi prepublish` then runs `npm publish` for each per-platform sub-package; modern npm refuses to auto-route a `0.23.1-rc0` version to `latest` and demands an explicit `--tag`. Rather than wire up `--tag rc` in every sub-publish (and risk an rc landing on `latest` by accident), gate the entire publish job on `!contains(github.ref, 'rc')`. Matches the existing pattern in rust-release.yml. rc tags still run the build + universal-macOS matrix end-to-end — they just skip the registry push, so they're useful for verifying the cross-compile / lipo / artifact-collection flow before a real release. --- .github/workflows/node-release.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index 67a76207e..53a7948d8 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -171,8 +171,16 @@ jobs: if-no-files-found: error publish: + # Skip the npm publish step on rc tags — `napi prepublish` would try + # to create a GitHub release and call `npm publish` for each + # per-platform sub-package, both of which need stable-version / + # write-permission setup we only want on real releases. rc tags still + # exercise the build + universal-macOS jobs (so the matrix is tested + # end-to-end), they just don't push to the registry. + if: ${{ !contains(github.ref, 'rc') }} permissions: - contents: read + # `napi prepublish` creates a GitHub Release; needs contents=write. + contents: write id-token: write name: Publish runs-on: ubuntu-latest From 3b030fdf3957b5fa8a20fec15ead3ccf223b1595 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Apr 2026 22:35:12 +0900 Subject: [PATCH 8/8] =?UTF-8?q?ci(python-release):=20fix=20ft=20cells=20?= =?UTF-8?q?=E2=80=94=20install=203.14t=20on=20macOS,=20use=20ext-module=20?= =?UTF-8?q?alias,=20name=20from=20flavor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three review fixes folded into one commit: 1. macOS `flavor: ft` cells were missing `python-install: "3.14t"`; setup-python defaulted to 3.14, so maturin's `--interpreter 3.14t` would have failed to find an interpreter. Linux `manylinux`/ `musllinux` ft cells run inside the maturin docker image (which ships 3.14t), so they don't need it. Windows ft already had it. 2. Switch the dropped-feature flag from `pyo3/extension-module` to the project-level `ext-module` feature alias defined in `bindings/python/Cargo.toml`. Less coupled to the dependency name — if the feature wiring changes (e.g. pyo3 renames the feature, or we add wrapper logic to ext-module), the workflow doesn't have to move with it. 3. Job-name `interpreter` segment now derives from `flavor`, so 3.14t cells display as `3.14t` instead of the misleading `3.14` they got from the unset `matrix.interpreter`. --- .github/workflows/python-release.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml index cc7a20e31..6a8996e36 100644 --- a/.github/workflows/python-release.yml +++ b/.github/workflows/python-release.yml @@ -19,7 +19,7 @@ jobs: working-directory: ./bindings/python build: - name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }} - ${{ matrix.interpreter || '3.14' }}) + name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }} - ${{ matrix.flavor == 'ft' && '3.14t' || matrix.interpreter || '3.14' }}) # only run on push to main and on release needs: [lock_exists] if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'Full Build') @@ -99,18 +99,20 @@ jobs: interpreter: "3.14" # --- Free-threaded Python 3.14t wheels ------------------------- - # The `flavor: ft` field is the only thing that varies — the - # 3.14t-specific `interpreter` and `--no-default-features - # --features pyo3/extension-module` (drop abi3, since 3.14t - # can't load limited-API extensions) are derived from `flavor` - # in the maturin invocation below. windows-11-arm 3.14t is - # intentionally absent — see the abi3 windows-11-arm entry. + # `flavor: ft` switches the build to non-abi3 (`--no-default-features + # --features ext-module`) and `--interpreter 3.14t`, derived from + # `flavor` in the maturin invocation below. linux container builds + # (manylinux/musllinux) get 3.14t from the docker image, so + # `python-install` is unset for those; macOS/windows host builds + # need it set explicitly so setup-python actually installs 3.14t. + # windows-11-arm 3.14t is intentionally absent — see the abi3 + # windows-11-arm entry above (upstream-broken package). - { os: ubuntu, platform: linux, target: x86_64, manylinux: auto, flavor: ft } - { os: ubuntu, platform: linux, target: aarch64, manylinux: auto, flavor: ft } - { os: ubuntu, platform: linux, target: x86_64, manylinux: musllinux_1_1, flavor: ft } - { os: ubuntu, platform: linux, target: aarch64, manylinux: musllinux_1_1, flavor: ft } - - { os: macos, target: x86_64, manylinux: auto, flavor: ft } - - { os: macos, target: aarch64, manylinux: auto, flavor: ft } + - { os: macos, target: x86_64, manylinux: auto, flavor: ft, python-install: "3.14t" } + - { os: macos, target: aarch64, manylinux: auto, flavor: ft, python-install: "3.14t" } - { os: windows, ls: dir, target: x86_64, manylinux: auto, python-architecture: x64, python-install: "3.14t", flavor: ft } exclude: - os: windows @@ -152,7 +154,7 @@ jobs: args: >- --release --out dist --interpreter ${{ matrix.flavor == 'ft' && '3.14t' || matrix.interpreter || '3.14' }} - ${{ matrix.flavor == 'ft' && '--no-default-features --features pyo3/extension-module' || '' }} + ${{ matrix.flavor == 'ft' && '--no-default-features --features ext-module' || '' }} rust-toolchain: stable sccache: false docker-options: -e CI