This commit is contained in:
yujonglee 2026-11-06 00:04:57 +00:00 • committed by GitHub
commit 11150347e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 139 additions and 0 deletions

View file

@ -0,0 +1,44 @@
import inspect
import os
import sys
import traceback
import warnings
from collections.abc import Mapping
from pathlib import Path
from types import MappingProxyType
from typing import Final
_LITELLM_ROOT: Final = f"{Path(__file__).parents[1]}{os.sep}"
_DEPRECATED: Final = MappingProxyType(
{
"client": (
"client= is deprecated: litellm is moving requests to Rust, which cannot use a caller's HTTP client. "
"Set network options with litellm.ssl_verify, litellm.ssl_certificate, or proxy and SSL environment "
"variables instead"
)
}
)
def _first_stacklevel_outside_litellm() -> int:
return next(
(
level
for level, (frame, _) in enumerate(traceback.walk_stack(inspect.currentframe()))
if not frame.f_code.co_filename.startswith(_LITELLM_ROOT)
),
1,
)
def warn_deprecated(name: str) -> None:
if sys.version_info >= (3, 12):
warnings.warn(_DEPRECATED[name], DeprecationWarning, skip_file_prefixes=(_LITELLM_ROOT,))
return
warnings.warn(_DEPRECATED[name], DeprecationWarning, stacklevel=_first_stacklevel_outside_litellm())
def warn_deprecated_in(kwargs: Mapping[str, object]) -> None:
for name in (name for name in _DEPRECATED if kwargs.get(name) is not None):
warn_deprecated(name)

View file

@ -111,6 +111,7 @@ from litellm.litellm_core_utils.tool_fields import (
from litellm.rust_bridge import tokenizer as tokenizer_dispatch
from litellm.rust_bridge.catalog import decision
from litellm.rust_bridge.configuration import Decision
from litellm.rust_bridge.deprecated_arguments import warn_deprecated_in
_CachingHandlerResponse = None
_LLMCachingHandler = None
@ -1267,6 +1268,7 @@ def function_setup(
**kwargs: Any, # kwargs-ok: forwarded to Logging()/callbacks, varies per call_type
) -> tuple[LiteLLMLoggingObject, dict[str, Any]]:
### NOTICES ###
warn_deprecated_in(kwargs)
if litellm.set_verbose is True:
verbose_logger.warning(
"`litellm.set_verbose` is deprecated. Please set `os.environ['LITELLM_LOG'] = 'DEBUG'` for debug logs."

View file

@ -1,3 +1,4 @@
import warnings
from collections.abc import Mapping
from typing import Final, NoReturn
@ -44,6 +45,26 @@ async def test_ocr_does_not_depend_on_chat_cache(
assert len(server.requests) == 1
@pytest.mark.asyncio
@pytest.mark.parametrize("asynchronous", [False, True])
async def test_ocr_warns_that_a_caller_client_is_ignored(server: RecordingServer, asynchronous: bool) -> None:
arguments: Final = {
"model": OCR_MODEL,
"document": OCR_DOCUMENT,
"api_key": "test-key",
"api_base": server.base_url,
"client": object(),
}
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
response: Final = await litellm.aocr(**arguments) if asynchronous else litellm.ocr(**arguments)
ignored: Final = [warning for warning in caught if "client=" in str(warning.message)]
assert response.pages[0].markdown == "native OCR response"
assert len(server.requests) == 1
assert [(warning.category, warning.filename) for warning in ignored] == [(DeprecationWarning, __file__)]
@pytest.mark.parametrize("failure", ["invalid", "live", "schema"])
def test_native_projection_errors_never_select_python(
server: RecordingServer, monkeypatch: pytest.MonkeyPatch, failure: str

View file

@ -1,8 +1,10 @@
from __future__ import annotations
import warnings
from collections.abc import Generator
from typing import Final
import openai
import pytest
import litellm
@ -301,3 +303,43 @@ def test_bedrock_transcription_rejects_params_it_cannot_honor(unsupported: dict[
forwarded: Final = bridge.calls[0].resolved["optional_params"]
assert forwarded["language"] == "fr"
assert forwarded.keys().isdisjoint(unsupported)
def test_bedrock_transcription_warns_that_a_caller_client_is_ignored() -> None:
bridge: Final = SyncBridge()
NATIVE_TRANSCRIPTION.override(bridge)
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
response: Final = litellm.transcription(model=MODEL, file=AUDIO_FILE, client=object())
ignored: Final = [warning for warning in caught if "client=" in str(warning.message)]
assert response.text == "rust"
assert len(bridge.calls) == 1
assert [(warning.category, warning.filename) for warning in ignored] == [(DeprecationWarning, __file__)]
@pytest.mark.asyncio
async def test_bedrock_atranscription_warns_once_that_a_caller_client_is_deprecated() -> None:
bridge: Final = AsyncBridge()
NATIVE_ATRANSCRIPTION.override(bridge)
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
response: Final = await litellm.atranscription(model=MODEL, file=AUDIO_FILE, client=object())
ignored: Final = [warning for warning in caught if "client=" in str(warning.message)]
assert response.text == "async rust"
assert [(warning.category, warning.filename) for warning in ignored] == [(DeprecationWarning, __file__)]
def test_python_served_transcription_warns_that_a_caller_client_is_deprecated() -> None:
client: Final = openai.OpenAI(api_key="sk-test", base_url="http://127.0.0.1:9", max_retries=0)
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
with pytest.raises(openai.APIConnectionError, match="Connection error"):
litellm.transcription(model="openai/whisper-1", file=AUDIO_FILE, client=client)
ignored: Final = [warning for warning in caught if "client=" in str(warning.message)]
assert [(warning.category, warning.filename) for warning in ignored] == [(DeprecationWarning, __file__)]

View file

@ -13,6 +13,7 @@ import queue
import threading
import time
import uuid
import warnings
from collections.abc import Callable, Iterator, Mapping
from concurrent.futures import Future, ThreadPoolExecutor
from datetime import datetime, timedelta, timezone
@ -11626,3 +11627,32 @@ async def test_success_enqueue_is_tracked_without_starting_callbacks_synchronous
assert GLOBAL_LOGGING_WORKER.pending_count > 0, "Tracked enqueue must finish before worker draining starts"
await GLOBAL_LOGGING_WORKER.flush()
assert logging_obj.model_call_details["has_logged_async_success"] is True
def _client_deprecations(caught: list[warnings.WarningMessage]) -> list[tuple[type[Warning], str]]:
return [(warning.category, warning.filename) for warning in caught if "client=" in str(warning.message)]
@pytest.mark.asyncio
@pytest.mark.parametrize("asynchronous", [False, True])
async def test_python_served_call_keeps_the_client_but_warns_once_that_it_is_deprecated(asynchronous: bool) -> None:
arguments: Final = {
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "hi"}],
"mock_response": "hi",
"client": object(),
}
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
response: Final = await litellm.acompletion(**arguments) if asynchronous else litellm.completion(**arguments)
assert response.choices[0].message.content == "hi"
assert _client_deprecations(caught) == [(DeprecationWarning, __file__)]
def test_call_without_a_client_does_not_warn() -> None:
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
litellm.completion(model="gpt-4o-mini", messages=[{"role": "user", "content": "hi"}], mock_response="hi")
assert _client_deprecations(caught) == []