mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
build: migrate packaging metadata to uv
This commit is contained in:
parent
7250cba3db
commit
e103d3dcc6
11 changed files with 11017 additions and 8651 deletions
7
enterprise/poetry.lock
generated
7
enterprise/poetry.lock
generated
|
|
@ -1,7 +0,0 @@
|
|||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
package = []
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.8.1,<4.0, !=3.9.7"
|
||||
content-hash = "2cf39473e67ff0615f0a61c9d2ac9f02b38cc08cbb1bdb893d89bee002646623"
|
||||
|
|
@ -1,30 +1,29 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "litellm-enterprise"
|
||||
version = "0.1.35"
|
||||
description = "Package for LiteLLM Enterprise features"
|
||||
authors = ["BerriAI"]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
license-files = ["LICENSE.md"]
|
||||
authors = [
|
||||
{ name = "BerriAI" },
|
||||
]
|
||||
|
||||
|
||||
[tool.poetry.urls]
|
||||
homepage = "https://litellm.ai"
|
||||
[project.urls]
|
||||
Homepage = "https://litellm.ai"
|
||||
repository = "https://github.com/BerriAI/litellm"
|
||||
Repository = "https://github.com/BerriAI/litellm"
|
||||
documentation = "https://docs.litellm.ai"
|
||||
Documentation = "https://docs.litellm.ai"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8.1,<4.0, !=3.9.7"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["uv_build>=0.10.7,<0.11"]
|
||||
build-backend = "uv_build"
|
||||
|
||||
[tool.uv.build-backend]
|
||||
module-root = ""
|
||||
|
||||
[tool.commitizen]
|
||||
version = "0.1.35"
|
||||
version_files = [
|
||||
"pyproject.toml:version",
|
||||
"../requirements.txt:litellm-enterprise==",
|
||||
"../pyproject.toml:litellm-enterprise = {version = \""
|
||||
]
|
||||
"pyproject.toml:^version",
|
||||
"../pyproject.toml:litellm-enterprise==",
|
||||
]
|
||||
|
|
|
|||
7
litellm-proxy-extras/poetry.lock
generated
7
litellm-proxy-extras/poetry.lock
generated
|
|
@ -1,7 +0,0 @@
|
|||
# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand.
|
||||
package = []
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.8.1,<4.0, !=3.9.7"
|
||||
content-hash = "2cf39473e67ff0615f0a61c9d2ac9f02b38cc08cbb1bdb893d89bee002646623"
|
||||
|
|
@ -1,30 +1,29 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "litellm-proxy-extras"
|
||||
version = "0.4.62"
|
||||
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
|
||||
authors = ["BerriAI"]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
license-files = ["LICENSE"]
|
||||
authors = [
|
||||
{ name = "BerriAI" },
|
||||
]
|
||||
|
||||
|
||||
[tool.poetry.urls]
|
||||
homepage = "https://litellm.ai"
|
||||
[project.urls]
|
||||
Homepage = "https://litellm.ai"
|
||||
repository = "https://github.com/BerriAI/litellm"
|
||||
Repository = "https://github.com/BerriAI/litellm"
|
||||
documentation = "https://docs.litellm.ai"
|
||||
Documentation = "https://docs.litellm.ai"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8.1,<4.0, !=3.9.7"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["uv_build>=0.10.7,<0.11"]
|
||||
build-backend = "uv_build"
|
||||
|
||||
[tool.uv.build-backend]
|
||||
module-root = ""
|
||||
|
||||
[tool.commitizen]
|
||||
version = "0.4.62"
|
||||
version_files = [
|
||||
"pyproject.toml:version",
|
||||
"../requirements.txt:litellm-proxy-extras==",
|
||||
"../pyproject.toml:litellm-proxy-extras = {version = \""
|
||||
]
|
||||
"pyproject.toml:^version",
|
||||
"../pyproject.toml:litellm-proxy-extras==",
|
||||
]
|
||||
|
|
|
|||
8312
poetry.lock
generated
8312
poetry.lock
generated
File diff suppressed because it is too large
Load diff
354
pyproject.toml
354
pyproject.toml
|
|
@ -1,189 +1,231 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "litellm"
|
||||
version = "1.83.0"
|
||||
description = "Library to easily interface with LLM API providers"
|
||||
authors = ["BerriAI"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
packages = [
|
||||
{ include = "litellm" },
|
||||
{ include = "litellm/py.typed"},
|
||||
requires-python = ">=3.9"
|
||||
license = "MIT"
|
||||
license-files = ["LICENSE"]
|
||||
authors = [
|
||||
{ name = "BerriAI" },
|
||||
]
|
||||
dependencies = [
|
||||
"fastuuid==0.14.0",
|
||||
"httpx==0.28.1",
|
||||
"openai==2.24.0",
|
||||
"python-dotenv==1.0.1",
|
||||
"tiktoken==0.12.0",
|
||||
"importlib-metadata==8.5.0",
|
||||
"tokenizers==0.22.2",
|
||||
"click==8.1.8",
|
||||
"jinja2==3.1.6",
|
||||
"aiohttp==3.13.3",
|
||||
"pydantic==2.12.5",
|
||||
"jsonschema==4.23.0",
|
||||
]
|
||||
|
||||
[tool.poetry.urls]
|
||||
homepage = "https://litellm.ai"
|
||||
[project.urls]
|
||||
Homepage = "https://litellm.ai"
|
||||
repository = "https://github.com/BerriAI/litellm"
|
||||
Repository = "https://github.com/BerriAI/litellm"
|
||||
documentation = "https://docs.litellm.ai"
|
||||
Documentation = "https://docs.litellm.ai"
|
||||
|
||||
# Dependencies pinned from `pip install litellm[proxy]==1.83.0` PyPI resolution.
|
||||
# Docker builds use requirements.txt (different pins). These two paths are independent.
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<4.0"
|
||||
fastuuid = "0.14.0"
|
||||
httpx = "0.28.1"
|
||||
openai = "2.30.0"
|
||||
python-dotenv = "1.0.1"
|
||||
tiktoken = "0.12.0"
|
||||
importlib-metadata = "8.5.0"
|
||||
tokenizers = "0.22.2"
|
||||
click = "8.1.8"
|
||||
jinja2 = "3.1.6"
|
||||
aiohttp = "3.13.5"
|
||||
pydantic = "2.12.5"
|
||||
jsonschema = "4.23.0"
|
||||
numpydoc = {version = "1.8.0", optional = true} # not in Docker or PyPI proxy extra
|
||||
|
||||
uvicorn = {version = "0.33.0", optional = true}
|
||||
uvloop = {version = "0.21.0", optional = true, markers="sys_platform != 'win32'"}
|
||||
gunicorn = {version = "23.0.0", optional = true}
|
||||
fastapi = {version = "0.124.4", optional = true}
|
||||
backoff = {version = "2.2.1", optional = true}
|
||||
pyyaml = {version = "6.0.3", optional = true}
|
||||
rq = {version = "2.7.0", optional = true}
|
||||
orjson = {version = "3.10.15", optional = true}
|
||||
apscheduler = {version = "3.11.2", optional = true}
|
||||
fastapi-sso = { version = "0.16.0", optional = true }
|
||||
PyJWT = { version = "2.12.1", optional = true, python = ">=3.9" }
|
||||
python-multipart = { version = "0.0.20", optional = true}
|
||||
cryptography = {version = "43.0.3", optional = true} # Docker uses 46.0.5; pyproject uses 43.0.3 for Poetry Python 3.9.0/3.9.1 compat
|
||||
prisma = {version = "0.11.0", optional = true}
|
||||
azure-identity = {version = "1.25.3", optional = true, python = ">=3.9"}
|
||||
azure-keyvault-secrets = {version = "4.10.0", optional = true}
|
||||
azure-storage-blob = {version = "12.28.0", optional = true}
|
||||
google-cloud-kms = {version = "2.24.2", optional = true} # not in PyPI proxy extra
|
||||
google-cloud-iam = {version = "2.19.1", optional = true}
|
||||
google-cloud-aiplatform = {version = "1.133.0", optional = true}
|
||||
resend = {version = "2.23.0", optional = true} # not in PyPI proxy extra
|
||||
pynacl = {version = "1.6.2", optional = true}
|
||||
websockets = {version = "15.0.1", optional = true}
|
||||
boto3 = { version = "1.42.80", optional = true }
|
||||
redisvl = {version = "0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"}
|
||||
mcp = {version = "1.26.0", optional = true, python = ">=3.10"}
|
||||
a2a-sdk = {version = "0.3.25", optional = true, python = ">=3.10"}
|
||||
litellm-proxy-extras = {version = "0.4.62", optional = true}
|
||||
rich = {version = "13.9.4", optional = true}
|
||||
litellm-enterprise = {version = "0.1.35", optional = true}
|
||||
diskcache = {version = "5.6.3", optional = true}
|
||||
polars = {version = "1.39.3", optional = true, python = ">=3.10"}
|
||||
semantic-router = {version = "0.1.12", optional = true, python = ">=3.9,<3.14"}
|
||||
mlflow = {version = "3.9.0", optional = true, python = ">=3.10"} # not in PyPI proxy extra
|
||||
soundfile = {version = "0.12.1", optional = true}
|
||||
pyroscope-io = {version = "0.8.16", optional = true, markers = "sys_platform != 'win32'"}
|
||||
# grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels)
|
||||
grpcio = {version = "1.80.0", optional = true}
|
||||
|
||||
[tool.poetry.extras]
|
||||
# Dependencies pinned from the published `litellm[proxy]==1.83.0` resolution.
|
||||
# Docker and CI should prefer `uv.lock` rather than maintaining parallel installers.
|
||||
[project.optional-dependencies]
|
||||
proxy = [
|
||||
"gunicorn",
|
||||
"uvicorn",
|
||||
"uvloop",
|
||||
"fastapi",
|
||||
"backoff",
|
||||
"pyyaml",
|
||||
"rq",
|
||||
"orjson",
|
||||
"apscheduler",
|
||||
"fastapi-sso",
|
||||
"PyJWT",
|
||||
"python-multipart",
|
||||
"cryptography",
|
||||
"pynacl",
|
||||
"websockets",
|
||||
"boto3",
|
||||
"azure-identity",
|
||||
"azure-storage-blob",
|
||||
"mcp",
|
||||
"litellm-proxy-extras",
|
||||
"litellm-enterprise",
|
||||
"rich",
|
||||
"polars",
|
||||
"soundfile",
|
||||
"pyroscope-io",
|
||||
"gunicorn==23.0.0",
|
||||
"uvicorn==0.33.0",
|
||||
"uvloop==0.21.0; sys_platform != 'win32'",
|
||||
"fastapi==0.124.4",
|
||||
"backoff==2.2.1",
|
||||
"pyyaml==6.0.3",
|
||||
"rq==2.7.0",
|
||||
"orjson==3.10.15",
|
||||
"apscheduler==3.11.2",
|
||||
"fastapi-sso==0.16.0",
|
||||
"PyJWT==2.11.0; python_version >= '3.9'",
|
||||
"python-multipart==0.0.20",
|
||||
# Docker uses 46.0.5; pyproject uses 43.0.3 for Python 3.9.0/3.9.1 compat.
|
||||
"cryptography==43.0.3",
|
||||
"pynacl==1.6.2",
|
||||
"websockets==15.0.1",
|
||||
"boto3==1.42.59",
|
||||
"azure-identity==1.25.2; python_version >= '3.9'",
|
||||
"azure-storage-blob==12.28.0",
|
||||
"mcp==1.26.0; python_version >= '3.10'",
|
||||
"litellm-proxy-extras==0.4.62",
|
||||
"litellm-enterprise==0.1.35",
|
||||
"rich==13.9.4",
|
||||
"polars==1.38.1; python_version >= '3.10'",
|
||||
"soundfile==0.12.1",
|
||||
"pyroscope-io==0.8.16; sys_platform != 'win32'",
|
||||
]
|
||||
|
||||
extra_proxy = [
|
||||
"prisma",
|
||||
"azure-identity",
|
||||
"azure-keyvault-secrets",
|
||||
"google-cloud-kms",
|
||||
"google-cloud-iam",
|
||||
"resend",
|
||||
"redisvl",
|
||||
"a2a-sdk"
|
||||
"prisma==0.11.0",
|
||||
"nodejs-wheel-binaries==24.13.1",
|
||||
"azure-identity==1.25.2; python_version >= '3.9'",
|
||||
"azure-keyvault-secrets==4.10.0",
|
||||
# Not in PyPI proxy extra.
|
||||
"google-cloud-kms==2.24.2",
|
||||
"google-cloud-iam==2.19.1",
|
||||
# Not in PyPI proxy extra.
|
||||
"resend==2.23.0",
|
||||
"redisvl==0.4.1; python_version >= '3.9' and python_version < '3.14'",
|
||||
"a2a-sdk==0.3.24; python_version >= '3.10'",
|
||||
]
|
||||
|
||||
utils = [
|
||||
"numpydoc",
|
||||
# Not in Docker or PyPI proxy extra.
|
||||
"numpydoc==1.8.0",
|
||||
]
|
||||
caching = ["diskcache==5.6.3"]
|
||||
semantic-router = [
|
||||
"semantic-router==0.1.12; python_version >= '3.9' and python_version < '3.14'",
|
||||
"aurelio-sdk==0.0.19; python_version >= '3.9' and python_version < '3.14'",
|
||||
]
|
||||
mlflow = ["mlflow==3.9.0; python_version >= '3.10'"]
|
||||
grpc = [
|
||||
# Newest non-yanked release older than the 30-day cutoff.
|
||||
"grpcio==1.78.0",
|
||||
]
|
||||
google = ["google-cloud-aiplatform==1.133.0"]
|
||||
proxy-runtime = [
|
||||
# Historically bundled in the proxy Docker images via requirements.txt.
|
||||
# Keep these in a dedicated extra so uv-based images preserve the same
|
||||
# feature surface without forcing the base SDK install to grow.
|
||||
"google-cloud-aiplatform==1.133.0",
|
||||
"google-genai==1.37.0",
|
||||
"anthropic[vertex]==0.84.0",
|
||||
"grpcio==1.78.0",
|
||||
"prometheus-client==0.20.0",
|
||||
"langfuse==2.59.7",
|
||||
"opentelemetry-api==1.28.0",
|
||||
"opentelemetry-sdk==1.28.0",
|
||||
"opentelemetry-exporter-otlp==1.28.0",
|
||||
"ddtrace==2.19.0",
|
||||
"sentry-sdk==2.21.0",
|
||||
"mangum==0.17.0",
|
||||
"azure-ai-contentsafety==1.0.0",
|
||||
"azure-storage-file-datalake==12.20.0",
|
||||
"pypdf==6.7.5; python_version < '3.14'",
|
||||
"llm-sandbox==0.3.31; python_version >= '3.10'",
|
||||
"detect-secrets==1.5.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
litellm = "litellm:run_server"
|
||||
litellm-proxy = "litellm.proxy.client.cli:cli"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"diff-cover==9.7.2",
|
||||
"flake8==7.3.0",
|
||||
"black==24.10.0",
|
||||
"mypy==1.19.0",
|
||||
"pytest==8.3.5",
|
||||
"pytest-mock==3.15.1",
|
||||
"pytest-asyncio==1.2.0",
|
||||
"pytest-postgresql==7.0.2",
|
||||
"pytest-xdist==3.8.0",
|
||||
"requests-mock==1.12.1",
|
||||
"responses==0.26.0",
|
||||
"respx==0.22.0",
|
||||
"ruff==0.15.3",
|
||||
"types-requests==2.32.4.20260107; python_version >= '3.10'",
|
||||
"types-setuptools==75.8.0.20250225",
|
||||
"types-redis==4.6.0.20241004",
|
||||
"types-PyYAML==6.0.12.20250915",
|
||||
"opentelemetry-api==1.28.0",
|
||||
"opentelemetry-sdk==1.28.0",
|
||||
"opentelemetry-exporter-otlp==1.28.0",
|
||||
"langfuse==2.59.7",
|
||||
"fastapi-offline==1.7.6",
|
||||
"fakeredis==2.34.1",
|
||||
"pytest-rerunfailures==15.1",
|
||||
"pytest-cov==5.0.0",
|
||||
"parameterized==0.9.0",
|
||||
"openapi-core==0.22.0; python_version < '3.14'",
|
||||
"pytest-timeout==2.4.0",
|
||||
]
|
||||
proxy-dev = [
|
||||
"prisma==0.11.0",
|
||||
"hypercorn==0.17.3",
|
||||
"prometheus-client==0.20.0",
|
||||
"opentelemetry-api==1.28.0",
|
||||
"opentelemetry-sdk==1.28.0",
|
||||
"opentelemetry-exporter-otlp==1.28.0",
|
||||
"azure-identity==1.25.2; python_version >= '3.9'",
|
||||
"a2a-sdk==0.3.24; python_version >= '3.10'",
|
||||
"nodejs-wheel-binaries==24.13.1",
|
||||
]
|
||||
ci = [
|
||||
# pytest-postgresql imports psycopg v3 during pytest startup. Keep the base
|
||||
# package and the binary wheel explicit so uv sync yields a usable driver
|
||||
# without requiring contributors to install libpq separately.
|
||||
"psycopg==3.2.13; python_version < '3.10'",
|
||||
"psycopg==3.3.3; python_version >= '3.10'",
|
||||
"psycopg-binary==3.2.13; python_version < '3.10'",
|
||||
"psycopg-binary==3.3.3; python_version >= '3.10'",
|
||||
# Azure batch E2E tests still import psycopg2 directly.
|
||||
"psycopg2-binary==2.9.11",
|
||||
"pytest-codspeed==4.3.0",
|
||||
"tenacity==8.5.0",
|
||||
"pytest-retry==1.7.0",
|
||||
"google-generativeai==0.8.6",
|
||||
"pyarrow==21.0.0; python_version < '3.10'",
|
||||
"pyarrow==22.0.0; python_version >= '3.10'",
|
||||
"langchain==0.3.27; python_version < '3.10'",
|
||||
"langchain==1.2.10; python_version >= '3.10'",
|
||||
"lunary==1.0.36; python_version < '3.10'",
|
||||
"lunary==1.4.36; python_version == '3.10'",
|
||||
"lunary==1.4.37; python_version >= '3.11'",
|
||||
"logfire==4.6.0",
|
||||
"traceloop-sdk==0.33.12",
|
||||
"detect-secrets==1.5.0",
|
||||
"PyGithub==2.8.1",
|
||||
"aiodynamo==24.7",
|
||||
"argon2-cffi==25.1.0",
|
||||
"Pillow==11.3.0; python_version < '3.10'",
|
||||
"Pillow==12.1.1; python_version >= '3.10'",
|
||||
"assemblyai==0.52.4",
|
||||
"jsonlines==4.0.0",
|
||||
"anthropic==0.84.0",
|
||||
"blockbuster==1.5.26",
|
||||
"beautifulsoup4==4.14.3",
|
||||
"pylint==3.3.9; python_version < '3.10'",
|
||||
"pylint==4.0.5; python_version >= '3.10'",
|
||||
"pyright==1.1.408",
|
||||
"langchain-mcp-adapters==0.2.1; python_version >= '3.10'",
|
||||
"langchain-openai==1.1.10; python_version >= '3.10'",
|
||||
"langgraph==1.0.10; python_version >= '3.10'",
|
||||
"claude-agent-sdk==0.1.44; python_version >= '3.10'",
|
||||
]
|
||||
|
||||
caching = ["diskcache"]
|
||||
[build-system]
|
||||
requires = ["uv_build>=0.10.7,<0.11"]
|
||||
build-backend = "uv_build"
|
||||
|
||||
semantic-router = ["semantic-router"]
|
||||
[tool.uv]
|
||||
default-groups = ["dev"]
|
||||
exclude-newer = "30 days"
|
||||
|
||||
mlflow = ["mlflow"]
|
||||
[tool.uv.sources]
|
||||
litellm-proxy-extras = { workspace = true }
|
||||
litellm-enterprise = { workspace = true }
|
||||
|
||||
grpc = ["grpcio"]
|
||||
[tool.uv.workspace]
|
||||
members = ["enterprise", "litellm-proxy-extras"]
|
||||
|
||||
google = ["google-cloud-aiplatform"]
|
||||
[tool.uv.build-backend]
|
||||
module-root = ""
|
||||
source-exclude = ["litellm/proxy/enterprise"]
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
litellm = 'litellm:run_server'
|
||||
litellm-proxy = 'litellm.proxy.client.cli:cli'
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
diff-cover = "9.7.2"
|
||||
flake8 = "7.3.0"
|
||||
black = "24.10.0"
|
||||
mypy = "1.19.0"
|
||||
pytest = "8.3.5"
|
||||
pytest-mock = "3.15.1"
|
||||
pytest-asyncio = "1.2.0"
|
||||
pytest-postgresql = "7.0.2"
|
||||
pytest-xdist = "3.8.0"
|
||||
requests-mock = "1.12.1"
|
||||
responses = "0.26.0"
|
||||
respx = "0.22.0"
|
||||
ruff = "0.15.3"
|
||||
types-requests = {version = "2.32.4.20260107", python = ">=3.10"}
|
||||
types-setuptools = "75.8.0.20250225"
|
||||
types-redis = "4.6.0.20241004"
|
||||
types-PyYAML = "6.0.12.20250915"
|
||||
opentelemetry-api = "1.28.0"
|
||||
opentelemetry-sdk = "1.28.0"
|
||||
opentelemetry-exporter-otlp = "1.28.0"
|
||||
langfuse = "2.59.7"
|
||||
fastapi-offline = "1.7.6"
|
||||
fakeredis = "2.34.1"
|
||||
pytest-rerunfailures = "15.1"
|
||||
pytest-cov = "5.0.0"
|
||||
parameterized = "0.9.0"
|
||||
|
||||
[tool.poetry.group.proxy-dev.dependencies]
|
||||
prisma = "0.11.0"
|
||||
hypercorn = "0.17.3"
|
||||
prometheus-client = "0.20.0"
|
||||
opentelemetry-api = "1.28.0"
|
||||
opentelemetry-sdk = "1.28.0"
|
||||
opentelemetry-exporter-otlp = "1.28.0"
|
||||
azure-identity = {version = "1.25.3", python = ">=3.9"}
|
||||
a2a-sdk = {version = "0.3.25", python = ">=3.10"}
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core", "wheel"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.commitizen]
|
||||
version = "1.83.0"
|
||||
version_files = [
|
||||
"pyproject.toml:^version"
|
||||
"pyproject.toml:^version",
|
||||
]
|
||||
|
||||
[tool.mypy]
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
# LITELLM PROXY DEPENDENCIES #
|
||||
# Security: explicit pins for transitive deps (CVE fixes)
|
||||
urllib3==2.6.3 # CVE-2025-66471, CVE-2025-66418, CVE-2026-21441
|
||||
tornado==6.5.5 # CVE-2025-67725, CVE-2025-67726, CVE-2025-67724, CVE-2026-31958, GHSA-78cv-mqj4-43f7
|
||||
filelock==3.25.2 # CVE-2025-68146
|
||||
h11==0.16.0 # CVE-2025-43859, GHSA-vqfr-h8mv-ghfj — HTTP request smuggling
|
||||
wheel==0.46.3 # CVE-2026-24049 — path traversal
|
||||
Pillow==12.1.1 #GHSA-cfh3-3jmp-rvhc
|
||||
cryptography==46.0.5 #GHSA-r6ph-v2qm-q3c2
|
||||
|
||||
anyio==4.8.0 # openai + http req.
|
||||
httpx==0.28.1
|
||||
openai==2.30.0 # openai req.
|
||||
fastapi==0.124.4 # server dep
|
||||
starlette==0.49.1 # starlette fastapi dep
|
||||
backoff==2.2.1 # server dep
|
||||
pyyaml==6.0.3 # server dep
|
||||
uvicorn==0.33.0 # server dep
|
||||
gunicorn==23.0.0 # server dep
|
||||
fastuuid==0.14.0 # for uuid4
|
||||
uvloop==0.21.0 # uvicorn dep, gives us much better performance under load
|
||||
boto3==1.42.80 # aws bedrock/sagemaker calls
|
||||
redis==5.2.1 # redis caching
|
||||
redisvl==0.4.1 ## redis semantic caching
|
||||
prisma==0.11.0 # for db
|
||||
nodejs-wheel-binaries==24.13.1 ## required by prisma for migrations, prevents runtime download (updated from nodejs-bin for security fixes)
|
||||
mangum==0.17.0 # for aws lambda functions
|
||||
pynacl==1.6.2 # for encrypting keys
|
||||
google-cloud-aiplatform==1.133.0 # for vertex ai calls
|
||||
google-cloud-iam==2.19.1 # for GCP IAM Redis authentication
|
||||
google-genai==1.37.0
|
||||
anthropic[vertex]==0.54.0
|
||||
mcp==1.26.0 ; python_version >= "3.10" # for MCP server
|
||||
# google-generativeai removed - deprecated, replaced by google-genai (line 21)
|
||||
async_generator==1.10.0 # for async ollama calls
|
||||
langfuse==2.59.7 # for langfuse self-hosted logging
|
||||
prometheus_client==0.20.0 # for /metrics endpoint on proxy
|
||||
ddtrace==2.19.0 # for advanced DD tracing / profiling
|
||||
orjson==3.10.15 # fast /embedding responses
|
||||
polars==1.39.3 # for data processing
|
||||
apscheduler==3.11.2 # for resetting budget in background
|
||||
fastapi-sso==0.16.0 # admin UI, SSO
|
||||
pyjwt[crypto]==2.12.1 ; python_version >= "3.9"
|
||||
python-multipart==0.0.20 # admin UI
|
||||
jaraco.context==6.1.2
|
||||
azure-ai-contentsafety==1.0.0 # for azure content safety
|
||||
azure-identity==1.25.3 ; python_version >= "3.9" # for azure content safety
|
||||
azure-keyvault==4.2.0 # for azure KMS integration
|
||||
azure-storage-file-datalake==12.20.0 # for azure buck storage logging
|
||||
opentelemetry-api==1.28.0
|
||||
opentelemetry-sdk==1.28.0
|
||||
opentelemetry-exporter-otlp==1.28.0
|
||||
a2a-sdk==0.3.25 ; python_version >= "3.10"
|
||||
# grpcio: pinned to 1.80.0 (past reconnect bug #38290 in 1.68.x, has Python 3.14 wheels)
|
||||
grpcio==1.80.0
|
||||
sentry_sdk==2.21.0 # for sentry error handling
|
||||
detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests
|
||||
tzdata==2025.1 # IANA time zone database
|
||||
litellm-proxy-extras==0.4.62 # for proxy extras - e.g. prisma migrations
|
||||
llm-sandbox==0.3.31 # for skill execution in sandbox
|
||||
### LITELLM PACKAGE DEPENDENCIES
|
||||
python-dotenv==1.0.1 # for env
|
||||
tiktoken==0.12.0 # for calculating usage
|
||||
importlib-metadata==8.5.0 # for random utils
|
||||
tokenizers==0.22.2 # for calculating usage
|
||||
click==8.1.8 # for proxy cli
|
||||
rich==13.9.4 # for litellm proxy cli
|
||||
jinja2==3.1.6 # for prompt templates
|
||||
aiohttp==3.13.5 # for network calls
|
||||
tenacity==8.5.0 # for retrying requests, when litellm.num_retries set
|
||||
pydantic==2.12.5 # proxy + openai req. + mcp
|
||||
jsonschema==4.23.0 # validating json schema - aligned with openapi-core + mcp
|
||||
websockets==15.0.1 # for realtime API
|
||||
soundfile==0.12.1 # for audio file processing
|
||||
openapi-core==0.21.0 # for OpenAPI compliance tests
|
||||
pypdf==6.9.2 # for PDF text extraction in RAG ingestion (CVE-2026-27888)
|
||||
|
||||
# Transitive deps pinned to prevent floating between builds
|
||||
aiofiles==24.1.0 # transitive dep (langfuse)
|
||||
colorlog==6.10.1 # transitive dep (ddtrace)
|
||||
grpc-google-iam-v1==0.14.3 # transitive dep (google-cloud-iam)
|
||||
hf-xet==1.4.2 # transitive dep (huggingface_hub)
|
||||
requests-toolbelt==1.0.0 # transitive dep (langfuse)
|
||||
|
||||
########################
|
||||
# LITELLM ENTERPRISE DEPENDENCIES
|
||||
########################
|
||||
litellm-enterprise==0.1.35
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import tomllib
|
||||
|
||||
import requests
|
||||
from packaging.requirements import Requirement
|
||||
|
|
@ -52,6 +53,11 @@ class LicenseChecker:
|
|||
# Track package results
|
||||
self.package_results: List[PackageLicense] = []
|
||||
|
||||
@staticmethod
|
||||
def _normalize_package_name(package_name: str) -> str:
|
||||
"""Canonicalize package names so '-', '_' and '.' compare equivalently."""
|
||||
return re.sub(r"[-_.]+", "-", package_name).lower()
|
||||
|
||||
def _parse_license_list(self, section: str, option: str) -> Set[str]:
|
||||
"""Parse license list from config, handling comments and whitespace."""
|
||||
if not self.config.has_option(section, option):
|
||||
|
|
@ -70,7 +76,7 @@ class LicenseChecker:
|
|||
if self.config.has_section("Authorized Packages"):
|
||||
for package, spec in self.config.items("Authorized Packages"):
|
||||
if not package.startswith("#"):
|
||||
package = package.strip().lower()
|
||||
package = self._normalize_package_name(package.strip())
|
||||
parts = spec.split("#", 1)
|
||||
version_spec = parts[0].strip()
|
||||
comment = parts[1].strip() if len(parts) > 1 else ""
|
||||
|
|
@ -127,7 +133,7 @@ class LicenseChecker:
|
|||
|
||||
def check_package(self, package_name: str, version: Optional[str] = None) -> bool:
|
||||
"""Check if a specific package version is compliant."""
|
||||
package_lower = package_name.lower()
|
||||
package_lower = self._normalize_package_name(package_name)
|
||||
|
||||
# Check if package is in authorized packages list
|
||||
if package_lower in self.authorized_packages:
|
||||
|
|
@ -207,19 +213,45 @@ class LicenseChecker:
|
|||
|
||||
return is_acceptable
|
||||
|
||||
def check_requirements(self, requirements_file: Path) -> bool:
|
||||
"""Check all packages in a requirements file."""
|
||||
print(f"\nChecking licenses for packages in {requirements_file}...")
|
||||
def _load_requirements(
|
||||
self, requirements_file: Optional[Path] = None
|
||||
) -> List[Requirement]:
|
||||
"""Load pinned requirements from a file or from the root pyproject.toml."""
|
||||
try:
|
||||
if requirements_file is not None:
|
||||
with open(requirements_file) as f:
|
||||
requirement_lines = f.readlines()
|
||||
else:
|
||||
with open("pyproject.toml", "rb") as f:
|
||||
pyproject = tomllib.load(f)
|
||||
|
||||
requirement_lines = list(pyproject["project"].get("dependencies", []))
|
||||
for extra_reqs in pyproject["project"].get(
|
||||
"optional-dependencies", {}
|
||||
).values():
|
||||
requirement_lines.extend(extra_reqs)
|
||||
|
||||
# Preserve declaration order while removing duplicates.
|
||||
requirement_lines = list(dict.fromkeys(requirement_lines))
|
||||
|
||||
return [
|
||||
Requirement(line.split("#")[0].strip())
|
||||
for line in requirement_lines
|
||||
if line.split("#")[0].strip() and not line.startswith("#")
|
||||
]
|
||||
except Exception as e:
|
||||
source = requirements_file or "uv export"
|
||||
raise RuntimeError(f"Error parsing requirements from {source}: {str(e)}") from e
|
||||
|
||||
def check_requirements(self, requirements_file: Optional[Path] = None) -> bool:
|
||||
"""Check all packages from a requirements file or the root pyproject."""
|
||||
source = requirements_file or "pyproject.toml"
|
||||
print(f"\nChecking licenses for packages in {source}...")
|
||||
|
||||
try:
|
||||
with open(requirements_file) as f:
|
||||
requirements = [
|
||||
Requirement(line.split("#")[0].strip())
|
||||
for line in f
|
||||
if line.split("#")[0].strip() and not line.startswith("#")
|
||||
]
|
||||
except Exception as e:
|
||||
print(f"Error parsing {requirements_file}: {str(e)}")
|
||||
requirements = self._load_requirements(requirements_file)
|
||||
except RuntimeError as e:
|
||||
print(str(e))
|
||||
return False
|
||||
|
||||
all_compliant = True
|
||||
|
|
@ -243,12 +275,11 @@ class LicenseChecker:
|
|||
|
||||
|
||||
def main():
|
||||
# req_file = "../../requirements.txt" ## LOCAL TESTING
|
||||
req_file = "./requirements.txt"
|
||||
req_file = Path(sys.argv[1]) if len(sys.argv) > 1 else None
|
||||
checker = LicenseChecker()
|
||||
|
||||
# Check requirements
|
||||
if not checker.check_requirements(Path(req_file)):
|
||||
if not checker.check_requirements(req_file):
|
||||
# Get lists of problematic packages
|
||||
unverified = [p for p in checker.package_results if not p.license_type]
|
||||
invalid = [
|
||||
|
|
@ -272,7 +303,7 @@ def main():
|
|||
unhandled_packages = [
|
||||
p
|
||||
for p in (unverified + invalid)
|
||||
if p.name.lower() not in checker.authorized_packages
|
||||
if checker._normalize_package_name(p.name) not in checker.authorized_packages
|
||||
]
|
||||
|
||||
if unhandled_packages:
|
||||
|
|
|
|||
|
|
@ -136,7 +136,10 @@ pydantic: >=2.10.2 # Unknown license
|
|||
jsonschema: >=4.22.0 # Unknown license
|
||||
websockets: >=13.1.0 # Unknown license
|
||||
polars: >=1.31.0 # Unknown license, the license.md allows free of charge use
|
||||
semantic_router: >=0.1.10 # Unknown license
|
||||
rq: >=2.7.0 # BSD-2-Clause License
|
||||
resend: >=2.23.0 # MIT License
|
||||
semantic_router: >=0.1.10 # MIT License
|
||||
aurelio-sdk: >=0.0.19 # MIT License
|
||||
pondpond: >=1.4.1 # Apache 2.0 License
|
||||
fastuuid: >=0.13.0 # BSD-3-Clause license
|
||||
llm-sandbox: >=0.3.31 # MIT License - https://github.com/vndee/llm-sandbox
|
||||
|
|
|
|||
|
|
@ -18,14 +18,12 @@ def test_using_litellm():
|
|||
|
||||
print("litellm imported successfully")
|
||||
except Exception as e:
|
||||
pytest.fail(
|
||||
f"Error occurred: {e}. Installing litellm on python3.8 failed please retry"
|
||||
)
|
||||
pytest.fail(f"Error occurred: {e}. Installing litellm failed please retry")
|
||||
|
||||
|
||||
def test_litellm_proxy_server():
|
||||
# Install the local litellm[proxy] package in development mode
|
||||
subprocess.run(["pip", "install", "-e", ".[proxy]"])
|
||||
# Sync the local litellm[proxy] dependencies into the project environment
|
||||
subprocess.run(["uv", "sync", "--frozen", "--extra", "proxy"], check=True)
|
||||
|
||||
# Import the proxy_server module
|
||||
try:
|
||||
|
|
@ -39,11 +37,12 @@ def test_litellm_proxy_server():
|
|||
|
||||
def test_package_dependencies():
|
||||
"""
|
||||
Test that all optional dependencies are correctly specified in extras.
|
||||
Test that all optional dependency entries are exposed via project optional-dependencies.
|
||||
"""
|
||||
try:
|
||||
import pathlib
|
||||
import litellm
|
||||
from packaging.requirements import Requirement
|
||||
|
||||
# Try to import tomllib (Python 3.11+) or tomli (older versions)
|
||||
try:
|
||||
|
|
@ -62,28 +61,22 @@ def test_package_dependencies():
|
|||
with open(pyproject_path, "rb") as f:
|
||||
pyproject = tomli.load(f)
|
||||
|
||||
# Get all optional dependencies from poetry.dependencies
|
||||
poetry_deps = pyproject["tool"]["poetry"]["dependencies"]
|
||||
optional_deps = {
|
||||
name.lower()
|
||||
for name, value in poetry_deps.items()
|
||||
if isinstance(value, dict) and value.get("optional", False)
|
||||
}
|
||||
print(optional_deps)
|
||||
# Get all packages listed in extras
|
||||
extras = pyproject["tool"]["poetry"]["extras"]
|
||||
all_extra_deps = set()
|
||||
for extra_group in extras.values():
|
||||
all_extra_deps.update(dep.lower() for dep in extra_group)
|
||||
print(all_extra_deps)
|
||||
# Check that all optional dependencies are in some extras group
|
||||
missing_from_extras = optional_deps - all_extra_deps
|
||||
assert (
|
||||
not missing_from_extras
|
||||
), f"Optional dependencies missing from extras: {missing_from_extras}"
|
||||
optional_deps = pyproject["project"]["optional-dependencies"]
|
||||
assert optional_deps, "Expected project.optional-dependencies to be defined"
|
||||
|
||||
parsed_requirements = set()
|
||||
for extra_name, requirements in optional_deps.items():
|
||||
assert requirements, f"Optional dependency group '{extra_name}' is empty"
|
||||
for requirement in requirements:
|
||||
assert isinstance(
|
||||
requirement, str
|
||||
), f"Expected string requirement in extra '{extra_name}'"
|
||||
parsed = Requirement(requirement)
|
||||
parsed_requirements.add(parsed.name.lower())
|
||||
|
||||
print(parsed_requirements)
|
||||
print(
|
||||
f"All {len(optional_deps)} optional dependencies are correctly specified in extras"
|
||||
f"Validated {len(parsed_requirements)} optional dependencies across {len(optional_deps)} extras groups"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -102,11 +95,13 @@ import requests
|
|||
|
||||
|
||||
def test_litellm_proxy_server_config_no_general_settings():
|
||||
# Install the local litellm packages in development mode
|
||||
# Sync the local litellm packages into the project environment
|
||||
server_process = None
|
||||
try:
|
||||
subprocess.run(["pip", "install", "-e", ".[proxy]"])
|
||||
subprocess.run(["pip", "install", "-e", ".[extra_proxy]"])
|
||||
subprocess.run(
|
||||
["uv", "sync", "--frozen", "--group", "proxy-dev", "--extra", "proxy", "--extra", "extra_proxy"],
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Ensure Prisma client is generated
|
||||
try:
|
||||
|
|
@ -115,7 +110,7 @@ def test_litellm_proxy_server_config_no_general_settings():
|
|||
print(f"Running prisma generate from: {project_root}")
|
||||
|
||||
result = subprocess.run(
|
||||
["prisma", "generate"],
|
||||
["uv", "run", "--no-sync", "prisma", "generate"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue