ci(rust): add an experimental free-threaded (3.14t) wheel lane

This commit is contained in:
Yujong Lee 2026-09-03 14:29:24 -07:00
parent 8bfe009522
commit 6e46ee9df7
2 changed files with 80 additions and 0 deletions

View file

@ -126,3 +126,80 @@ jobs:
- name: Test native route wheel
run: python tests/test_litellm/rust_bridge/native_route_wheel_test.py dist/*.whl
# EXPERIMENTAL: build and smoke-test the native module on a free-threaded
# (no-GIL) CPython. This lane is a signal, not a gate.
free-threaded-wheel:
continue-on-error: true
name: free-threaded wheel (3.14t, experimental)
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
steps:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Set up free-threaded Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.14t"
- name: Set up Rust
run: rustup toolchain install
- name: Build free-threaded wheel
run: |
python -m pip install maturin==1.15.0
maturin build --profile release -i python --no-default-features --features freethreaded,extension-module -o dist
- name: Assert free-threaded wheel tag
run: >-
python -c 'import glob, sys; wheels = glob.glob("dist/*.whl");
assert wheels and all("cp314t" in w and "t-" in w for w in wheels), wheels'
- name: Smoke-test free-threaded native module
run: |
python -m pip install --no-deps dist/*.whl
python - <<'EOF'
import importlib.util
import sys
import sysconfig
import tempfile
import zipfile
from pathlib import Path
wheel = next(Path("dist").glob("*.whl"))
with tempfile.TemporaryDirectory() as temporary_directory, zipfile.ZipFile(wheel) as archive:
member = next(
member
for member in archive.namelist()
if member.startswith("litellm/rust_bridge/_native.") and member.endswith(".so")
)
native = Path(temporary_directory) / Path(member).name
native.write_bytes(archive.read(member))
spec = importlib.util.spec_from_file_location("litellm.rust_bridge._native", native)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
assert sys.version_info[:2] == (3, 14), sys.version
assert sysconfig.get_config_var("Py_GIL_DISABLED") == 1, sys.version
info = module.build_info()
assert info["gil_disabled"] is True, info
stats = module.gil_stats()
assert isinstance(stats["releases"], int), stats
decline = module.chat_completions_decline(
"gpt-4o-mini", [{"role": "user", "content": "hi"}]
)
assert decline is None or isinstance(decline, str), decline
print(f"free-threaded smoke ok on {sys.version}: gil_stats={dict(stats)}")
EOF
- name: Test native route wheel
run: python tests/test_litellm/rust_bridge/native_route_wheel_test.py dist/*.whl

View file

@ -12,6 +12,9 @@ crate-type = ["cdylib"]
[features]
default = ["abi3"]
abi3 = ["pyo3/abi3-py310"]
# Free-threaded stable ABI (cp3XXt wheels), following the cryptography project's
# pyo3 setup; deliberately omits the abi3-py310 GIL-wheel pin.
freethreaded = ["pyo3/abi3", "pyo3/abi3t"]
extension-module = ["pyo3/extension-module"]
panic-test = []