build(rust): raise pyo3 to 0.29 so the native bridge compiles on Python 3.14 - #33798
Conversation
…on 3.14 pyo3 0.23.5 hard-caps the interpreter at Python 3.13, so building the native bridge against a 3.14 interpreter aborts inside pyo3-ffi's build script before anything links. This raises pyo3 and pyo3-async-runtimes to 0.29 (currently the newest line, and the range starting at 0.26 that supports 3.14) and migrates the three call sites whose APIs were renamed across that range: Python::with_gil is now Python::attach and Python::allow_threads is now Python::detach. On a GIL-enabled interpreter those are pure renames with identical semantics, so behavior on 3.10 through 3.13 is unchanged Verified by compiling the native module for cp313 and cp314 and driving it directly on both interpreters: gil_stats reports exactly one GIL release per sync OCR call and the async path completes, matching the 0.23.5 baseline. cargo fmt, clippy, and the workspace tests pass on both 3.13 and 3.14 with the lockfile locked, and the lock churn is confined to the pyo3 crates Part of #26343; addresses the pyo3 build failure reported in #33116
…itellm_/python-3-14-compat-8363c1
Greptile SummaryThis PR bumps pyo3 and pyo3-async-runtimes from 0.23 to 0.29, which is the minimum version that removes the hard Python 3.13 cap in pyo3-ffi's build script, allowing the native bridge to compile on Python 3.14. Three call sites are migrated in lockstep to the renamed APIs introduced in pyo3 0.24 (
Confidence Score: 5/5The change is a targeted dependency version bump with mechanical API renames; no logic paths, data handling, or Python glue are altered. Every changed line is either a version string in a manifest, a lockfile entry, or a one-for-one rename of a pyo3 API that carries identical runtime semantics. The PR description provides build logs and a live 3.14 end-to-end probe, and the existing workspace test suite passes identically on both interpreters. No files require special attention; all changes are in the Rust native bridge and its build manifests, with no Python glue or proxy logic touched.
|
| Filename | Overview |
|---|---|
| litellm-rust/Cargo.toml | Bumps pyo3 from 0.23.5 to 0.29.0 and pyo3-async-runtimes from 0.23.0 to 0.29.0 to lift the Python 3.13 hard cap |
| litellm-rust/Cargo.lock | Lockfile updated to reflect pyo3 0.29.0 tree; removes now-unneeded transitive deps (autocfg, futures, futures-executor, indoc, memoffset, unindent) and bumps target-lexicon to 0.13.5 |
| litellm-rust/crates/python-bridge/src/gil.rs | Migrates py.allow_threads → py.detach (pure rename in pyo3 0.24+, identical semantics); updates the doc-comment to match |
| litellm-rust/crates/python-bridge/src/lib.rs | Migrates Python::with_gil → Python::attach in the aocr result-marshaling site (pure rename, correct usage inside future_into_py async block) |
| litellm-rust/crates/ai-gateway/src/python/config.rs | Migrates Python::with_gil → Python::attach in the boot-time router config loader; no behavioral change |
Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/lit..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
f3d2015
into
litellm_internal_staging
…1.93.0 stable cut (#33847) * fix(ci): bump pillow to 12.3.0 to resolve osv-scan CVEs (#33093) (cherry picked from commit 20e646c) * chore(deps): pin httplib2 and setuptools transitive floors (#33233) Raise the constraint floors for two transitive dependencies so resolution moves them to their latest maintenance releases: httplib2 0.31.2 -> 0.32.0 and setuptools 82.0.1 -> 83.0.0. Both are pulled in only by optional integrations (Google API client, grpc tooling, lunary observability, the nvidia-riva extra), all lower-bound only, so the floors stay inside every requirer's allowed range and a default install is unaffected (cherry picked from commit 8b32320) * fix(anthropic/passthrough): drop incompatible temperature when downgrading adaptive thinking for pre-4.6 models (#33244) * fix(anthropic/passthrough): drop temperature and cap thinking budget when downgrading adaptive thinking for pre-4.6 models * test(anthropic/passthrough): use sufficient max_tokens for reasoning_effort thinking mapping * fix(anthropic/passthrough): drop incompatible temperature when downgrading adaptive thinking for pre-4.6 models Narrow the fix to the temperature reconciliation; the reasoning_effort budget cap is reverted because the live translation grid relies on budget_tokens >= max_tokens to reject unsupported effort tiers (xhigh/max) on budget-mode models, so capping turned those 400s into 200s. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> (cherry picked from commit 71dffc1) * build: raise requires-python cap to <3.15 so Python 3.14 installs current releases (#33438) * build: drop requires-python upper cap so Python 3.14 resolves to current releases The <3.14 cap made pip on Python 3.14 fall back to litellm 1.83.7, a pre-April release whose old auth flow fails with 400s. The cap was added in d9a4602 because deps lacked 3.14 wheels and uv could not resolve the 3.14 split; both are fixed now via the existing python_version markers plus a ddtrace version split (2.x has no cp314 wheels, 3.16+ does). Verified on 3.14.5: uv sync --all-extras installs, litellm and proxy_server import (rust bridge falls back to pure python), real provider calls succeed sync/async/streaming, and the core-utils test suite passes. * build: cap requires-python at <3.15 and keep ddtrace on one major per python band Reviewer preference to bound the supported window at the newest tested minor rather than leaving it open-ended, and Greptile flagged the ddtrace 3.14+ range spanning two majors; every ddtrace 4.x ships cp314 wheels so the band is now >=4.0,<5.0, matching the single-major convention of the 2.x band. (cherry picked from commit c6d49a8) * build(deps): update ddtrace to the 4.x line A single ddtrace constraint now covers every supported Python version, so this collapses the version split introduced in #33438. Also aligns the build_from_pip image pin and updates the type-only Tracer import to its current module path (cherry picked from commit edc38ea) * fix(docker): restore litellm-proxy-extras source dir in runtime images (#33592) * fix(docker): restore litellm-proxy-extras source dir in runtime images #30243 narrowed the runtime stage to an allowlist COPY, which dropped /app/litellm-proxy-extras from the published images. Downstream migration jobs point prisma migrate deploy at that path; with the schema gone (or a schema with no adjacent migrations dir, where prisma exits 0 without applying anything) those jobs went green while never migrating the database. Restore the folder in all three runtime stages and assert in image-scan that the schema and a non-empty migrations dir ship at the source path * chore(ci): drop image-scan migration-assets assertion (cherry picked from commit 111d447) * fix(model_armor): restore reference attachments via skip_unscannable_attachments and remove the attachment count cap (#33554) * fix(model_armor): add skip_unscannable_attachments to allow reference-only attachments through * fix(model_armor): wire skip_unscannable_attachments through guardrail config * fix(model_armor): make max_file_attachments configurable and scan overflow instead of dropping * fix(model_armor): remove the per-request attachment count cap and scan all attachments --------- Co-authored-by: yucheng <yucheng@berri.ai> (cherry picked from commit 0d7b0f7) * build(rust): raise pyo3 to 0.29 so the native bridge compiles on Python 3.14 (#33798) pyo3 0.23.5 hard-caps the interpreter at Python 3.13, so building the native bridge against a 3.14 interpreter aborts inside pyo3-ffi's build script before anything links. This raises pyo3 and pyo3-async-runtimes to 0.29 (currently the newest line, and the range starting at 0.26 that supports 3.14) and migrates the three call sites whose APIs were renamed across that range: Python::with_gil is now Python::attach and Python::allow_threads is now Python::detach. On a GIL-enabled interpreter those are pure renames with identical semantics, so behavior on 3.10 through 3.13 is unchanged Verified by compiling the native module for cp313 and cp314 and driving it directly on both interpreters: gil_stats reports exactly one GIL release per sync OCR call and the async path completes, matching the 0.23.5 baseline. cargo fmt, clippy, and the workspace tests pass on both 3.13 and 3.14 with the lockfile locked, and the lock churn is confined to the pyo3 crates Part of #26343; addresses the pyo3 build failure reported in #33116 (cherry picked from commit f3d2015) * build(deps): allow redisvl, pypdf, and openapi-core on Python 3.14 (#33801) Remove the python_version < '3.14' environment markers from redisvl, pypdf, and openapi-core now that all three install and import cleanly on 3.14. The relock is marker-only: no package version changed for any Python branch, and the locked versions (redisvl 0.4.1, pypdf 6.13.3, openapi-core 0.22.0) now serve 3.14 as well. semantic-router and aurelio-sdk stay gated because every published release caps python_requires below 3.14 (cherry picked from commit 967d934) * build(deps): bump mcp lock to 1.28.1 to clear image-scan findings (#33803) * build(deps): bump mcp lock to 1.28.1 to clear image-scan findings * build(deps): require mcp>=1.28.1 (cherry picked from commit 40e914c) * fix(proxy): source /v1/models token limits from the cost map instead of Router.get_model_group_info (#33721) * fix(proxy): source /v1/models token limits from cost map instead of Router.get_model_group_info Resolves the per-model get_model_group_info fan-out on GET /v1/models (and /models) that pegged the event loop on wildcard listings (#33636). create_model_info_response now reads max_input_tokens/max_output_tokens from litellm.get_model_info (the static cost map) rather than the router, which aggregated and deepcopied every deployment in a group per listed model. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(proxy): inject model-info lookup into create_model_info_response for deterministic coverage Inject the cost-map lookup (defaulting to litellm.get_model_info) so the except and max_output_tokens branches are exercised deterministically and the token-limit tests no longer hardcode mutable cost-map values. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * feat(proxy): surface custom deployment token limits on /v1/models via cheap index lookup Add Router.get_configured_token_limits, an O(1) model-name index lookup that reads a concrete deployment's configured max_input_tokens/max_output_tokens without triggering pattern matching or deep copies. create_model_info_response layers this over the cost map so custom deployments absent from the cost map still surface their limits, and admin-configured limits override cost-map defaults, while wildcard-expanded names stay on the fast path. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: ryan <ryan@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> (cherry picked from commit 8536e3b) --------- Co-authored-by: yucheng-berri <yucheng@berri.ai> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: ryan-crabbe-berri <ryan@berri.ai>
Relevant issues
Part of #26343 (Python 3.14 support); addresses the pyo3 build failure reported in #33116
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
This is a build-compatibility change, so the proof is the native module refusing to compile on Python 3.14 before and building plus running after, with a live Mistral OCR round-trip exercising the migrated GIL calls end to end (no mocks; a bad key returns 401 from the real API)
Before (pyo3 0.23.5, at
04a5ebb94d) building the native module for Python 3.14 aborts in pyo3-ffi's build script:After (pyo3 0.29.0, at
9011b24c9f) wheels build for both cp313 and cp314:The compiled bridge exercised directly on Python 3.14, calling the live Mistral OCR API with a bad key so a 401 comes back only after the request is marshaled, the GIL is released via
detach, the tokio runtime runs, and the GIL is reacquired viaattach:The same probe on Python 3.13 returns byte-for-byte the same result as the 0.23.5 baseline, so
with_gil->attachandallow_threads->detachare behavior-neutral on GIL-enabled buildsThe workspace checks that CI runs pass on both interpreters at
9011b24c9fwith the lockfile locked:Type
🐛 Bug Fix
🚄 Infrastructure
Changes
pyo3 and pyo3-async-runtimes move from 0.23 to 0.29, the first line that supports Python 3.14 (support landed in 0.26) and the current newest release. pyo3 0.23.5 hard-caps the interpreter at 3.13, so any 3.14 install that falls back to the sdist fails in pyo3-ffi's build script before anything links
Three call sites use APIs that were renamed across that range and are migrated in lockstep:
Python::with_gilbecomesPython::attach(the async OCR result marshaling and thepython-configrouter loader) andPython::allow_threadsbecomesPython::detach(the single GIL-release chokepoint). On a GIL-enabled interpreter these are pure renames with identical semantics, so behavior on Python 3.10 through 3.13 is unchanged, and the lockfile churn is confined to the pyo3 cratesNo new tests are added: this is a dependency bump with no unit-testable surface, the Python glue is untouched, and parity is proven by the existing workspace suite passing identically on 3.13 and 3.14 plus the end-to-end native probe above
This change only makes the source build succeed on 3.14; publishing cp314 wheels and widening the CI matrix are deliberately separate follow-ups, so a 3.14 install still builds from the sdist and needs a Rust toolchain until those land, which is a visible actionable error rather than a silent failure
Final Attestation