diff --git a/litellm/integrations/weights_biases.py b/litellm/integrations/weights_biases.py index 97a2acbac08..d1a8ec098cf 100644 --- a/litellm/integrations/weights_biases.py +++ b/litellm/integrations/weights_biases.py @@ -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) diff --git a/litellm/litellm_core_utils/coroutine_checker.py b/litellm/litellm_core_utils/coroutine_checker.py index 52fc44ba8dc..0335ec9bdc7 100644 --- a/litellm/litellm_core_utils/coroutine_checker.py +++ b/litellm/litellm_core_utils/coroutine_checker.py @@ -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 diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index 56c1d605700..2d549595e05 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -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")) diff --git a/litellm/litellm_core_utils/token_counter.py b/litellm/litellm_core_utils/token_counter.py index 3732ffd734c..830303f49cb 100644 --- a/litellm/litellm_core_utils/token_counter.py +++ b/litellm/litellm_core_utils/token_counter.py @@ -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: diff --git a/litellm/llms/azure_ai/common_utils.py b/litellm/llms/azure_ai/common_utils.py index aa34bab5b2e..0dbe999f51d 100644 --- a/litellm/llms/azure_ai/common_utils.py +++ b/litellm/llms/azure_ai/common_utils.py @@ -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: """ diff --git a/litellm/proxy/guardrails/guardrail_hooks/javelin/javelin.py b/litellm/proxy/guardrails/guardrail_hooks/javelin/javelin.py index 3e5d8fb311d..e54e07b6a1b 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/javelin/javelin.py +++ b/litellm/proxy/guardrails/guardrail_hooks/javelin/javelin.py @@ -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 diff --git a/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/__init__.py b/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/__init__.py index a911c78ddc3..95db4bd4f77 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/__init__.py +++ b/litellm/proxy/guardrails/guardrail_hooks/mcp_end_user_permission/__init__.py @@ -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", ""), diff --git a/litellm/proxy/management_helpers/team_metadata_validation.py b/litellm/proxy/management_helpers/team_metadata_validation.py index 7bc66c240c7..81e75bf224a 100644 --- a/litellm/proxy/management_helpers/team_metadata_validation.py +++ b/litellm/proxy/management_helpers/team_metadata_validation.py @@ -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, diff --git a/litellm/proxy/spend_tracking/spend_tracking_utils.py b/litellm/proxy/spend_tracking/spend_tracking_utils.py index 8a06bf68b81..4d69bf2cdbc 100644 --- a/litellm/proxy/spend_tracking/spend_tracking_utils.py +++ b/litellm/proxy/spend_tracking/spend_tracking_utils.py @@ -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, diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index ddf31cb1d8a..4a430d08e6d 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -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 diff --git a/litellm/router.py b/litellm/router.py index 95cabfad4bd..0761ad7315c 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -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) diff --git a/litellm/utils.py b/litellm/utils.py index d0e11bc9551..9c241b8b40f 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -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: diff --git a/tests/test_litellm/litellm_core_utils/test_coroutine_checker.py b/tests/test_litellm/litellm_core_utils/test_coroutine_checker.py index 04fc4fc6645..2654264ba22 100644 --- a/tests/test_litellm/litellm_core_utils/test_coroutine_checker.py +++ b/tests/test_litellm/litellm_core_utils/test_coroutine_checker.py @@ -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."""