Skip to content

build(rust): bump pyo3 to 0.29 so litellm-rust compiles on Python 3.14 - #33457

Closed
ryan-crabbe-berri wants to merge 2 commits into
litellm_internal_stagingfrom
litellm_pyo3_0_29_python_3_14
Closed

build(rust): bump pyo3 to 0.29 so litellm-rust compiles on Python 3.14#33457
ryan-crabbe-berri wants to merge 2 commits into
litellm_internal_stagingfrom
litellm_pyo3_0_29_python_3_14

Conversation

@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor

Relevant issues

Addresses the PyO3 half of #33116. The requires-python metadata bump it also asks for is #33438, and publishing cp314 wheels happens in the wheel build matrix outside this repo, so this PR does not auto-close the issue

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Before, at 24a438a (current litellm_internal_staging HEAD, with the #33438 requires-python bump applied so the build is even attempted, which is exactly what a Python 3.14 user hits once #33438 ships):

$ uv build --wheel --python 3.14
Building wheel...
🍹 Building a mixed python/rust project
error: failed to run custom build command for `pyo3-ffi v0.23.5`
  error: the configured Python interpreter version (3.14) is newer than PyO3's maximum supported version (3.13)
  = help: please check if an updated version of PyO3 is available. Current version: 0.23.5
💥 maturin failed

This is the same failure reported in #33116

After, at 1fc700e:

$ uv build --wheel --python 3.14
📦 Built wheel for CPython 3.14: litellm-1.94.0-cp314-cp314-macosx_11_0_arm64.whl

$ uv venv --python 3.14 py314 && uv pip install --python py314/bin/python litellm-1.94.0-cp314-cp314-macosx_11_0_arm64.whl
$ py314/bin/python -c "
from litellm.rust_bridge import loader
mod = loader.get_native_bridge()
try:
    mod.ocr('mistral/mistral-ocr-latest', {'type': 'document_url', 'document_url': 'https://example.com/x.pdf'})
except ValueError as e:
    print('mapped to ValueError:', e)
print(mod.gil_stats())
"
mapped to ValueError: Missing Mistral API Key - A call is being made to Mistral but no key is set either in the environment variables or via params
{'releases': 1}

The native extension builds, loads, and round-trips a real call on 3.14: Python input marshaling, GIL release through the renamed Python::detach (the release counter increments), the tokio runtime, and the Rust error mapped back to a Python ValueError. A 3.13 build of the same commit still succeeds (litellm-1.94.0-cp313-cp313-macosx_11_0_arm64.whl) and the existing bridge unit tests pass (34 passed)

Type

🚄 Infrastructure

Changes

PyO3 0.23.5 refuses to compile against CPython 3.14 (it supports up to 3.13), so any Python 3.14 install that reaches the sdist fails in maturin. This bumps pyo3 and pyo3-async-runtimes from 0.23 to 0.29, the current stable line, which supports 3.14

The API fallout is small because the bridge is thin: Python::with_gil was renamed to Python::attach and Python::allow_threads to Python::detach (PyO3 dropped GIL-centric naming for free-threading support), so the three call sites in python-bridge and the feature-gated config embed in ai-gateway are renamed accordingly. No behavior change

To keep this class of breakage from coming back silently, test-rust.yml gains a job that compiles litellm-python-bridge against Python 3.14 via PYO3_PYTHON; it fails on exactly the pyo3-ffi version gate shown above whenever the pinned PyO3 falls behind the CPython we claim to support

Note for release sequencing: this should land before or together with #33438. Lifting the requires-python cap without this bump would turn today's silent fallback to 1.83.7 into a hard build failure for every 3.14 pip install. Publishing cp314 wheels in the wheel build matrix remains as a follow-up so 3.14 users get prebuilt wheels instead of sdist builds

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

@ryan-crabbe-berri
ryan-crabbe-berri requested a review from a team July 15, 2026 21:38
@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR bumps pyo3 from 0.23.5 to 0.29.0 and pyo3-async-runtimes from 0.23.0 to 0.29.0 so the litellm-rust crate compiles against CPython 3.14. The only required code changes are three mechanical API renames — Python::with_gilPython::attach and py.allow_threadspy.detach — which PyO3 introduced to drop GIL-centric naming ahead of free-threading support.

  • Dependency update (Cargo.toml / Cargo.lock): pyo3 and pyo3-async-runtimes are pinned to 0.29.0; indirect dependencies (memoffset, indoc, unindent, futures-executor, autocfg) are removed because pyo3 0.29 dropped them.
  • API renames (lib.rs, gil.rs, config.rs): three call sites updated to the new naming; no behavior change.
  • CI guard (test-rust.yml): new python-bridge-newest-python job runs cargo check -p litellm-python-bridge against Python 3.14, so the version gate that caused this issue cannot regress silently.

Confidence Score: 5/5

Safe to merge — the change is a focused dependency bump with three mechanical API renames; all call sites are updated, the lockfile is regenerated, and a new CI job guards against the same class of breakage recurring.

All three PyO3 API rename sites (Python::with_gil → Python::attach, py.allow_threads → py.detach) are correctly updated. The pyo3 and pyo3-async-runtimes versions are kept in sync at 0.29.0 as required. The new CI job correctly uses cargo check rather than a heavier full build, namespaces its cache key to avoid collisions, and pins action SHAs. No behavior changes and no custom rules are violated.

No files require special attention.

Important Files Changed

Filename Overview
litellm-rust/Cargo.toml Bumps pyo3 to 0.29.0 and pyo3-async-runtimes to 0.29.0; versions match as required by pyo3-async-runtimes' re-export of pyo3 types.
litellm-rust/crates/python-bridge/src/lib.rs Renames Python::with_gil to Python::attach in the async aocr helper; correct usage for re-acquiring the GIL after an await point.
litellm-rust/crates/python-bridge/src/gil.rs Renames py.allow_threads to py.detach and updates the doc-comment; semantics unchanged.
litellm-rust/crates/ai-gateway/src/python/config.rs Renames Python::with_gil to Python::attach under the python-config feature gate; no behavioral change.
.github/workflows/test-rust.yml Adds a python-bridge-newest-python CI job that runs cargo check against Python 3.14; action commits are pinned to SHA, cache keys are namespaced to avoid collisions with the existing job.
litellm-rust/Cargo.lock Lockfile regenerated to reflect pyo3 0.29.0 tree; removals (memoffset, indoc, unindent, futures-executor, autocfg) are expected as pyo3 0.29 dropped those dependencies.

Reviews (1): Last reviewed commit: "ci(rust): compile the PyO3 bridge agains..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_pyo3_0_29_python_3_14 (ad0e64f) with litellm_internal_staging (9121ae3)

Open in CodSpeed

rustup toolchain install stable --profile minimal
rustup default stable

- name: Cache Cargo registry and target

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we need to cache this?

@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor Author

closign cus yuneng got it

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

2 participants