From 8e3aa142872a362cc5958a501b5e17323c5aa934 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 15 May 2024 19:40:34 -0700 Subject: [PATCH 1/6] fix revert 3600 --- litellm/proxy/_types.py | 109 ++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 60 deletions(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index b1af153e81..0320b0d0f9 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -1,37 +1,11 @@ -from pydantic import ConfigDict, BaseModel, Field, root_validator, Json, VERSION +from pydantic import BaseModel, Extra, Field, root_validator, Json, validator +from dataclasses import fields import enum from typing import Optional, List, Union, Dict, Literal, Any from datetime import datetime -import uuid -import json +import uuid, json, sys, os from litellm.types.router import UpdateRouterConfig -try: - from pydantic import model_validator # type: ignore -except ImportError: - from pydantic import root_validator # pydantic v1 - - def model_validator(mode): # type: ignore - pre = mode == "before" - return root_validator(pre=pre) - - -# Function to get Pydantic version -def is_pydantic_v2() -> int: - return int(VERSION.split(".")[0]) - - -def get_model_config(arbitrary_types_allowed: bool = False) -> ConfigDict: - # Version-specific configuration - if is_pydantic_v2() >= 2: - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=arbitrary_types_allowed, protected_namespaces=()) # type: ignore - else: - from pydantic import Extra - - model_config = ConfigDict(extra=Extra.allow, arbitrary_types_allowed=arbitrary_types_allowed) # type: ignore - - return model_config - def hash_token(token: str): import hashlib @@ -61,7 +35,8 @@ class LiteLLMBase(BaseModel): # if using pydantic v1 return self.__fields_set__ - model_config = get_model_config() + class Config: + protected_namespaces = () class LiteLLM_UpperboundKeyGenerateParams(LiteLLMBase): @@ -104,11 +79,6 @@ class LiteLLMRoutes(enum.Enum): "/v1/models", ] - # NOTE: ROUTES ONLY FOR MASTER KEY - only the Master Key should be able to Reset Spend - master_key_only_routes: List = [ - "/global/spend/reset", - ] - info_routes: List = [ "/key/info", "/team/info", @@ -119,6 +89,11 @@ class LiteLLMRoutes(enum.Enum): "/v2/key/info", ] + # NOTE: ROUTES ONLY FOR MASTER KEY - only the Master Key should be able to Reset Spend + master_key_only_routes: List = [ + "/global/spend/reset", + ] + sso_only_routes: List = [ "/key/generate", "/key/update", @@ -259,7 +234,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: @@ -317,7 +292,8 @@ class ProxyChatCompletionRequest(LiteLLMBase): deployment_id: Optional[str] = None request_timeout: Optional[int] = None - model_config = get_model_config() + class Config: + extra = "allow" # allow params not defined here, these fall in litellm.completion(**kwargs) class ModelInfoDelete(LiteLLMBase): @@ -344,9 +320,11 @@ class ModelInfo(LiteLLMBase): ] ] - model_config = get_model_config() + class Config: + extra = Extra.allow # Allow extra fields + 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())}) @@ -372,9 +350,10 @@ class ModelParams(LiteLLMBase): litellm_params: dict model_info: ModelInfo - model_config = get_model_config() + class Config: + 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()}) @@ -410,7 +389,8 @@ class GenerateKeyRequest(GenerateRequestBase): {} ) # {"gpt-4": 5.0, "gpt-3.5-turbo": 5.0}, defaults to {} - model_config = get_model_config() + class Config: + protected_namespaces = () class GenerateKeyResponse(GenerateKeyRequest): @@ -420,7 +400,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")}) @@ -460,7 +440,8 @@ class LiteLLM_ModelTable(LiteLLMBase): created_by: str updated_by: str - model_config = get_model_config() + class Config: + protected_namespaces = () class NewUserRequest(GenerateKeyRequest): @@ -488,7 +469,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") @@ -508,7 +489,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.") @@ -521,7 +502,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") @@ -546,7 +527,8 @@ class TeamBase(LiteLLMBase): class NewTeamRequest(TeamBase): model_aliases: Optional[dict] = None - model_config = get_model_config() + class Config: + protected_namespaces = () class GlobalEndUsersSpend(LiteLLMBase): @@ -565,7 +547,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") @@ -599,9 +581,10 @@ class LiteLLM_TeamTable(TeamBase): budget_reset_at: Optional[datetime] = None model_id: Optional[int] = None - model_config = get_model_config() + class Config: + protected_namespaces = () - @model_validator(mode="before") + @root_validator(pre=True) def set_model_info(cls, values): dict_fields = [ "metadata", @@ -637,7 +620,8 @@ class LiteLLM_BudgetTable(LiteLLMBase): model_max_budget: Optional[dict] = None budget_duration: Optional[str] = None - model_config = get_model_config() + class Config: + protected_namespaces = () class NewOrganizationRequest(LiteLLM_BudgetTable): @@ -687,7 +671,8 @@ class KeyManagementSettings(LiteLLMBase): class TeamDefaultSettings(LiteLLMBase): team_id: str - model_config = get_model_config() + class Config: + extra = "allow" # allow params not defined here, these fall in litellm.completion(**kwargs) class DynamoDBArgs(LiteLLMBase): @@ -828,7 +813,8 @@ 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 = get_model_config() + class Config: + protected_namespaces = () class LiteLLM_VerificationToken(LiteLLMBase): @@ -862,7 +848,8 @@ class LiteLLM_VerificationToken(LiteLLMBase): user_id_rate_limits: Optional[dict] = None team_id_rate_limits: Optional[dict] = None - model_config = get_model_config() + class Config: + protected_namespaces = () class LiteLLM_VerificationTokenView(LiteLLM_VerificationToken): @@ -892,7 +879,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"))}) @@ -919,7 +906,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}) @@ -927,7 +914,8 @@ class LiteLLM_UserTable(LiteLLMBase): values.update({"models": []}) return values - model_config = get_model_config() + class Config: + protected_namespaces = () class LiteLLM_EndUserTable(LiteLLMBase): @@ -939,13 +927,14 @@ 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}) return values - model_config = get_model_config() + class Config: + protected_namespaces = () class LiteLLM_SpendLogs(LiteLLMBase): From 136746abc985986760cab5dbc54b88c9bbc09cbf Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 15 May 2024 19:42:39 -0700 Subject: [PATCH 2/6] fix test config --- litellm/tests/test_config.py | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/litellm/tests/test_config.py b/litellm/tests/test_config.py index 96c766919e..e38187e0ea 100644 --- a/litellm/tests/test_config.py +++ b/litellm/tests/test_config.py @@ -5,7 +5,6 @@ import sys, os import traceback from dotenv import load_dotenv -from pydantic import ConfigDict load_dotenv() import os, io @@ -14,36 +13,21 @@ sys.path.insert( 0, os.path.abspath("../..") ) # Adds the parent directory to the, system path import pytest, litellm -from pydantic import BaseModel, VERSION +from pydantic import BaseModel from litellm.proxy.proxy_server import ProxyConfig from litellm.proxy.utils import encrypt_value, ProxyLogging, DualCache from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo from typing import Literal -# Function to get Pydantic version -def is_pydantic_v2() -> int: - return int(VERSION.split(".")[0]) - - -def get_model_config(arbitrary_types_allowed: bool = False) -> ConfigDict: - # Version-specific configuration - if is_pydantic_v2() >= 2: - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=arbitrary_types_allowed, protected_namespaces=()) # type: ignore - else: - from pydantic import Extra - - model_config = ConfigDict(extra=Extra.allow, arbitrary_types_allowed=arbitrary_types_allowed) # type: ignore - - return model_config - - class DBModel(BaseModel): model_id: str model_name: str model_info: dict litellm_params: dict - model_config = get_model_config() + + class Config: + protected_namespaces = () @pytest.mark.asyncio From 86223bc7038575f56294c952f231233289f64780 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 15 May 2024 19:45:16 -0700 Subject: [PATCH 3/6] revert changes to types/completion.py --- litellm/types/completion.py | 25 +++++-------------------- litellm/types/embedding.py | 24 +++++------------------- 2 files changed, 10 insertions(+), 39 deletions(-) diff --git a/litellm/types/completion.py b/litellm/types/completion.py index 87a7629daf..78af7667ba 100644 --- a/litellm/types/completion.py +++ b/litellm/types/completion.py @@ -1,27 +1,10 @@ -from typing import List, Optional, Union, Iterable, cast +from typing import List, Optional, Union, Iterable -from pydantic import ConfigDict, BaseModel, validator, VERSION +from pydantic import BaseModel, validator from typing_extensions import Literal, Required, TypedDict -# Function to get Pydantic version -def is_pydantic_v2() -> int: - return int(VERSION.split(".")[0]) - - -def get_model_config() -> ConfigDict: - # Version-specific configuration - if is_pydantic_v2() >= 2: - model_config = ConfigDict(extra="allow", protected_namespaces=()) # type: ignore - else: - from pydantic import Extra - - model_config = ConfigDict(extra=Extra.allow) # type: ignore - - return model_config - - class ChatCompletionSystemMessageParam(TypedDict, total=False): content: Required[str] """The contents of the system message.""" @@ -208,4 +191,6 @@ class CompletionRequest(BaseModel): api_key: Optional[str] = None model_list: Optional[List[str]] = None - model_config = get_model_config() + class Config: + extra = "allow" + protected_namespaces = () diff --git a/litellm/types/embedding.py b/litellm/types/embedding.py index 831c4266c3..9db0ef2907 100644 --- a/litellm/types/embedding.py +++ b/litellm/types/embedding.py @@ -1,23 +1,6 @@ from typing import List, Optional, Union -from pydantic import ConfigDict, BaseModel, validator, VERSION - - -# Function to get Pydantic version -def is_pydantic_v2() -> int: - return int(VERSION.split(".")[0]) - - -def get_model_config(arbitrary_types_allowed: bool = False) -> ConfigDict: - # Version-specific configuration - if is_pydantic_v2() >= 2: - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=arbitrary_types_allowed, protected_namespaces=()) # type: ignore - else: - from pydantic import Extra - - model_config = ConfigDict(extra=Extra.allow, arbitrary_types_allowed=arbitrary_types_allowed) # type: ignore - - return model_config +from pydantic import BaseModel, validator class EmbeddingRequest(BaseModel): @@ -34,4 +17,7 @@ class EmbeddingRequest(BaseModel): litellm_call_id: Optional[str] = None litellm_logging_obj: Optional[dict] = None logger_fn: Optional[str] = None - model_config = get_model_config() + + class Config: + # allow kwargs + extra = "allow" From 1a67f244fb6df331790e1f15d60663cf534c48ea Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 15 May 2024 19:46:30 -0700 Subject: [PATCH 4/6] fix types/router.py --- litellm/types/router.py | 70 ++++++++++++----------------------------- 1 file changed, 20 insertions(+), 50 deletions(-) diff --git a/litellm/types/router.py b/litellm/types/router.py index 0cc84d8c30..68ee387fea 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -1,42 +1,19 @@ from typing import List, Optional, Union, Dict, Tuple, Literal, TypedDict import httpx -from pydantic import ( - ConfigDict, - BaseModel, - validator, - Field, - __version__ as pydantic_version, - VERSION, -) +from pydantic import BaseModel, validator, Field from .completion import CompletionRequest from .embedding import EmbeddingRequest import uuid, enum -# Function to get Pydantic version -def is_pydantic_v2() -> int: - return int(VERSION.split(".")[0]) - - -def get_model_config(arbitrary_types_allowed: bool = False) -> ConfigDict: - # Version-specific configuration - if is_pydantic_v2() >= 2: - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=arbitrary_types_allowed, protected_namespaces=()) # type: ignore - else: - from pydantic import Extra - - model_config = ConfigDict(extra=Extra.allow, arbitrary_types_allowed=arbitrary_types_allowed) # type: ignore - - return model_config - - class ModelConfig(BaseModel): model_name: str litellm_params: Union[CompletionRequest, EmbeddingRequest] tpm: int rpm: int - model_config = get_model_config() + class Config: + protected_namespaces = () class RouterConfig(BaseModel): @@ -67,7 +44,8 @@ class RouterConfig(BaseModel): "latency-based-routing", ] = "simple-shuffle" - model_config = get_model_config() + class Config: + protected_namespaces = () class UpdateRouterConfig(BaseModel): @@ -87,7 +65,8 @@ class UpdateRouterConfig(BaseModel): fallbacks: Optional[List[dict]] = None context_window_fallbacks: Optional[List[dict]] = None - model_config = get_model_config() + class Config: + protected_namespaces = () class ModelInfo(BaseModel): @@ -105,7 +84,8 @@ class ModelInfo(BaseModel): id = str(id) super().__init__(id=id, **params) - model_config = get_model_config() + class Config: + extra = "allow" def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -200,15 +180,9 @@ class GenericLiteLLMParams(BaseModel): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - model_config = get_model_config(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 + class Config: + extra = "allow" + arbitrary_types_allowed = True def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -267,16 +241,9 @@ class LiteLLM_Params(GenericLiteLLMParams): max_retries = int(max_retries) # cast to int super().__init__(max_retries=max_retries, **args, **params) - model_config = get_model_config(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 + class Config: + extra = "allow" + arbitrary_types_allowed = True def __contains__(self, key): # Define custom behavior for the 'in' operator @@ -306,7 +273,8 @@ class updateDeployment(BaseModel): litellm_params: Optional[updateLiteLLMParams] = None model_info: Optional[ModelInfo] = None - model_config = get_model_config() + class Config: + protected_namespaces = () class LiteLLMParamsTypedDict(TypedDict, total=False): @@ -380,7 +348,9 @@ class Deployment(BaseModel): # if using pydantic v1 return self.dict(**kwargs) - model_config = get_model_config() + class Config: + extra = "allow" + protected_namespaces = () def __contains__(self, key): # Define custom behavior for the 'in' operator From 765d43d2414b2c6178868bdbe73e89c3eb749d49 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 15 May 2024 19:54:52 -0700 Subject: [PATCH 5/6] fix utils.py --- litellm/utils.py | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/litellm/utils.py b/litellm/utils.py index 88b85feff7..f82ae1e449 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -19,7 +19,7 @@ from functools import wraps, lru_cache import datetime, time import tiktoken import uuid -from pydantic import ConfigDict, BaseModel, VERSION +from pydantic import BaseModel import aiohttp import textwrap import logging @@ -185,23 +185,6 @@ last_fetched_at_keys = None # } -# Function to get Pydantic version -def is_pydantic_v2() -> int: - return int(VERSION.split(".")[0]) - - -def get_model_config(arbitrary_types_allowed: bool = False) -> ConfigDict: - # Version-specific configuration - if is_pydantic_v2() >= 2: - model_config = ConfigDict(extra="allow", arbitrary_types_allowed=arbitrary_types_allowed, protected_namespaces=()) # type: ignore - else: - from pydantic import Extra - - model_config = ConfigDict(extra=Extra.allow, arbitrary_types_allowed=arbitrary_types_allowed) # type: ignore - - return model_config - - class UnsupportedParamsError(Exception): def __init__(self, status_code, message): self.status_code = status_code @@ -348,7 +331,10 @@ 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 - model_config = get_model_config() + + class Config: + 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 c2a306c4ddab0154b1c892d6bb4150f08e4f5aad Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 15 May 2024 20:03:30 -0700 Subject: [PATCH 6/6] (ci/cd) run again --- litellm/tests/test_completion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/tests/test_completion.py b/litellm/tests/test_completion.py index 4aa967848f..120a65acbf 100644 --- a/litellm/tests/test_completion.py +++ b/litellm/tests/test_completion.py @@ -38,7 +38,7 @@ def reset_callbacks(): @pytest.mark.skip(reason="Local test") def test_response_model_none(): """ - Addresses: https://github.com/BerriAI/litellm/issues/2972 + Addresses:https://github.com/BerriAI/litellm/issues/2972 """ x = completion( model="mymodel",