diff --git a/litellm/__init__.py b/litellm/__init__.py index d141a3fb28..6135e27577 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -2,6 +2,9 @@ import warnings warnings.filterwarnings("ignore", message=".*conflict with protected namespace.*") +# Suppress Pydantic 2.11+ deprecation warning about accessing model_fields on instances +# This warning can accumulate during streaming and cause memory leaks +warnings.filterwarnings("ignore", message=".*Accessing the.*attribute on the instance is deprecated.*") ### INIT VARIABLES ###################### import threading import os diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index 9935eed292..42fcabcf68 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -1595,7 +1595,8 @@ class BaseTokenUsageProcessor: combined.prompt_tokens_details = PromptTokensDetailsWrapper() # Check what keys exist in the model's prompt_tokens_details - for attr in usage.prompt_tokens_details.model_fields: + # Access model_fields on the class, not the instance, to avoid Pydantic 2.11+ deprecation warnings + for attr in type(usage.prompt_tokens_details).model_fields: if ( hasattr(usage.prompt_tokens_details, attr) and not attr.startswith("_") @@ -1626,7 +1627,8 @@ class BaseTokenUsageProcessor: ) # Check what keys exist in the model's completion_tokens_details - for attr in usage.completion_tokens_details.model_fields: + # Access model_fields on the class, not the instance, to avoid Pydantic 2.11+ deprecation warnings + for attr in type(usage.completion_tokens_details).model_fields: if not attr.startswith("_") and not callable( getattr(usage.completion_tokens_details, attr) ): diff --git a/litellm/litellm_core_utils/core_helpers.py b/litellm/litellm_core_utils/core_helpers.py index 8b9f53cec1..47034c3a5c 100644 --- a/litellm/litellm_core_utils/core_helpers.py +++ b/litellm/litellm_core_utils/core_helpers.py @@ -234,7 +234,8 @@ def preserve_upstream_non_openai_attributes( """ Preserve non-OpenAI attributes from the original chunk. """ - expected_keys = set(model_response.model_fields.keys()).union({"usage"}) + # Access model_fields on the class, not the instance, to avoid Pydantic 2.11+ deprecation warnings + expected_keys = set(type(model_response).model_fields.keys()).union({"usage"}) for key, value in original_chunk.model_dump().items(): if key not in expected_keys: setattr(model_response, key, value) diff --git a/litellm/litellm_core_utils/model_response_utils.py b/litellm/litellm_core_utils/model_response_utils.py index 974d12aef6..00462221fe 100644 --- a/litellm/litellm_core_utils/model_response_utils.py +++ b/litellm/litellm_core_utils/model_response_utils.py @@ -46,7 +46,8 @@ def is_model_response_stream_empty(model_response: ModelResponseStream) -> bool: return False # Check for any non-base fields that are set - for model_response_field in model_response.model_fields.keys(): + # Access model_fields on the class, not the instance, to avoid Pydantic 2.11+ deprecation warnings + for model_response_field in type(model_response).model_fields.keys(): # Skip base fields that are always set if model_response_field in BASE_FIELDS: continue