From 80b1b9b1889845eb686dd64691a14656c21b8a66 Mon Sep 17 00:00:00 2001 From: Mateo Wang <277851410+mateo-berri@users.noreply.github.com> Date: Thu, 5 Nov 2026 16:50:53 -0800 Subject: [PATCH] fix(router): let type checkers see the real Router constructor arguments (#50278) --- .../management_endpoints/router_settings_endpoints.py | 2 +- litellm/router.py | 11 ++++++++--- litellm/router_utils/handle_error.py | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/management_endpoints/router_settings_endpoints.py b/litellm/proxy/management_endpoints/router_settings_endpoints.py index 9951891fd07..013eb1ebff4 100644 --- a/litellm/proxy/management_endpoints/router_settings_endpoints.py +++ b/litellm/proxy/management_endpoints/router_settings_endpoints.py @@ -68,7 +68,7 @@ def _get_routing_strategies_from_router_class() -> list[str]: Dynamically extract routing strategies from the Router class __init__ method. """ # Get the __init__ signature - sig: Final = inspect.signature(Router.__init__) + sig: Final = inspect.signature(Router) # Get the routing_strategy parameter routing_strategy_param: Final = sig.parameters.get("routing_strategy") diff --git a/litellm/router.py b/litellm/router.py index a5d72daea1e..4b51c16aa81 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # ``Router(...)``'s parameters, their defaults and its docstring: ``router_arguments`` binds a call # against them and ``Router.__init__`` reports them. The body is never run. def _router_init( - self, + self: object, model_list: list[DeploymentTypedDict] | list[dict[str, Any]] | None = None, ## ASSISTANTS API ## assistants_config: AssistantsTypedDict | None = None, @@ -222,17 +222,22 @@ def _class_descriptor(cls: type, name: str) -> bool: if TYPE_CHECKING: - from typing import overload + from typing import ParamSpec, overload from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper from litellm.types.llms.openai import AllMessageValues, OpenAIFileObject from litellm.types.utils import EmbeddingResponse, LiteLLMBatch, ModelResponse + _P: Final = ParamSpec("_P") + + def _takes_parameters_of(source: Callable[_P, None]) -> Callable[[Callable[..., None]], Callable[_P, None]]: ... + class Router(RustCore, DeprecatedRouterMembers): """What type checkers see: the constructor's parameters and the endpoints' return types. The endpoints are served by the core at run time (litellm/router_rust/invoke/endpoints.py).""" - __init__ = _router_init # pyright: ignore[reportAssignmentType, reportIncompatibleMethodOverride] # Router(...)'s parameters + @_takes_parameters_of(_router_init) + def __init__(self) -> None: ... # pyright: ignore[reportMissingSuperCall] # a type-checking stub @classmethod def from_config(cls, config: RouterConfig, host: PythonHost = python_host) -> "Router": ... diff --git a/litellm/router_utils/handle_error.py b/litellm/router_utils/handle_error.py index 6033024123f..97bf4710fca 100644 --- a/litellm/router_utils/handle_error.py +++ b/litellm/router_utils/handle_error.py @@ -26,7 +26,7 @@ async def send_llm_exception_alert( ctx: "RoutingContext | None", request_kwargs: dict, error_traceback_str: str, - original_exception, + original_exception: Exception, ): """ Only runs if router.slack_alerting_logger is set @@ -34,7 +34,7 @@ async def send_llm_exception_alert( Parameters: ctx (RoutingContext): The router's routing context. - original_exception (Any): The original exception that occurred. + original_exception (Exception): The original exception that occurred. Returns: None