From 876840e9957bc7e9f7d6a2b58c4d7c53dad16481 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 12 May 2024 10:09:38 -0700 Subject: [PATCH 1/9] Update pydantic code to fix warnings Before: ```shell $ env -i PATH=$PATH poetry run pytest litellm/tests/test_proxy_server.py ====================================== test session starts ====================================== platform darwin -- Python 3.12.3, pytest-7.4.4, pluggy-1.5.0 rootdir: /Users/abramowi/Code/OpenSource/litellm plugins: anyio-4.3.0, asyncio-0.23.6, mock-3.14.0 asyncio: mode=Mode.STRICT collected 12 items litellm/tests/test_proxy_server.py s..........s [100%] ======================================= warnings summary ======================================== ../../../Library/Caches/pypoetry/virtualenvs/litellm-Fe7WjZrx-py3.12/lib/python3.12/site-packages/pydantic/_internal/_config.py:284: 25 warnings /Users/abramowi/Library/Caches/pypoetry/virtualenvs/litellm-Fe7WjZrx-py3.12/lib/python3.12/site-packages/pydantic/_internal/_config.py:284: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning) litellm/proxy/_types.py:225 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:225: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:312 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:312: PydanticDeprecatedSince20: `pydantic.config.Extra` is deprecated, use literal values instead (e.g. `extra='allow'`). Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ extra = Extra.allow # Allow extra fields litellm/proxy/_types.py:315 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:315: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:344 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:344: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:391 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:391: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:460 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:460: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:480 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:480: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:493 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:493: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:538 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:538: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:575 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:575: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:870 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:870: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:897 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:897: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/proxy/_types.py:918 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:918: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) litellm/utils.py:43 /Users/abramowi/Code/OpenSource/litellm/litellm/utils.py:43: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html import pkg_resources # type: ignore litellm/tests/test_proxy_server.py::test_bedrock_embedding litellm/tests/test_proxy_server.py::test_chat_completion litellm/tests/test_proxy_server.py::test_chat_completion_azure litellm/tests/test_proxy_server.py::test_chat_completion_optional_params litellm/tests/test_proxy_server.py::test_embedding litellm/tests/test_proxy_server.py::test_engines_model_chat_completions litellm/tests/test_proxy_server.py::test_health litellm/tests/test_proxy_server.py::test_img_gen litellm/tests/test_proxy_server.py::test_openai_deployments_model_chat_completions_azure /Users/abramowi/Library/Caches/pypoetry/virtualenvs/litellm-Fe7WjZrx-py3.12/lib/python3.12/site-packages/httpx/_client.py:680: DeprecationWarning: The 'app' shortcut is now deprecated. Use the explicit style 'transport=WSGITransport(app=...)' instead. warnings.warn(message, DeprecationWarning) -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ========================== 10 passed, 2 skipped, 48 warnings in 9.83s =========================== ``` After: ```shell $ env -i PATH=$PATH poetry run pytest litellm/tests/test_proxy_server.py ====================================== test session starts ====================================== platform darwin -- Python 3.12.3, pytest-7.4.4, pluggy-1.5.0 rootdir: /Users/abramowi/Code/OpenSource/litellm plugins: anyio-4.3.0, asyncio-0.23.6, mock-3.14.0 asyncio: mode=Mode.STRICT collected 12 items litellm/tests/test_proxy_server.py s..........s [100%] ======================================= warnings summary ======================================== litellm/utils.py:43 /Users/abramowi/Code/OpenSource/litellm/litellm/utils.py:43: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html import pkg_resources # type: ignore litellm/tests/test_proxy_server.py::test_bedrock_embedding litellm/tests/test_proxy_server.py::test_chat_completion litellm/tests/test_proxy_server.py::test_chat_completion_azure litellm/tests/test_proxy_server.py::test_chat_completion_optional_params litellm/tests/test_proxy_server.py::test_embedding litellm/tests/test_proxy_server.py::test_engines_model_chat_completions litellm/tests/test_proxy_server.py::test_health litellm/tests/test_proxy_server.py::test_img_gen litellm/tests/test_proxy_server.py::test_openai_deployments_model_chat_completions_azure /Users/abramowi/Library/Caches/pypoetry/virtualenvs/litellm-Fe7WjZrx-py3.12/lib/python3.12/site-packages/httpx/_client.py:680: DeprecationWarning: The 'app' shortcut is now deprecated. Use the explicit style 'transport=WSGITransport(app=...)' instead. warnings.warn(message, DeprecationWarning) -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ========================== 10 passed, 2 skipped, 10 warnings in 9.62s =========================== ``` --- litellm/integrations/slack_alerting.py | 2 +- litellm/proxy/_types.py | 102 ++++++++++++++----------- litellm/tests/test_config.py | 5 +- litellm/tests/test_streaming.py | 14 ++-- litellm/types/completion.py | 7 +- litellm/types/embedding.py | 7 +- litellm/types/router.py | 39 +++------- litellm/utils.py | 7 +- 8 files changed, 84 insertions(+), 99 deletions(-) diff --git a/litellm/integrations/slack_alerting.py b/litellm/integrations/slack_alerting.py index 07c3585f0..397d740de 100644 --- a/litellm/integrations/slack_alerting.py +++ b/litellm/integrations/slack_alerting.py @@ -50,7 +50,7 @@ class DeploymentMetrics(LiteLLMBase): failed_request: bool """did it fail the request?""" - latency_per_output_token: Optional[float] + latency_per_output_token: Optional[float] = None """latency/output token of deployment""" updated_at: dt diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index d513ba5de..6f86adc67 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1,9 +1,9 @@ -from pydantic import BaseModel, Extra, Field, root_validator, Json, validator -from dataclasses import fields +from pydantic import BaseModel, Field, model_validator, Json import enum from typing import Optional, List, Union, Dict, Literal, Any from datetime import datetime -import uuid, json, sys, os +import uuid +import json from litellm.types.router import UpdateRouterConfig @@ -35,8 +35,9 @@ class LiteLLMBase(BaseModel): # if using pydantic v1 return self.__fields_set__ - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class LiteLLM_UpperboundKeyGenerateParams(LiteLLMBase): @@ -216,7 +217,7 @@ class LiteLLMPromptInjectionParams(LiteLLMBase): llm_api_system_prompt: Optional[str] = None llm_api_fail_call_string: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_llm_api_params(cls, values): llm_api_check = values.get("llm_api_check") if llm_api_check is True: @@ -274,8 +275,9 @@ class ProxyChatCompletionRequest(LiteLLMBase): deployment_id: Optional[str] = None request_timeout: Optional[int] = None - class Config: - extra = "allow" # allow params not defined here, these fall in litellm.completion(**kwargs) + model_config = dict( + extra = "allow", # allow params not defined here, these fall in litellm.completion(**kwargs) + ) class ModelInfoDelete(LiteLLMBase): @@ -302,11 +304,12 @@ class ModelInfo(LiteLLMBase): ] ] - class Config: - extra = Extra.allow # Allow extra fields - protected_namespaces = () + model_config = dict( + extra = "allow", # Allow extra fields + protected_namespaces = (), + ) - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("id") is None: values.update({"id": str(uuid.uuid4())}) @@ -332,10 +335,11 @@ class ModelParams(LiteLLMBase): litellm_params: dict model_info: ModelInfo - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("model_info") is None: values.update({"model_info": ModelInfo()}) @@ -371,8 +375,9 @@ class GenerateKeyRequest(GenerateRequestBase): {} ) # {"gpt-4": 5.0, "gpt-3.5-turbo": 5.0}, defaults to {} - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class GenerateKeyResponse(GenerateKeyRequest): @@ -382,7 +387,7 @@ class GenerateKeyResponse(GenerateKeyRequest): user_id: Optional[str] = None token_id: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("token") is not None: values.update({"key": values.get("token")}) @@ -422,8 +427,9 @@ class LiteLLM_ModelTable(LiteLLMBase): created_by: str updated_by: str - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class NewUserRequest(GenerateKeyRequest): @@ -451,7 +457,7 @@ class UpdateUserRequest(GenerateRequestBase): user_role: Optional[str] = None max_budget: Optional[float] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -471,7 +477,7 @@ class NewEndUserRequest(LiteLLMBase): None # if no equivalent model in allowed region - default all requests to this model ) - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("max_budget") is not None and values.get("budget_id") is not None: raise ValueError("Set either 'max_budget' or 'budget_id', not both.") @@ -484,7 +490,7 @@ class Member(LiteLLMBase): user_id: Optional[str] = None user_email: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -509,8 +515,9 @@ class TeamBase(LiteLLMBase): class NewTeamRequest(TeamBase): model_aliases: Optional[dict] = None - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class GlobalEndUsersSpend(LiteLLMBase): @@ -529,7 +536,7 @@ class TeamMemberDeleteRequest(LiteLLMBase): user_id: Optional[str] = None user_email: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -563,10 +570,11 @@ class LiteLLM_TeamTable(TeamBase): budget_reset_at: Optional[datetime] = None model_id: Optional[int] = None - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): dict_fields = [ "metadata", @@ -602,8 +610,9 @@ class LiteLLM_BudgetTable(LiteLLMBase): model_max_budget: Optional[dict] = None budget_duration: Optional[str] = None - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class NewOrganizationRequest(LiteLLM_BudgetTable): @@ -653,8 +662,9 @@ class KeyManagementSettings(LiteLLMBase): class TeamDefaultSettings(LiteLLMBase): team_id: str - class Config: - extra = "allow" # allow params not defined here, these fall in litellm.completion(**kwargs) + model_config = dict( + extra = "allow", # allow params not defined here, these fall in litellm.completion(**kwargs) + ) class DynamoDBArgs(LiteLLMBase): @@ -795,8 +805,9 @@ class ConfigYAML(LiteLLMBase): description="litellm router object settings. See router.py __init__ for all, example router.num_retries=5, router.timeout=5, router.max_retries=5, router.retry_after=5", ) - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class LiteLLM_VerificationToken(LiteLLMBase): @@ -830,8 +841,9 @@ class LiteLLM_VerificationToken(LiteLLMBase): user_id_rate_limits: Optional[dict] = None team_id_rate_limits: Optional[dict] = None - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class LiteLLM_VerificationTokenView(LiteLLM_VerificationToken): @@ -861,7 +873,7 @@ class UserAPIKeyAuth( user_role: Optional[Literal["proxy_admin", "app_owner", "app_user"]] = None allowed_model_region: Optional[Literal["eu"]] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_api_key(cls, values): if values.get("api_key") is not None: values.update({"token": hash_token(values.get("api_key"))}) @@ -888,7 +900,7 @@ class LiteLLM_UserTable(LiteLLMBase): tpm_limit: Optional[int] = None rpm_limit: Optional[int] = None - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("spend") is None: values.update({"spend": 0.0}) @@ -896,8 +908,9 @@ class LiteLLM_UserTable(LiteLLMBase): values.update({"models": []}) return values - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class LiteLLM_EndUserTable(LiteLLMBase): @@ -909,14 +922,15 @@ class LiteLLM_EndUserTable(LiteLLMBase): default_model: Optional[str] = None litellm_budget_table: Optional[LiteLLM_BudgetTable] = None - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("spend") is None: values.update({"spend": 0.0}) return values - class Config: - protected_namespaces = () + model_config = dict( + protected_namespaces = (), + ) class LiteLLM_SpendLogs(LiteLLMBase): diff --git a/litellm/tests/test_config.py b/litellm/tests/test_config.py index e38187e0e..d0cd93d1f 100644 --- a/litellm/tests/test_config.py +++ b/litellm/tests/test_config.py @@ -5,6 +5,7 @@ import sys, os import traceback from dotenv import load_dotenv +from pydantic import ConfigDict load_dotenv() import os, io @@ -25,9 +26,7 @@ class DBModel(BaseModel): model_name: str model_info: dict litellm_params: dict - - class Config: - protected_namespaces = () + model_config = ConfigDict(protected_namespaces=()) @pytest.mark.asyncio diff --git a/litellm/tests/test_streaming.py b/litellm/tests/test_streaming.py index 13cadf227..1ece4a95b 100644 --- a/litellm/tests/test_streaming.py +++ b/litellm/tests/test_streaming.py @@ -2156,15 +2156,15 @@ class ToolCalls(BaseModel): class Delta(BaseModel): role: str - content: Optional[str] + content: Optional[str] = None tool_calls: List[ToolCalls] class Choices(BaseModel): index: int delta: Delta - logprobs: Optional[str] - finish_reason: Optional[str] + logprobs: Optional[str] = None + finish_reason: Optional[str] = None class Chunk(BaseModel): @@ -2218,7 +2218,7 @@ class Function2(BaseModel): class ToolCalls2(BaseModel): index: int - function: Optional[Function2] + function: Optional[Function2] = None class Delta2(BaseModel): @@ -2228,8 +2228,8 @@ class Delta2(BaseModel): class Choices2(BaseModel): index: int delta: Delta2 - logprobs: Optional[str] - finish_reason: Optional[str] + logprobs: Optional[str] = None + finish_reason: Optional[str] = None class Chunk2(BaseModel): @@ -2283,7 +2283,7 @@ class Delta3(BaseModel): class Choices3(BaseModel): index: int delta: Delta3 - logprobs: Optional[str] + logprobs: Optional[str] = None finish_reason: str diff --git a/litellm/types/completion.py b/litellm/types/completion.py index 78af7667b..aede0bc9e 100644 --- a/litellm/types/completion.py +++ b/litellm/types/completion.py @@ -1,6 +1,6 @@ from typing import List, Optional, Union, Iterable -from pydantic import BaseModel, validator +from pydantic import ConfigDict, BaseModel, validator from typing_extensions import Literal, Required, TypedDict @@ -190,7 +190,4 @@ class CompletionRequest(BaseModel): api_version: Optional[str] = None api_key: Optional[str] = None model_list: Optional[List[str]] = None - - class Config: - extra = "allow" - protected_namespaces = () + model_config = ConfigDict(extra="allow", protected_namespaces=()) diff --git a/litellm/types/embedding.py b/litellm/types/embedding.py index 9db0ef290..4690b1332 100644 --- a/litellm/types/embedding.py +++ b/litellm/types/embedding.py @@ -1,6 +1,6 @@ from typing import List, Optional, Union -from pydantic import BaseModel, validator +from pydantic import ConfigDict, BaseModel, validator class EmbeddingRequest(BaseModel): @@ -17,7 +17,4 @@ class EmbeddingRequest(BaseModel): litellm_call_id: Optional[str] = None litellm_logging_obj: Optional[dict] = None logger_fn: Optional[str] = None - - class Config: - # allow kwargs - extra = "allow" + model_config = ConfigDict(extra="allow") diff --git a/litellm/types/router.py b/litellm/types/router.py index e8f3ff641..f9f6fd989 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -1,6 +1,6 @@ from typing import List, Optional, Union, Dict, Tuple, Literal import httpx -from pydantic import BaseModel, validator, Field +from pydantic import ConfigDict, BaseModel, validator, Field from .completion import CompletionRequest from .embedding import EmbeddingRequest import uuid, enum @@ -11,9 +11,7 @@ class ModelConfig(BaseModel): litellm_params: Union[CompletionRequest, EmbeddingRequest] tpm: int rpm: int - - class Config: - protected_namespaces = () + model_config = ConfigDict(protected_namespaces=()) class RouterConfig(BaseModel): @@ -43,9 +41,7 @@ class RouterConfig(BaseModel): "usage-based-routing", "latency-based-routing", ] = "simple-shuffle" - - class Config: - protected_namespaces = () + model_config = ConfigDict(protected_namespaces=()) class UpdateRouterConfig(BaseModel): @@ -64,15 +60,13 @@ class UpdateRouterConfig(BaseModel): retry_after: Optional[float] = None fallbacks: Optional[List[dict]] = None context_window_fallbacks: Optional[List[dict]] = None - - class Config: - protected_namespaces = () + model_config = ConfigDict(protected_namespaces=()) class ModelInfo(BaseModel): id: Optional[ str - ] # Allow id to be optional on input, but it will always be present as a str in the model instance + ] = None # Allow id to be optional on input, but it will always be present as a str in the model instance db_model: bool = ( False # used for proxy - to separate models which are stored in the db vs. config. ) @@ -83,9 +77,7 @@ class ModelInfo(BaseModel): elif isinstance(id, int): id = str(id) super().__init__(id=id, **params) - - class Config: - extra = "allow" + model_config = ConfigDict(extra="allow") def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -179,10 +171,7 @@ class GenericLiteLLMParams(BaseModel): if max_retries is not None and isinstance(max_retries, str): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - - class Config: - extra = "allow" - arbitrary_types_allowed = True + model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True) def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -240,10 +229,7 @@ class LiteLLM_Params(GenericLiteLLMParams): if max_retries is not None and isinstance(max_retries, str): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - - class Config: - extra = "allow" - arbitrary_types_allowed = True + model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True) def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -272,9 +258,7 @@ class updateDeployment(BaseModel): model_name: Optional[str] = None litellm_params: Optional[updateLiteLLMParams] = None model_info: Optional[ModelInfo] = None - - class Config: - protected_namespaces = () + model_config = ConfigDict(protected_namespaces=()) class Deployment(BaseModel): @@ -306,10 +290,7 @@ class Deployment(BaseModel): except Exception as e: # if using pydantic v1 return self.dict(**kwargs) - - class Config: - extra = "allow" - protected_namespaces = () + model_config = ConfigDict(extra="allow", protected_namespaces=()) def __contains__(self, key): # Define custom behavior for the 'in' operator diff --git a/litellm/utils.py b/litellm/utils.py index 7a1b70f00..dd49a417a 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -19,7 +19,7 @@ from functools import wraps import datetime, time import tiktoken import uuid -from pydantic import BaseModel +from pydantic import ConfigDict, BaseModel import aiohttp import textwrap import logging @@ -331,10 +331,7 @@ class HiddenParams(OpenAIObject): original_response: Optional[str] = None model_id: Optional[str] = None # used in Router for individual deployments api_base: Optional[str] = None # returns api base used for making completion call - - class Config: - extra = "allow" - protected_namespaces = () + model_config = ConfigDict(extra="allow", protected_namespaces=()) def get(self, key, default=None): # Custom .get() method to access attributes with a default value if the attribute doesn't exist From abe2514ba1a0f26babc3efee2da75af96be37eea Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 12 May 2024 10:15:10 -0700 Subject: [PATCH 2/9] Add my commit to .git-blame-ignore-revs because I made a lot of fairly mindless changes to pydantic code to fix warnings and I don't want git blame to give people the impression that I know more about this code than I do. --- .git-blame-ignore-revs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..f0ced6bed --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,10 @@ +# Add the commit hash of any commit you want to ignore in `git blame` here. +# One commit hash per line. +# +# The GitHub Blame UI will use this file automatically! +# +# Run this command to always ignore formatting commits in `git blame` +# git config blame.ignoreRevsFile .git-blame-ignore-revs + +# Update pydantic code to fix warnings (GH-3600) +876840e9957bc7e9f7d6a2b58c4d7c53dad16481 From ad8c3ac2c3ab1bdc2ba81e9f141fcce68d817c25 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 10:15:37 -0700 Subject: [PATCH 3/9] Change pydantic root_validator to model_validator pydantic v1 uses `root_validator` and pydantic v2 uses `model_validator`. pydantic v2 emits a warning when `root_validator` is used. E.g.: ``` litellm/proxy/_types.py:225 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:225: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) ``` This change eliminates those warnings with pydantic v2, while retaining compatibility with pydantic v1. pydantic 2.7.1 before ``` $ env -i PATH=$PATH poetry run pytest litellm/tests/test_proxy_server.py ... litellm/proxy/_types.py:225 /Users/abramowi/Code/OpenSource/litellm/litellm/proxy/_types.py:225: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.7/migration/ @root_validator(pre=True) ... ========================== 10 passed, 2 skipped, 39 warnings in 8.67s =========================== ``` pydantic 2.7.1 after ``` $ env -i PATH=$PATH poetry run pytest litellm/tests/test_proxy_server.py ... ========================== 10 passed, 2 skipped, 27 warnings in 9.85s =========================== ``` pydantic 1.10.5 after ``` $ poetry run pip install 'pydantic<2' ... Successfully installed pydantic-1.10.15 $ env -i PATH=$PATH poetry run pytest litellm/tests/test_proxy_server.py ... =========================== 10 passed, 2 skipped, 1 warning in 8.13s ============================ ``` --- litellm/proxy/_types.py | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index a2776f465..988e92f67 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -6,6 +6,15 @@ from datetime import datetime import uuid, json, sys, os from litellm.types.router import UpdateRouterConfig +try: + from pydantic import model_validator # pydantic v2 +except ImportError: + from pydantic import root_validator # pydantic v1 + + def model_validator(mode): + pre = mode == "before" + return root_validator(pre=pre) + def hash_token(token: str): import hashlib @@ -222,7 +231,7 @@ class LiteLLMPromptInjectionParams(LiteLLMBase): llm_api_system_prompt: Optional[str] = None llm_api_fail_call_string: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_llm_api_params(cls, values): llm_api_check = values.get("llm_api_check") if llm_api_check is True: @@ -312,7 +321,7 @@ class ModelInfo(LiteLLMBase): extra = Extra.allow # Allow extra fields protected_namespaces = () - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("id") is None: values.update({"id": str(uuid.uuid4())}) @@ -341,7 +350,7 @@ class ModelParams(LiteLLMBase): class Config: protected_namespaces = () - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("model_info") is None: values.update({"model_info": ModelInfo()}) @@ -388,7 +397,7 @@ class GenerateKeyResponse(GenerateKeyRequest): user_id: Optional[str] = None token_id: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("token") is not None: values.update({"key": values.get("token")}) @@ -457,7 +466,7 @@ class UpdateUserRequest(GenerateRequestBase): user_role: Optional[str] = None max_budget: Optional[float] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -477,7 +486,7 @@ class NewEndUserRequest(LiteLLMBase): None # if no equivalent model in allowed region - default all requests to this model ) - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("max_budget") is not None and values.get("budget_id") is not None: raise ValueError("Set either 'max_budget' or 'budget_id', not both.") @@ -490,7 +499,7 @@ class Member(LiteLLMBase): user_id: Optional[str] = None user_email: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -535,7 +544,7 @@ class TeamMemberDeleteRequest(LiteLLMBase): user_id: Optional[str] = None user_email: Optional[str] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -572,7 +581,7 @@ class LiteLLM_TeamTable(TeamBase): class Config: protected_namespaces = () - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): dict_fields = [ "metadata", @@ -867,7 +876,7 @@ class UserAPIKeyAuth( user_role: Optional[Literal["proxy_admin", "app_owner", "app_user"]] = None allowed_model_region: Optional[Literal["eu"]] = None - @root_validator(pre=True) + @model_validator(mode="before") def check_api_key(cls, values): if values.get("api_key") is not None: values.update({"token": hash_token(values.get("api_key"))}) @@ -894,7 +903,7 @@ class LiteLLM_UserTable(LiteLLMBase): tpm_limit: Optional[int] = None rpm_limit: Optional[int] = None - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("spend") is None: values.update({"spend": 0.0}) @@ -915,7 +924,7 @@ class LiteLLM_EndUserTable(LiteLLMBase): default_model: Optional[str] = None litellm_budget_table: Optional[LiteLLM_BudgetTable] = None - @root_validator(pre=True) + @model_validator(mode="before") def set_model_info(cls, values): if values.get("spend") is None: values.update({"spend": 0.0}) From abd90e629678831eac4c262267d7588fc46ef9ec Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 10:33:04 -0700 Subject: [PATCH 4/9] Revert root_validator => model_validator change I have it in a separate PR: https://github.com/BerriAI/litellm/pull/3611 --- litellm/proxy/_types.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 6f86adc67..24e789544 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field, model_validator, Json +from pydantic import BaseModel, Field, root_validator, Json import enum from typing import Optional, List, Union, Dict, Literal, Any from datetime import datetime @@ -217,7 +217,7 @@ class LiteLLMPromptInjectionParams(LiteLLMBase): llm_api_system_prompt: Optional[str] = None llm_api_fail_call_string: Optional[str] = None - @model_validator(mode="before") + @root_validator(pre=True) def check_llm_api_params(cls, values): llm_api_check = values.get("llm_api_check") if llm_api_check is True: @@ -309,7 +309,7 @@ class ModelInfo(LiteLLMBase): protected_namespaces = (), ) - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): if values.get("id") is None: values.update({"id": str(uuid.uuid4())}) @@ -339,7 +339,7 @@ class ModelParams(LiteLLMBase): protected_namespaces = (), ) - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): if values.get("model_info") is None: values.update({"model_info": ModelInfo()}) @@ -387,7 +387,7 @@ class GenerateKeyResponse(GenerateKeyRequest): user_id: Optional[str] = None token_id: Optional[str] = None - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): if values.get("token") is not None: values.update({"key": values.get("token")}) @@ -457,7 +457,7 @@ class UpdateUserRequest(GenerateRequestBase): user_role: Optional[str] = None max_budget: Optional[float] = None - @model_validator(mode="before") + @root_validator(pre=True) def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -477,7 +477,7 @@ class NewEndUserRequest(LiteLLMBase): None # if no equivalent model in allowed region - default all requests to this model ) - @model_validator(mode="before") + @root_validator(pre=True) def check_user_info(cls, values): if values.get("max_budget") is not None and values.get("budget_id") is not None: raise ValueError("Set either 'max_budget' or 'budget_id', not both.") @@ -490,7 +490,7 @@ class Member(LiteLLMBase): user_id: Optional[str] = None user_email: Optional[str] = None - @model_validator(mode="before") + @root_validator(pre=True) def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -536,7 +536,7 @@ class TeamMemberDeleteRequest(LiteLLMBase): user_id: Optional[str] = None user_email: Optional[str] = None - @model_validator(mode="before") + @root_validator(pre=True) def check_user_info(cls, values): if values.get("user_id") is None and values.get("user_email") is None: raise ValueError("Either user id or user email must be provided") @@ -574,7 +574,7 @@ class LiteLLM_TeamTable(TeamBase): protected_namespaces = (), ) - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): dict_fields = [ "metadata", @@ -873,7 +873,7 @@ class UserAPIKeyAuth( user_role: Optional[Literal["proxy_admin", "app_owner", "app_user"]] = None allowed_model_region: Optional[Literal["eu"]] = None - @model_validator(mode="before") + @root_validator(pre=True) def check_api_key(cls, values): if values.get("api_key") is not None: values.update({"token": hash_token(values.get("api_key"))}) @@ -900,7 +900,7 @@ class LiteLLM_UserTable(LiteLLMBase): tpm_limit: Optional[int] = None rpm_limit: Optional[int] = None - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): if values.get("spend") is None: values.update({"spend": 0.0}) @@ -922,7 +922,7 @@ class LiteLLM_EndUserTable(LiteLLMBase): default_model: Optional[str] = None litellm_budget_table: Optional[LiteLLM_BudgetTable] = None - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): if values.get("spend") is None: values.update({"spend": 0.0}) From eacafa7cd7e22898eab05b2348766b66de3cbc2e Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 10:34:05 -0700 Subject: [PATCH 5/9] Revert litellm/types/router.py changes These don't work in pydantic v1. --- litellm/types/router.py | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/litellm/types/router.py b/litellm/types/router.py index f9f6fd989..e8f3ff641 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -1,6 +1,6 @@ from typing import List, Optional, Union, Dict, Tuple, Literal import httpx -from pydantic import ConfigDict, BaseModel, validator, Field +from pydantic import BaseModel, validator, Field from .completion import CompletionRequest from .embedding import EmbeddingRequest import uuid, enum @@ -11,7 +11,9 @@ class ModelConfig(BaseModel): litellm_params: Union[CompletionRequest, EmbeddingRequest] tpm: int rpm: int - model_config = ConfigDict(protected_namespaces=()) + + class Config: + protected_namespaces = () class RouterConfig(BaseModel): @@ -41,7 +43,9 @@ class RouterConfig(BaseModel): "usage-based-routing", "latency-based-routing", ] = "simple-shuffle" - model_config = ConfigDict(protected_namespaces=()) + + class Config: + protected_namespaces = () class UpdateRouterConfig(BaseModel): @@ -60,13 +64,15 @@ class UpdateRouterConfig(BaseModel): retry_after: Optional[float] = None fallbacks: Optional[List[dict]] = None context_window_fallbacks: Optional[List[dict]] = None - model_config = ConfigDict(protected_namespaces=()) + + class Config: + protected_namespaces = () class ModelInfo(BaseModel): id: Optional[ str - ] = None # Allow id to be optional on input, but it will always be present as a str in the model instance + ] # Allow id to be optional on input, but it will always be present as a str in the model instance db_model: bool = ( False # used for proxy - to separate models which are stored in the db vs. config. ) @@ -77,7 +83,9 @@ class ModelInfo(BaseModel): elif isinstance(id, int): id = str(id) super().__init__(id=id, **params) - model_config = ConfigDict(extra="allow") + + class Config: + extra = "allow" def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -171,7 +179,10 @@ class GenericLiteLLMParams(BaseModel): if max_retries is not None and isinstance(max_retries, str): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True) + + class Config: + extra = "allow" + arbitrary_types_allowed = True def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -229,7 +240,10 @@ class LiteLLM_Params(GenericLiteLLMParams): if max_retries is not None and isinstance(max_retries, str): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True) + + class Config: + extra = "allow" + arbitrary_types_allowed = True def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -258,7 +272,9 @@ class updateDeployment(BaseModel): model_name: Optional[str] = None litellm_params: Optional[updateLiteLLMParams] = None model_info: Optional[ModelInfo] = None - model_config = ConfigDict(protected_namespaces=()) + + class Config: + protected_namespaces = () class Deployment(BaseModel): @@ -290,7 +306,10 @@ class Deployment(BaseModel): except Exception as e: # if using pydantic v1 return self.dict(**kwargs) - model_config = ConfigDict(extra="allow", protected_namespaces=()) + + class Config: + extra = "allow" + protected_namespaces = () def __contains__(self, key): # Define custom behavior for the 'in' operator From 4ccdbfd67d28b957111bfb9cd09b672b7b5a071d Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 10:38:01 -0700 Subject: [PATCH 6/9] model_config = ConfigDict instead of model_config = dict --- litellm/proxy/_types.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 24e789544..956c807a3 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field, root_validator, Json +from pydantic import ConfigDict, BaseModel, Field, root_validator, Json import enum from typing import Optional, List, Union, Dict, Literal, Any from datetime import datetime @@ -35,7 +35,7 @@ class LiteLLMBase(BaseModel): # if using pydantic v1 return self.__fields_set__ - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -275,7 +275,7 @@ class ProxyChatCompletionRequest(LiteLLMBase): deployment_id: Optional[str] = None request_timeout: Optional[int] = None - model_config = dict( + model_config = ConfigDict( extra = "allow", # allow params not defined here, these fall in litellm.completion(**kwargs) ) @@ -304,7 +304,7 @@ class ModelInfo(LiteLLMBase): ] ] - model_config = dict( + model_config = ConfigDict( extra = "allow", # Allow extra fields protected_namespaces = (), ) @@ -335,7 +335,7 @@ class ModelParams(LiteLLMBase): litellm_params: dict model_info: ModelInfo - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -375,7 +375,7 @@ class GenerateKeyRequest(GenerateRequestBase): {} ) # {"gpt-4": 5.0, "gpt-3.5-turbo": 5.0}, defaults to {} - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -427,7 +427,7 @@ class LiteLLM_ModelTable(LiteLLMBase): created_by: str updated_by: str - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -515,7 +515,7 @@ class TeamBase(LiteLLMBase): class NewTeamRequest(TeamBase): model_aliases: Optional[dict] = None - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -570,7 +570,7 @@ class LiteLLM_TeamTable(TeamBase): budget_reset_at: Optional[datetime] = None model_id: Optional[int] = None - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -610,7 +610,7 @@ class LiteLLM_BudgetTable(LiteLLMBase): model_max_budget: Optional[dict] = None budget_duration: Optional[str] = None - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -662,7 +662,7 @@ class KeyManagementSettings(LiteLLMBase): class TeamDefaultSettings(LiteLLMBase): team_id: str - model_config = dict( + model_config = ConfigDict( extra = "allow", # allow params not defined here, these fall in litellm.completion(**kwargs) ) @@ -805,7 +805,7 @@ class ConfigYAML(LiteLLMBase): description="litellm router object settings. See router.py __init__ for all, example router.num_retries=5, router.timeout=5, router.max_retries=5, router.retry_after=5", ) - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -841,7 +841,7 @@ class LiteLLM_VerificationToken(LiteLLMBase): user_id_rate_limits: Optional[dict] = None team_id_rate_limits: Optional[dict] = None - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -908,7 +908,7 @@ class LiteLLM_UserTable(LiteLLMBase): values.update({"models": []}) return values - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) @@ -928,7 +928,7 @@ class LiteLLM_EndUserTable(LiteLLMBase): values.update({"spend": 0.0}) return values - model_config = dict( + model_config = ConfigDict( protected_namespaces = (), ) From f233cde36c0a174deb3f66e9cf7e2fbd4f389aed Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 11:04:13 -0700 Subject: [PATCH 7/9] Replace some Config classes with model_config in `litellm/types/router.py` I didn't replace the ones that have `allow_arbitrary_types` because changing those seems to break pydantic v1 compatibility. --- litellm/types/router.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/litellm/types/router.py b/litellm/types/router.py index e8f3ff641..8f4b3f95c 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -1,6 +1,6 @@ from typing import List, Optional, Union, Dict, Tuple, Literal import httpx -from pydantic import BaseModel, validator, Field +from pydantic import ConfigDict, BaseModel, validator, Field from .completion import CompletionRequest from .embedding import EmbeddingRequest import uuid, enum @@ -12,8 +12,9 @@ class ModelConfig(BaseModel): tpm: int rpm: int - class Config: - protected_namespaces = () + model_config = ConfigDict( + protected_namespaces = (), + ) class RouterConfig(BaseModel): @@ -44,8 +45,9 @@ class RouterConfig(BaseModel): "latency-based-routing", ] = "simple-shuffle" - class Config: - protected_namespaces = () + model_config = ConfigDict( + protected_namespaces = (), + ) class UpdateRouterConfig(BaseModel): @@ -65,8 +67,9 @@ class UpdateRouterConfig(BaseModel): fallbacks: Optional[List[dict]] = None context_window_fallbacks: Optional[List[dict]] = None - class Config: - protected_namespaces = () + model_config = ConfigDict( + protected_namespaces = (), + ) class ModelInfo(BaseModel): @@ -84,8 +87,9 @@ class ModelInfo(BaseModel): id = str(id) super().__init__(id=id, **params) - class Config: - extra = "allow" + model_config = ConfigDict( + extra = "allow", + ) def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -273,8 +277,9 @@ class updateDeployment(BaseModel): litellm_params: Optional[updateLiteLLMParams] = None model_info: Optional[ModelInfo] = None - class Config: - protected_namespaces = () + model_config = ConfigDict( + protected_namespaces = (), + ) class Deployment(BaseModel): @@ -307,9 +312,10 @@ class Deployment(BaseModel): # if using pydantic v1 return self.dict(**kwargs) - class Config: - extra = "allow" - protected_namespaces = () + model_config = ConfigDict( + extra = "allow", + protected_namespaces = (), + ) def __contains__(self, key): # Define custom behavior for the 'in' operator From e261a9b2c2c0d285aa1a53b73fb5974339550a17 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 11:22:50 -0700 Subject: [PATCH 8/9] Use Config class w/ arbitrary_types_allowed for pydantic v1 pydantic v2 warns about using a Config class. But without this, pydantic v1 will raise an error: RuntimeError: no validator found for , see `arbitrary_types_allowed` in Config Putting arbitrary_types_allowed = True in the ConfigDict doesn't work in pydantic v1. So we mostly use model_config = ConfigDict(...) and then only use the Config class with arbitrary_types_allowed = True for pydantic v1. --- litellm/types/router.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/litellm/types/router.py b/litellm/types/router.py index 8f4b3f95c..2a984ef34 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -1,6 +1,6 @@ from typing import List, Optional, Union, Dict, Tuple, Literal import httpx -from pydantic import ConfigDict, BaseModel, validator, Field +from pydantic import ConfigDict, BaseModel, validator, Field, __version__ as pydantic_version from .completion import CompletionRequest from .embedding import EmbeddingRequest import uuid, enum @@ -184,9 +184,18 @@ class GenericLiteLLMParams(BaseModel): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - class Config: - extra = "allow" - arbitrary_types_allowed = True + model_config = ConfigDict( + extra = "allow", + arbitrary_types_allowed = True, + ) + if pydantic_version.startswith("1"): + # pydantic v2 warns about using a Config class. + # But without this, pydantic v1 will raise an error: + # RuntimeError: no validator found for , + # see `arbitrary_types_allowed` in Config + # Putting arbitrary_types_allowed = True in the ConfigDict doesn't work in pydantic v1. + class Config: + arbitrary_types_allowed = True def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -245,9 +254,18 @@ class LiteLLM_Params(GenericLiteLLMParams): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - class Config: - extra = "allow" - arbitrary_types_allowed = True + model_config = ConfigDict( + extra = "allow", + arbitrary_types_allowed = True, + ) + if pydantic_version.startswith("1"): + # pydantic v2 warns about using a Config class. + # But without this, pydantic v1 will raise an error: + # RuntimeError: no validator found for , + # see `arbitrary_types_allowed` in Config + # Putting arbitrary_types_allowed = True in the ConfigDict doesn't work in pydantic v1. + class Config: + arbitrary_types_allowed = True def __contains__(self, key): # Define custom behavior for the 'in' operator From bdb995f436de3c342713998bb694c1be35feaede Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 13 May 2024 16:49:36 -0700 Subject: [PATCH 9/9] Revert `= None` changes because @krrishdholakia said [here](https://github.com/BerriAI/litellm/pull/3600#discussion_r1599108453) that they were problematic in the past. --- litellm/integrations/slack_alerting.py | 2 +- litellm/tests/test_streaming.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/litellm/integrations/slack_alerting.py b/litellm/integrations/slack_alerting.py index 34199d6b6..b06a22920 100644 --- a/litellm/integrations/slack_alerting.py +++ b/litellm/integrations/slack_alerting.py @@ -48,7 +48,7 @@ class DeploymentMetrics(LiteLLMBase): failed_request: bool """did it fail the request?""" - latency_per_output_token: Optional[float] = None + latency_per_output_token: Optional[float] """latency/output token of deployment""" updated_at: dt diff --git a/litellm/tests/test_streaming.py b/litellm/tests/test_streaming.py index eb9aa310c..a948a5683 100644 --- a/litellm/tests/test_streaming.py +++ b/litellm/tests/test_streaming.py @@ -2214,15 +2214,15 @@ class ToolCalls(BaseModel): class Delta(BaseModel): role: str - content: Optional[str] = None + content: Optional[str] tool_calls: List[ToolCalls] class Choices(BaseModel): index: int delta: Delta - logprobs: Optional[str] = None - finish_reason: Optional[str] = None + logprobs: Optional[str] + finish_reason: Optional[str] class Chunk(BaseModel): @@ -2276,7 +2276,7 @@ class Function2(BaseModel): class ToolCalls2(BaseModel): index: int - function: Optional[Function2] = None + function: Optional[Function2] class Delta2(BaseModel): @@ -2286,8 +2286,8 @@ class Delta2(BaseModel): class Choices2(BaseModel): index: int delta: Delta2 - logprobs: Optional[str] = None - finish_reason: Optional[str] = None + logprobs: Optional[str] + finish_reason: Optional[str] class Chunk2(BaseModel): @@ -2341,7 +2341,7 @@ class Delta3(BaseModel): class Choices3(BaseModel): index: int delta: Delta3 - logprobs: Optional[str] = None + logprobs: Optional[str] finish_reason: str