From 12284308a34eb889e96833682d3c05b655bf79c1 Mon Sep 17 00:00:00 2001 From: Cesar Garcia <128240629+Chesars@users.noreply.github.com> Date: Wed, 5 Nov 2025 23:36:06 -0300 Subject: [PATCH] fix: Resolve MyPy type checking errors and CI linting (#16277) * fix: Remove unused asyncio import from litellm_logging.py - Fixes F401 linting error blocking CI * fix: Add type ignore comments for MyPy false positives - redis_cache.py: Add type ignore for aclose() - method exists but redis-py type stubs are incomplete - redis_cluster_cache.py: Add type ignore for ping() and aclose() - redis-py typing issue - responses/utils.py: Add type ignore for variable shadowing false positive - transformation.py: Add type ignore for TypedDict expansion - runtime works correctly - aws_secret_manager_v2.py: Add type ignore for dict[str, Any] assignment All changes are safe - code works correctly in runtime, these are MyPy inference limitations. Fixes 7 MyPy errors blocking CI without changing any logic. * fix: Add type ignore for Redis async methods in cache files - Add type: ignore[attr-defined] for aclose() in redis_cache.py - Add type: ignore[attr-defined] for ping() and aclose() in redis_cluster_cache.py - Methods exist but redis-py type stubs are incomplete * refactor: Remove variable shadowing in _transform_response_api_usage_to_chat_usage - Rename parameter 'usage' to 'usage_input' for clarity - Rename local variable 'usage' to 'chat_usage' to avoid shadowing - Eliminates MyPy false positive without needing type: ignore - No functional changes - all tests pass - Improves code readability and type safety --- litellm/caching/redis_cache.py | 4 ++-- litellm/caching/redis_cluster_cache.py | 6 +++--- .../transformation.py | 2 +- litellm/responses/utils.py | 14 ++++++++------ litellm/secret_managers/aws_secret_manager_v2.py | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/litellm/caching/redis_cache.py b/litellm/caching/redis_cache.py index b2e52b20eac..55ae47fe461 100644 --- a/litellm/caching/redis_cache.py +++ b/litellm/caching/redis_cache.py @@ -1071,9 +1071,9 @@ class RedisCache(BaseCache): # Test the connection ping_result = await redis_client.ping() - + # Close the connection - await redis_client.aclose() + await redis_client.aclose() # type: ignore[attr-defined] if ping_result: return { diff --git a/litellm/caching/redis_cluster_cache.py b/litellm/caching/redis_cluster_cache.py index 69bdb500de4..91fcf1d7288 100644 --- a/litellm/caching/redis_cluster_cache.py +++ b/litellm/caching/redis_cluster_cache.py @@ -83,10 +83,10 @@ class RedisClusterCache(RedisCache): ) # Test the connection - ping_result = await redis_client.ping() - + ping_result = await redis_client.ping() # type: ignore[attr-defined] + # Close the connection - await redis_client.aclose() + await redis_client.aclose() # type: ignore[attr-defined] if ping_result: return { diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index cb358498968..3ba75666b81 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -541,7 +541,7 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge): def _map_reasoning_effort(self, reasoning_effort: Union[str, Dict[str, Any]]) -> Optional[Reasoning]: # If dict is passed, convert it directly to Reasoning object if isinstance(reasoning_effort, dict): - return Reasoning(**reasoning_effort) + return Reasoning(**reasoning_effort) # type: ignore[typeddict-item] # If string is passed, map without summary (default) if reasoning_effort == "high": diff --git a/litellm/responses/utils.py b/litellm/responses/utils.py index 64db4d3e020..63c15e21a88 100644 --- a/litellm/responses/utils.py +++ b/litellm/responses/utils.py @@ -361,17 +361,19 @@ class ResponseAPILoggingUtils: @staticmethod def _transform_response_api_usage_to_chat_usage( - usage: Optional[Union[dict, ResponseAPIUsage]], + usage_input: Optional[Union[dict, ResponseAPIUsage]], ) -> Usage: """Tranforms the ResponseAPIUsage object to a Usage object""" - if usage is None: + if usage_input is None: return Usage( prompt_tokens=0, completion_tokens=0, total_tokens=0, ) response_api_usage: ResponseAPIUsage = ( - ResponseAPIUsage(**usage) if isinstance(usage, dict) else usage + ResponseAPIUsage(**usage_input) + if isinstance(usage_input, dict) + else usage_input ) prompt_tokens: int = response_api_usage.input_tokens or 0 completion_tokens: int = response_api_usage.output_tokens or 0 @@ -381,7 +383,7 @@ class ResponseAPILoggingUtils: cached_tokens=response_api_usage.input_tokens_details.cached_tokens, audio_tokens=response_api_usage.input_tokens_details.audio_tokens, ) - usage = Usage( + chat_usage = Usage( prompt_tokens=prompt_tokens, completion_tokens=completion_tokens, total_tokens=prompt_tokens + completion_tokens, @@ -390,6 +392,6 @@ class ResponseAPILoggingUtils: # Preserve cost attribute if it exists on ResponseAPIUsage if hasattr(response_api_usage, "cost") and response_api_usage.cost is not None: - setattr(usage, "cost", response_api_usage.cost) + setattr(chat_usage, "cost", response_api_usage.cost) - return usage + return chat_usage diff --git a/litellm/secret_managers/aws_secret_manager_v2.py b/litellm/secret_managers/aws_secret_manager_v2.py index 0e7a61d0370..8f3547fd082 100644 --- a/litellm/secret_managers/aws_secret_manager_v2.py +++ b/litellm/secret_managers/aws_secret_manager_v2.py @@ -238,7 +238,7 @@ class AWSSecretsManagerV2(BaseAWSLLM, BaseSecretManager): tags_list = tags else: raise ValueError("Tags must be a dict or list of {Key, Value} pairs") - data["Tags"] = tags_list + data["Tags"] = tags_list # type: ignore[assignment] endpoint_url, headers, body = self._prepare_request( action="CreateSecret",