From 39d81380ba34a6d3d519ce4faef24046ef47b62e Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sat, 29 Aug 2026 19:25:48 +0000 Subject: [PATCH] chore(lint): fix post-merge type regressions and ratchet lint budgets --- basedpyright-code-budget.json | 20 +++++++++---------- litellm/caching/valkey_semantic_cache.py | 5 +++-- .../arize/arize_phoenix_prompt_manager.py | 6 ++++-- .../context_management/editors/compact.py | 15 +++++++++----- litellm/llms/vertex_ai/common_utils.py | 7 ++++--- .../guardrail_hooks/bedrock_guardrails.py | 4 +--- litellm/proxy/litellm_pre_call_utils.py | 6 ++++-- .../key_management_endpoints.py | 5 ++++- ruff-strict-budget.json | 16 +++++++-------- type-discipline-budget.json | 8 ++++---- 10 files changed, 52 insertions(+), 40 deletions(-) diff --git a/basedpyright-code-budget.json b/basedpyright-code-budget.json index ef88ae574fb..00c79c1e418 100644 --- a/basedpyright-code-budget.json +++ b/basedpyright-code-budget.json @@ -1,9 +1,9 @@ { "reportAny": { - "limit": 17270 + "limit": 16279 }, "reportArgumentType": { - "limit": 2539 + "limit": 2530 }, "reportAssignmentType": { "limit": 319 @@ -24,7 +24,7 @@ "limit": 19 }, "reportExplicitAny": { - "limit": 5486 + "limit": 5063 }, "reportFunctionMemberAccess": { "limit": 7 @@ -42,7 +42,7 @@ "limit": 12 }, "reportIndexIssue": { - "limit": 35 + "limit": 30 }, "reportInvalidTypeForm": { "limit": 34 @@ -54,10 +54,10 @@ "limit": 0 }, "reportMissingParameterType": { - "limit": 5658 + "limit": 5642 }, "reportMissingTypeArgument": { - "limit": 15425 + "limit": 15404 }, "reportMissingTypeStubs": { "limit": 40 @@ -105,19 +105,19 @@ "limit": 109 }, "reportUnknownMemberType": { - "limit": 38721 + "limit": 38622 }, "reportUnknownParameterType": { - "limit": 19778 + "limit": 19748 }, "reportUnknownVariableType": { - "limit": 30290 + "limit": 30210 }, "reportUnnecessaryCast": { "limit": 117 }, "reportUnnecessaryComparison": { - "limit": 697 + "limit": 696 }, "reportUnnecessaryContains": { "limit": 5 diff --git a/litellm/caching/valkey_semantic_cache.py b/litellm/caching/valkey_semantic_cache.py index b63b2e0dc10..ec91651ed33 100644 --- a/litellm/caching/valkey_semantic_cache.py +++ b/litellm/caching/valkey_semantic_cache.py @@ -19,7 +19,7 @@ import hashlib import os from collections.abc import Mapping, Sequence from dataclasses import dataclass -from typing import Any, Final, Protocol +from typing import Any, Final, Protocol, cast from redis import Redis from redis.asyncio import Redis as AsyncRedis @@ -294,7 +294,8 @@ class ValkeySemanticCache(RedisSemanticCache): print_verbose("No prompt provided for semantic caching") return - embedding: Final = await self._get_async_embedding(prompt, metadata=kwargs.get("metadata")) + metadata: Final = cast("dict[str, object] | None", kwargs.get("metadata")) # cast-ok: untyped kwargs + embedding: Final = await self._get_async_embedding(prompt, metadata=metadata) await self._ensure_index_async(len(embedding)) doc_key: Final = self._doc_key(key) diff --git a/litellm/integrations/arize/arize_phoenix_prompt_manager.py b/litellm/integrations/arize/arize_phoenix_prompt_manager.py index 0c616e845f8..0c9e868c146 100644 --- a/litellm/integrations/arize/arize_phoenix_prompt_manager.py +++ b/litellm/integrations/arize/arize_phoenix_prompt_manager.py @@ -4,7 +4,7 @@ Fetches prompt versions from Arize Phoenix and provides workspace-based access c """ from collections.abc import Mapping, Sequence -from typing import Any, Final +from typing import Any, Final, cast from jinja2 import DictLoader, select_autoescape from jinja2.sandbox import ImmutableSandboxedEnvironment @@ -203,7 +203,9 @@ class ArizePhoenixTemplateManager: # Combine rendered content final_content = " ".join(rendered_content_parts) - rendered_messages.append({"role": role, "content": final_content}) + rendered_messages.append( + cast("AllMessageValues", {"role": role, "content": final_content}) # cast-ok: Phoenix roles are OpenAI + ) return rendered_messages diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py index 4551ff5213f..a45bfb93640 100644 --- a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py @@ -36,6 +36,7 @@ from litellm.types.llms.anthropic import ( CompactionBlock, UsageIteration, ) +from litellm.types.llms.openai import AllMessageValues if TYPE_CHECKING: from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper @@ -867,7 +868,7 @@ def _append_text_to_content(content: object, extra_text: str) -> object: class _SummaryCallUserKwarg(TypedDict, total=False): - user: ReadOnly[object] + user: ReadOnly[str] class _SummaryCallRegionKwarg(TypedDict, total=False): @@ -876,11 +877,11 @@ class _SummaryCallRegionKwarg(TypedDict, total=False): class _SummaryCallKwargs(TypedDict): model: ReadOnly[str] - messages: ReadOnly[list[dict[str, object]]] + messages: ReadOnly[list[AllMessageValues]] max_tokens: ReadOnly[int] timeout: ReadOnly[float] litellm_metadata: ReadOnly[Mapping[str, object]] - user: NotRequired[ReadOnly[object]] + user: NotRequired[ReadOnly[str]] allowed_model_region: NotRequired[ReadOnly[str]] @@ -927,11 +928,15 @@ async def _call_summary_model( end_user_id: Final = metadata.get("user_api_key_end_user_id") call_kwargs: Final[_SummaryCallKwargs] = { "model": summary_model, - "messages": summary_messages, + "messages": cast("list[AllMessageValues]", summary_messages), # cast-ok: built as OpenAI chat messages "max_tokens": max_tokens, "timeout": COMPACT_SUMMARY_TIMEOUT_SECONDS, "litellm_metadata": metadata, - **(_SummaryCallUserKwarg(user=end_user_id) if end_user_id else _SummaryCallUserKwarg()), + **( + _SummaryCallUserKwarg(user=end_user_id) + if isinstance(end_user_id, str) and end_user_id + else _SummaryCallUserKwarg() + ), **( _SummaryCallRegionKwarg(allowed_model_region=allowed_model_region) if allowed_model_region is not None diff --git a/litellm/llms/vertex_ai/common_utils.py b/litellm/llms/vertex_ai/common_utils.py index 48649cf3105..1de316835a1 100644 --- a/litellm/llms/vertex_ai/common_utils.py +++ b/litellm/llms/vertex_ai/common_utils.py @@ -1,7 +1,7 @@ import re from copy import deepcopy from enum import Enum -from typing import Any, Final, Literal, get_type_hints +from typing import Any, Final, Literal, cast, get_type_hints import httpx @@ -726,8 +726,9 @@ def set_schema_property_ordering(schema: dict[str, object], depth: int = 0) -> d schema["propertyOrdering"] = [k for k, v in schema["properties"].items()] for k, v in schema["properties"].items(): set_schema_property_ordering(v, depth + 1) - if "items" in schema: - set_schema_property_ordering(schema["items"], depth + 1) + items: Final = schema.get("items") + if isinstance(items, dict): + set_schema_property_ordering(cast("dict[str, object]", items), depth + 1) # cast-ok: JSON Schema child return schema diff --git a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py index 29fcafa40fa..4a3c8b0628d 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py +++ b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py @@ -364,9 +364,7 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM): bedrock_request["content"] = bedrock_request_content return bedrock_request - def _build_response_content_items( - self, response: object, has_grounding: bool - ) -> list[BedrockContentItem]: + def _build_response_content_items(self, response: object, has_grounding: bool) -> list[BedrockContentItem]: """Build content item(s) from the model response. When the request supplied grounding, the response is qualified ``guard_content`` so Bedrock can score it. """ diff --git a/litellm/proxy/litellm_pre_call_utils.py b/litellm/proxy/litellm_pre_call_utils.py index efa7cb04315..b49541f63ed 100644 --- a/litellm/proxy/litellm_pre_call_utils.py +++ b/litellm/proxy/litellm_pre_call_utils.py @@ -7,7 +7,7 @@ from collections import OrderedDict from collections.abc import Mapping, MutableMapping, Sequence from datetime import datetime from types import MappingProxyType -from typing import TYPE_CHECKING, Any, Final +from typing import TYPE_CHECKING, Any, Final, cast from fastapi import HTTPException, Request from pydantic import ValidationError as PydanticValidationError @@ -1343,6 +1343,8 @@ class LiteLLMProxyRequestSetup: def get_sanitized_user_information_from_key( user_api_key_dict: UserAPIKeyAuth, ) -> StandardLoggingUserAPIKeyMetadata: + stripped_metadata: Final = strip_callback_config(user_api_key_dict.metadata) + auth_metadata: Final = cast("dict[str, str] | None", stripped_metadata) # cast-ok: metadata is free-form JSON user_api_key_logged_metadata: Final = StandardLoggingUserAPIKeyMetadata( user_api_key_hash=user_api_key_dict.api_key, # just the hashed token user_api_key_alias=user_api_key_dict.key_alias, @@ -1365,7 +1367,7 @@ class LiteLLMProxyRequestSetup: user_api_key_budget_reset_at=( user_api_key_dict.budget_reset_at.isoformat() if user_api_key_dict.budget_reset_at else None ), - user_api_key_auth_metadata=strip_callback_config(user_api_key_dict.metadata), + user_api_key_auth_metadata=auth_metadata, ) return user_api_key_logged_metadata diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index e1157b75107..f0f684b0fa1 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -2476,6 +2476,9 @@ async def _validate_update_key_data( user_api_key_cache: UserApiKeyCache, ) -> None: """Validate permissions and constraints for key update.""" + if prisma_client is None: + raise HTTPException(status_code=500, detail={"error": "Database not connected"}) + # Reject NaN/±inf spend before it can reach the DB / spend counter. validate_finite_spend(data.spend) validate_budget_duration(data.budget_duration) @@ -2594,7 +2597,7 @@ async def _validate_update_key_data( # _check_key_admin_access that would otherwise require team/org admin status. _key_is_team_key: Final = getattr(existing_key_row, "team_id", None) is not None can_skip_admin_check: Final = (caller_is_creator or _key_is_team_key) and not _is_budget_change - if (not _is_proxy_admin) and prisma_client is not None and not can_skip_admin_check: + if (not _is_proxy_admin) and not can_skip_admin_check: hashed_key: Final = existing_key_row.token await _check_key_admin_access( user_api_key_dict=user_api_key_dict, diff --git a/ruff-strict-budget.json b/ruff-strict-budget.json index c60988eccc0..33877524fb5 100644 --- a/ruff-strict-budget.json +++ b/ruff-strict-budget.json @@ -1,21 +1,21 @@ { "ANN001": { - "limit": 3012 + "limit": 3004 }, "ANN002": { "limit": 71 }, "ANN003": { - "limit": 827 + "limit": 825 }, "ANN201": { "limit": 2003 }, "ANN202": { - "limit": 845 + "limit": 843 }, "ANN204": { - "limit": 702 + "limit": 700 }, "ANN205": { "limit": 112 @@ -24,7 +24,7 @@ "limit": 133 }, "ANN401": { - "limit": 655 + "limit": 517 }, "ASYNC230": { "limit": 11 @@ -168,7 +168,7 @@ "limit": 3 }, "RET504": { - "limit": 175 + "limit": 174 }, "RUF012": { "limit": 239 @@ -198,7 +198,7 @@ "limit": 58 }, "SIM102": { - "limit": 315 + "limit": 313 }, "SIM103": { "limit": 119 @@ -231,7 +231,7 @@ "limit": 5 }, "TID251": { - "limit": 1117 + "limit": 1105 }, "TRY002": { "limit": 524 diff --git a/type-discipline-budget.json b/type-discipline-budget.json index f3f1a7defe7..be3c9589015 100644 --- a/type-discipline-budget.json +++ b/type-discipline-budget.json @@ -1,9 +1,9 @@ { "LIT001": { - "limit": 22705 + "limit": 22655 }, "LIT002": { - "limit": 26854 + "limit": 26830 }, "LIT003": { "limit": 269 @@ -27,10 +27,10 @@ "limit": 0 }, "LIT010": { - "limit": 16564 + "limit": 16546 }, "LIT011": { - "limit": 5577 + "limit": 5558 }, "LIT012": { "limit": 4508