diff --git a/litellm/proxy/_lazy_features.py b/litellm/proxy/_lazy_features.py index 1da42fae6b6..f4d80833dbb 100644 --- a/litellm/proxy/_lazy_features.py +++ b/litellm/proxy/_lazy_features.py @@ -384,7 +384,7 @@ def _lazy_slots(app: "FastAPI") -> Mapping[str, BaseRoute | None]: return app.state.lazy_slots if hasattr(app.state, "lazy_slots") else MappingProxyType({}) -def _lazy_routes(app: "FastAPI") -> Mapping[str, tuple[BaseRoute, ...]]: +def lazy_feature_routes(app: "FastAPI") -> Mapping[str, tuple[BaseRoute, ...]]: return app.state.lazy_routes if hasattr(app.state, "lazy_routes") else MappingProxyType({}) @@ -499,7 +499,7 @@ def _register_feature(app: "FastAPI", feat: LazyFeature, module: object, feature before: Final = len(app.router.routes) feat.register_fn(app, module) lazy_routes: Final[Mapping[str, tuple[BaseRoute, ...]]] = MappingProxyType( - {**_lazy_routes(app), feat.module_path: tuple(app.router.routes[before:])} + {**lazy_feature_routes(app), feat.module_path: tuple(app.router.routes[before:])} ) app.state.lazy_routes = lazy_routes # rebind-ok: the app owns the record of which routes each feature added app.router.routes[:] = _route_table( # rebind-ok: the app owns its route table @@ -565,7 +565,10 @@ def _register_all_on_startup(inner: "Lifespan[FastAPI]", features: tuple[LazyFea def _restore_registry_order(app: "FastAPI", features: tuple[LazyFeature, ...]) -> None: present: Final = frozenset(id(route) for route in app.router.routes) still_routed: Final = MappingProxyType( - {module_path: tuple(r for r in routes if id(r) in present) for module_path, routes in _lazy_routes(app).items()} + { + module_path: tuple(r for r in routes if id(r) in present) + for module_path, routes in lazy_feature_routes(app).items() + } ) app.router.routes[:] = _route_table( # rebind-ok: the app owns its route table app, app.router.routes, still_routed, features @@ -621,7 +624,7 @@ def lazy_owned_routes(app: "FastAPI") -> frozenset[int]: """ids of the routes lazy features have registered on this app. A route added later at one of their paths (a config pass-through at /v1/decisions) goes ahead of them, the precedence lazy mode gives it when the feature has not loaded by the time the config is read.""" - return frozenset(id(route) for route in chain.from_iterable(_lazy_routes(app).values())) + return frozenset(id(route) for route in chain.from_iterable(lazy_feature_routes(app).values())) def loaded_lazy_modules(app: "FastAPI") -> frozenset[str]: diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 2231706b282..399d1f4e676 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -3350,7 +3350,13 @@ async def _load_team_member_default_model_budget( skip_budget_checks: bool, proxy_logging_obj: ProxyLogging | None, ) -> None: - team_metadata_value: Final[object] = getattr(team_object, "metadata", None) if team_object is not None else None + team_metadata_value: Final[object] = ( + cast( # cast-ok: team metadata is a string-keyed JSON object + object, team_object.metadata + ) + if team_object is not None + else None + ) team_metadata: Final[Mapping[str, object] | None] = ( cast( # cast-ok: team metadata is a string-keyed JSON object Mapping[str, object], team_metadata_value @@ -3378,7 +3384,11 @@ async def _load_team_member_default_model_budget( ) member_budget_row: Final = membership.litellm_budget_table if membership is not None else None member_budget_value: Final[object] = ( - getattr(member_budget_row, "model_max_budget", None) if member_budget_row is not None else None + cast( # cast-ok: budget table stores a string-keyed JSON object + object, member_budget_row.model_max_budget + ) + if member_budget_row is not None + else None ) if ( membership is not None @@ -3406,7 +3416,9 @@ async def _load_team_member_default_model_budget( return default_budget_value: Final[object] = ( - getattr(team_member_default_budget, "model_max_budget", None) + cast( # cast-ok: budget table stores a string-keyed JSON object + object, team_member_default_budget.model_max_budget + ) if team_member_default_budget is not None else None ) diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index d6358c638e7..51dccd1b4b3 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -73,7 +73,7 @@ from litellm.llms.base_llm.managed_resources.utils import ( from litellm.llms.custom_httpx.http_handler import get_async_httpx_client from litellm.llms.oss_decision import validate_oss_request from litellm.passthrough import BasePassthroughUtils -from litellm.proxy._lazy_features import lazy_owned_routes +from litellm.proxy._lazy_features import lazy_feature_routes, lazy_owned_routes from litellm.proxy._types import ( ConfigFieldInfo, ConfigFieldUpdate, @@ -3089,11 +3089,8 @@ class SafeRouteAdder: app.router.routes[:] = _placed_ahead( # rebind-ok: the app owns its route table app.router.routes, app.router.routes[-1], shadowed[0] ) - lazy_routes: Final[Mapping[str, tuple[BaseRoute, ...]] | None] = getattr( - getattr(app, "state", None), "lazy_routes", None - ) - if lazy_routes is not None and not builtin_pass_through_routes_first(): - builtin: Final = tuple(chain.from_iterable(lazy_routes.values())) + if not builtin_pass_through_routes_first(): + builtin: Final = tuple(chain.from_iterable(lazy_feature_routes(app).values())) if shadowed_by_builtin_claim(path, builtin): app.router.routes[:] = configured_pass_through_routes_first( # rebind-ok: the app owns its route table app.router.routes, builtin