mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-27 06:13:07 +00:00
fix: support Python 3.15 (#48359)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
dddbaa803d
commit
ebf829c2fa
9 changed files with 1292 additions and 434 deletions
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
|
@ -132,7 +132,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
|
|
|
|||
8
.github/workflows/test-merge-smoke.yml
vendored
8
.github/workflows/test-merge-smoke.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
|
||||
env:
|
||||
LITELLM_LOCAL_MODEL_COST_MAP: "True"
|
||||
steps:
|
||||
|
|
@ -76,6 +76,12 @@ jobs:
|
|||
- name: Import and CLI checks
|
||||
run: $IN_NETNS .venv/bin/python .github/scripts/run_merge_smoke.py cli
|
||||
|
||||
- name: Routing and UUID compatibility
|
||||
run: >-
|
||||
$IN_NETNS .venv/bin/python -m pytest
|
||||
tests/unit/router_strategy/test_complexity_router.py::TestCustomDimensions
|
||||
tests/unit/test_uuid_helper.py -q
|
||||
|
||||
- name: Proxy startup check
|
||||
run: $IN_NETNS .venv/bin/python .github/scripts/run_merge_smoke.py proxy-startup --diagnostics-dir "${RUNNER_TEMP}/smoke-diagnostics"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
"""
|
||||
Internal unified UUID helper.
|
||||
|
||||
Always uses fastuuid for performance.
|
||||
Uses fastuuid where supported and the standard library on Python 3.15+.
|
||||
"""
|
||||
|
||||
import fastuuid as _uuid
|
||||
import sys
|
||||
import uuid as _uuid
|
||||
|
||||
if sys.version_info < (3, 15):
|
||||
import fastuuid as _uuid
|
||||
|
||||
# Expose a module-like alias so callers can use: uuid.uuid4()
|
||||
uuid = _uuid
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ All values are configurable via proxy config.yaml.
|
|||
|
||||
import math
|
||||
import re
|
||||
import warnings
|
||||
import sys
|
||||
from collections.abc import Iterable, Mapping
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from types import MappingProxyType
|
||||
from typing import Annotated, Final, Literal, NamedTuple
|
||||
from typing import TYPE_CHECKING, Annotated, Final, Literal, NamedTuple
|
||||
|
||||
from pydantic import (
|
||||
ConfigDict,
|
||||
|
|
@ -27,8 +27,13 @@ from pydantic import (
|
|||
|
||||
from litellm.types.llms.base import LiteLLMBaseModel
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
if TYPE_CHECKING:
|
||||
import sre_constants
|
||||
import sre_parse
|
||||
elif sys.version_info >= (3, 11):
|
||||
from re import _constants as sre_constants
|
||||
from re import _parser as sre_parse
|
||||
else:
|
||||
import sre_constants
|
||||
import sre_parse
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ name = "litellm-core"
|
|||
version = "1.105.0"
|
||||
description = "Library to easily interface with LLM API providers"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10, <3.15"
|
||||
requires-python = ">=3.10, <3.16"
|
||||
license = "MIT"
|
||||
license-files = ["LICENSE"]
|
||||
authors = [
|
||||
{ name = "BerriAI" },
|
||||
]
|
||||
dependencies = [
|
||||
"fastuuid>=0.14.0,<1.0",
|
||||
"fastuuid>=0.14.0,<1.0; python_version < '3.15'",
|
||||
"filelock>=3.16.1,<4.0",
|
||||
"httpx[http2]>=0.28.0,<1.0",
|
||||
"openai>=2.20.0,<4.0.0",
|
||||
|
|
@ -20,14 +20,16 @@ dependencies = [
|
|||
"packaging>=24.0",
|
||||
"importlib-metadata>=8.0.0,<9.0",
|
||||
"tiktoken>=0.8.0,<1.0; python_version < '3.14'",
|
||||
"tiktoken>=0.12.0,<1.0; python_version >= '3.14'",
|
||||
"tiktoken>=0.12.0,<1.0; python_version == '3.14'",
|
||||
"tiktoken>=0.14.0,<1.0; python_version >= '3.15'",
|
||||
"click>=8.0.0,<9.0",
|
||||
"jinja2>=3.1.6,<4.0",
|
||||
"aiohttp>=3.14.2,<4.0",
|
||||
"anyio>=4.14.0,<5.0",
|
||||
"async-timeout>=4.0.3,<6.0; python_version < '3.11'",
|
||||
"pydantic>=2.11.0,<3.0.0; python_version < '3.14'",
|
||||
"pydantic>=2.12.0,<3.0.0; python_version >= '3.14'",
|
||||
"pydantic>=2.12.0,<3.0.0; python_version == '3.14'",
|
||||
"pydantic>=2.14.0,<3.0.0; python_version >= '3.15'",
|
||||
"pydantic-settings>=2.14.1,<3.0",
|
||||
"jsonschema>=4.0.0,<5.0",
|
||||
"certifi>=2026.10.19",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ name = "litellm"
|
|||
version = "1.108.0"
|
||||
description = "Library to easily interface with LLM API providers"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10, <3.15"
|
||||
requires-python = ">=3.10, <3.16"
|
||||
license = "MIT"
|
||||
license-files = ["LICENSE"]
|
||||
authors = [
|
||||
|
|
@ -14,7 +14,7 @@ dependencies = [
|
|||
# deps. Reproducibility for our Docker/CI comes from `uv.lock`.
|
||||
# When changing a floor, verify it installs + imports on every supported
|
||||
# Python with: `uv pip install --resolution=lowest-direct .`
|
||||
"fastuuid>=0.14.0,<1.0",
|
||||
"fastuuid>=0.14.0,<1.0; python_version < '3.15'",
|
||||
"filelock>=3.16.1,<4.0",
|
||||
"httpx[http2]>=0.28.0,<1.0",
|
||||
"openai>=2.20.0,<4.0.0",
|
||||
|
|
@ -23,7 +23,8 @@ dependencies = [
|
|||
"packaging>=24.0",
|
||||
"importlib-metadata>=8.0.0,<9.0",
|
||||
"tiktoken>=0.8.0,<1.0; python_version < '3.14'",
|
||||
"tiktoken>=0.12.0,<1.0; python_version >= '3.14'",
|
||||
"tiktoken>=0.12.0,<1.0; python_version == '3.14'",
|
||||
"tiktoken>=0.14.0,<1.0; python_version >= '3.15'",
|
||||
"tokenizers>=0.21.0,<1.0",
|
||||
"huggingface-hub>=0.34.0,<2.0",
|
||||
"click>=8.0.0,<9.0",
|
||||
|
|
@ -32,7 +33,8 @@ dependencies = [
|
|||
"anyio>=4.14.0,<5.0",
|
||||
"async-timeout>=4.0.3,<6.0; python_version < '3.11'",
|
||||
"pydantic>=2.11.0,<3.0.0; python_version < '3.14'",
|
||||
"pydantic>=2.12.0,<3.0.0; python_version >= '3.14'",
|
||||
"pydantic>=2.12.0,<3.0.0; python_version == '3.14'",
|
||||
"pydantic>=2.14.0,<3.0.0; python_version >= '3.15'",
|
||||
"pydantic-settings>=2.14.1,<3.0",
|
||||
"jsonschema>=4.0.0,<5.0",
|
||||
"boto3>=1.43.117,<2.0",
|
||||
|
|
@ -55,17 +57,20 @@ Documentation = "https://docs.litellm.ai"
|
|||
proxy = [
|
||||
"gunicorn>=23.0.0,<24.0",
|
||||
"uvicorn>=0.33.0,<1.0",
|
||||
"granian>=2.7.4,<3.0",
|
||||
"granian>=2.7.4,<3.0; python_version < '3.15'",
|
||||
"granian>=2.8.0,<3.0; python_version >= '3.15'",
|
||||
"uvloop>=0.22.1,<1.0; sys_platform != 'win32'",
|
||||
"fastapi>=0.136.3,<1.0",
|
||||
"starlette>=1.0.1,<2.0",
|
||||
"backoff>=2.2.1,<3.0",
|
||||
"pyyaml>=6.0.3,<7.0",
|
||||
"rq>=2.7.0,<3.0",
|
||||
"orjson>=3.11.6,<4.0",
|
||||
"orjson>=3.11.6,<4.0; python_version < '3.15'",
|
||||
"orjson>=3.12.0,<4.0; python_version >= '3.15'",
|
||||
# redis-py's C response parser. It arrives with redis (via rq) either way; naming
|
||||
# it here is what makes redis-py select _HiredisParser instead of the Python one.
|
||||
"hiredis>=3.0.0,<4.0",
|
||||
"hiredis>=3.0.0,<4.0; python_version < '3.15'",
|
||||
"hiredis>=3.5.0,<4.0; python_version >= '3.15'",
|
||||
"apscheduler>=3.11.2,<4.0",
|
||||
"fastapi-sso>=0.19.0,<1.0",
|
||||
"PyJWT>=2.13.0,<3.0",
|
||||
|
|
@ -210,8 +215,8 @@ dev = [
|
|||
"tomli==2.4.1; python_version < '3.11'",
|
||||
"pytest-mock==3.15.1",
|
||||
"pytest-asyncio==1.3.0",
|
||||
"psycopg==3.3.3",
|
||||
"psycopg-binary==3.3.3",
|
||||
"psycopg==3.3.6",
|
||||
"psycopg-binary==3.3.6",
|
||||
"pytest-xdist==3.8.0",
|
||||
"requests-mock==1.12.1",
|
||||
"responses==0.26.0",
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,11 @@ class TestCustomDimensions:
|
|||
"create table widgets (id integer); ALTER TABLE widgets ADD label text;",
|
||||
id="regex",
|
||||
),
|
||||
pytest.param(
|
||||
{"patterns": [r"\b(?P<verb>create|alter)\s{1,4}?table\b"]},
|
||||
"CREATE TABLE widgets (id integer)",
|
||||
id="named-group-alternation-lazy-repeat",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_custom_dimension_changes_only_matching_requests(
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
import importlib
|
||||
from typing import Final
|
||||
from uuid import NAMESPACE_DNS, UUID, uuid5 as stdlib_uuid5
|
||||
|
||||
from litellm._uuid import uuid, uuid4
|
||||
|
||||
|
||||
def test_uses_fastuuid_and_uuid4_works():
|
||||
mod = importlib.import_module("litellm._uuid")
|
||||
fastuuid_mod = importlib.import_module("fastuuid")
|
||||
assert hasattr(mod, "uuid4")
|
||||
assert hasattr(mod, "uuid")
|
||||
assert mod.uuid is fastuuid_mod
|
||||
def test_uuid4_returns_canonical_random_uuid() -> None:
|
||||
for value in (uuid4(), uuid.uuid4()):
|
||||
encoded: Final = str(value)
|
||||
parsed: Final = UUID(encoded)
|
||||
assert parsed.version == 4
|
||||
assert encoded == str(parsed)
|
||||
assert value.bytes == parsed.bytes
|
||||
|
||||
# Ensure uuid4 returns something that looks like a UUID string
|
||||
val = str(mod.uuid4())
|
||||
assert isinstance(val, str)
|
||||
assert len(val) >= 8
|
||||
|
||||
def test_uuid5_accepts_byte_names_for_stable_ids() -> None:
|
||||
namespace: Final = uuid.UUID(str(NAMESPACE_DNS))
|
||||
name: Final = "guardrail-\u00e9"
|
||||
generated: Final = uuid.uuid5(namespace, name.encode("utf-8"))
|
||||
assert str(generated) == str(stdlib_uuid5(NAMESPACE_DNS, name))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue