mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-15 09:12:18 +00:00
chore(lint): clear the last violation of 11 strict ruff rules
Each of these rules sat at a limit of 1 in ruff-strict-budget.json, 2 for B004, so a single lingering violation apiece was all that kept them ratcheted instead of hard-failing. Clearing them takes each to zero, which is what the header of ruff.toml describes as the precondition for moving a rule into extend-select Three carry real behavior. B004 rewrites two getattr(x, "__call__") probes as callable(x). Ruff's own hint says to replace the whole expression with callable(), which would be wrong here, because both sites need the __call__ object itself to hand to inspect.iscoroutinefunction. callable() resolves __call__ on the type the way an actual call does, so an object carrying __call__ as an instance attribute is no longer reported as an async callable when calling it would raise TypeError B021 drops an f prefix from JavelinGuardrail.__init__'s docstring. Python evaluated it as an f-string expression and threw it away, so __doc__ was None. PLR0206 removes an api_version parameter from a property getter on AzureFoundryModelInfo: attribute access cannot pass arguments, so that parameter was unreachable and read as None every time The rest preserve behavior exactly. A dict comprehension, a generator handed to any(), != over not ==, a plain boolean over a conditional expression, a constant over None or "success", math.isfinite over a NaN self-comparison paired with an inf membership test, a loop variable that no longer shadows the enclosing model argument, and a dead sys.version_info >= (3, 8) branch under a >=3.10 floor B019 and N999 are left for separate PRs. B019 needs the lru_cache moved off the method onto a per-instance cache, and four test files assert on cache_info. N999 renames litellm/proxy/lambda.py, which deployment config points at ruff-strict-budget.json is deliberately untouched, per CLAUDE.md
This commit is contained in:
parent
9dbfb060bd
commit
c3fc8aedb7
13 changed files with 34 additions and 25 deletions
|
|
@ -4,18 +4,10 @@ imported_openAIResponse = True
|
|||
try:
|
||||
import io
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, TypeVar
|
||||
from typing import Any, Literal, Protocol, TypeVar
|
||||
|
||||
from wandb.sdk.data_types import trace_tree
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal, Protocol
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
from typing_extensions import Protocol
|
||||
|
||||
logger: Final = logging.getLogger(__name__)
|
||||
|
||||
K = TypeVar("K", bound=str)
|
||||
|
|
|
|||
|
|
@ -36,9 +36,8 @@ class CoroutineChecker:
|
|||
target = callback
|
||||
if not inspect.isfunction(target) and not inspect.ismethod(target):
|
||||
try:
|
||||
call_attr: Final = getattr(target, "__call__", None)
|
||||
if call_attr is not None:
|
||||
target = call_attr
|
||||
if callable(target):
|
||||
target = target.__call__
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -1756,7 +1756,7 @@ def convert_to_anthropic_tool_invoke(
|
|||
anthropic_tool_invoke: Final[list[AnthropicMessagesToolUseParam | dict[str, object]]] = []
|
||||
|
||||
for tool in tool_calls:
|
||||
if not get_attribute_or_key(tool, "type") == "function":
|
||||
if get_attribute_or_key(tool, "type") != "function":
|
||||
continue
|
||||
|
||||
tool_id = cast(str, get_attribute_or_key(tool, "id"))
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ def token_counter(
|
|||
params: Final = _MessageCountParams(model, custom_tokenizer)
|
||||
num_tokens = _count_messages(params, new_messages, use_default_image_token_count, default_token_count)
|
||||
if count_response_tokens is False:
|
||||
includes_system_message: Final = any([message.get("role", None) == "system" for message in new_messages])
|
||||
includes_system_message: Final = any(message.get("role", None) == "system" for message in new_messages)
|
||||
num_tokens += _count_extra(params.count_function, tools, tool_choice, includes_system_message)
|
||||
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -138,9 +138,8 @@ class AzureFoundryModelInfo(BaseLLMModelInfo):
|
|||
return api_key or litellm.api_key or get_secret_str("AZURE_AI_API_KEY")
|
||||
|
||||
@property
|
||||
def api_version(self, api_version: str | None = None) -> str | None:
|
||||
api_version = api_version or litellm.api_version or get_secret_str("AZURE_API_VERSION")
|
||||
return api_version
|
||||
def api_version(self) -> str | None:
|
||||
return litellm.api_version or get_secret_str("AZURE_API_VERSION")
|
||||
|
||||
def get_token_counter(self) -> BaseTokenCounter | None:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class JavelinGuardrail(CustomGuardrail):
|
|||
application: str | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
f"""
|
||||
"""
|
||||
Initialize the JavelinGuardrail class.
|
||||
|
||||
This calls: {api_base}/{api_version}/guardrail/{guardrail_name}/apply
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ def initialize_guardrail(litellm_params: "LitellmParams", guardrail: "Guardrail"
|
|||
# We check the raw guardrail dict because LitellmParams normalizes None → False,
|
||||
# making it impossible to distinguish "not set" from "explicitly false" via litellm_params.
|
||||
_raw_default_on: Final = cast(dict[str, Any], guardrail).get("litellm_params", {}).get("default_on")
|
||||
_default_on: Final = False if _raw_default_on is False else True
|
||||
_default_on: Final = _raw_default_on is not False
|
||||
|
||||
_callback: Final = MCPEndUserPermissionGuardrail(
|
||||
guardrail_name=guardrail.get("guardrail_name", ""),
|
||||
|
|
|
|||
|
|
@ -116,7 +116,8 @@ async def run_team_metadata_validation(
|
|||
},
|
||||
)
|
||||
if not (
|
||||
inspect.iscoroutinefunction(validator) or inspect.iscoroutinefunction(getattr(validator, "__call__", None))
|
||||
inspect.iscoroutinefunction(validator)
|
||||
or (callable(validator) and inspect.iscoroutinefunction(validator.__call__))
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ def _get_spend_logs_metadata(
|
|||
requester_ip_address=None,
|
||||
additional_usage_values=None,
|
||||
applied_guardrails=None,
|
||||
status=None or "success",
|
||||
status="success",
|
||||
error_information=None,
|
||||
proxy_server_request=None,
|
||||
batch_models=None,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import copy
|
|||
import hashlib
|
||||
import inspect
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import smtplib
|
||||
import ssl
|
||||
|
|
@ -5887,7 +5888,7 @@ class PrismaClient:
|
|||
return None
|
||||
try:
|
||||
value: Final = float(response_time_ms)
|
||||
return value if value == value and value not in (float("inf"), float("-inf")) else None
|
||||
return value if math.isfinite(value) else None
|
||||
except (ValueError, TypeError):
|
||||
verbose_proxy_logger.warning("Invalid response_time_ms value: %s", response_time_ms)
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -4024,9 +4024,9 @@ class Router:
|
|||
except KeyError:
|
||||
pass
|
||||
|
||||
for model in models:
|
||||
for model_name in models:
|
||||
task = asyncio.create_task(
|
||||
_async_completion_no_exceptions(model=model, messages=messages, stream=stream, **kwargs)
|
||||
_async_completion_no_exceptions(model=model_name, messages=messages, stream=stream, **kwargs)
|
||||
)
|
||||
pending_tasks.append(task)
|
||||
|
||||
|
|
|
|||
|
|
@ -6188,7 +6188,7 @@ def function_to_dict(input_function) -> dict:
|
|||
"enum": param_enum,
|
||||
}
|
||||
|
||||
parameters[param_name] = dict([(k, v) for k, v in param_dict.items() if isinstance(v, str)])
|
||||
parameters[param_name] = {k: v for k, v in param_dict.items() if isinstance(v, str)}
|
||||
|
||||
# Check if the parameter has no default value (i.e., it's required)
|
||||
if param.default == param.empty:
|
||||
|
|
|
|||
|
|
@ -84,6 +84,23 @@ class TestCoroutineChecker:
|
|||
assert self.checker.is_async_callable(obj.sync_method) is False
|
||||
assert self.checker.is_async_callable(SyncCallable()) is False
|
||||
|
||||
def test_instance_attribute_dunder_call_is_not_callable(self):
|
||||
"""An async __call__ set on the instance does not make the object callable."""
|
||||
|
||||
async def async_func():
|
||||
return "async"
|
||||
|
||||
class NotCallable:
|
||||
pass
|
||||
|
||||
obj = NotCallable()
|
||||
obj.__call__ = async_func # readable attribute, but never used for a call
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
obj()
|
||||
|
||||
assert self.checker.is_async_callable(obj) is False
|
||||
|
||||
def test_is_async_callable_caching(self):
|
||||
"""Test that is_async_callable caches callable objects."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue