mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(ci): stop deferred pydantic builds leaking caller locals and add the missing Lens FK migration (#44981)
* fix(ci): stop deferred pydantic builds leaking caller locals and add missing Lens FK migration Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(types): drop narrating comment from caller-locals regression test Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(proxy-extras): guard the Lens review FK migration with DO blocks Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(types): run the caller-locals regression in-process Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(proxy-extras): scope the Lens review FK guards to their table Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: mateo <mateo@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
68c0a972a7
commit
43cf7e7493
3 changed files with 53 additions and 0 deletions
|
|
@ -0,0 +1,15 @@
|
|||
-- DropForeignKey
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'LiteLLM_LensReview_lens_id_fkey' AND conrelid = '"LiteLLM_LensReview"'::regclass) THEN
|
||||
ALTER TABLE "LiteLLM_LensReview" DROP CONSTRAINT "LiteLLM_LensReview_lens_id_fkey";
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- AddForeignKey
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'LiteLLM_LensReview_lens_id_fkey' AND conrelid = '"LiteLLM_LensReview"'::regclass) THEN
|
||||
ALTER TABLE "LiteLLM_LensReview" ADD CONSTRAINT "LiteLLM_LensReview_lens_id_fkey" FOREIGN KEY ("lens_id") REFERENCES "LiteLLM_Lens"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
from collections.abc import Mapping
|
||||
from typing import TYPE_CHECKING, Any, Final
|
||||
|
||||
from openai._models import BaseModel as OpenAIObject
|
||||
|
|
@ -13,6 +14,24 @@ class LiteLLMBaseModel(BaseModel):
|
|||
|
||||
def __init__(self, /, **data: object) -> None: ...
|
||||
|
||||
@classmethod
|
||||
def model_rebuild(
|
||||
cls,
|
||||
*,
|
||||
force: bool = False,
|
||||
raise_errors: bool = True,
|
||||
_parent_namespace_depth: int = 2,
|
||||
_types_namespace: Mapping[str, object] | None = None,
|
||||
) -> bool | None:
|
||||
# Resolve names from the model's own module, never a caller frame: a deferred first-use build
|
||||
# reads f_locals 5 frames up, and on Python < 3.13 that rewrites the dict the caller's locals() returned
|
||||
return super().model_rebuild(
|
||||
force=force,
|
||||
raise_errors=raise_errors,
|
||||
_parent_namespace_depth=0,
|
||||
_types_namespace=_types_namespace,
|
||||
)
|
||||
|
||||
def model_post_init(self, context: object, /) -> None:
|
||||
# Instances built by a parent's validator or by model_construct skip this class's own
|
||||
# first-use build, leaving a MockValSer that fails when the instance is serialized as Any
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import sys
|
|||
from typing import Final
|
||||
|
||||
import pytest
|
||||
from pydantic import ConfigDict
|
||||
|
||||
from litellm.types.llms.base import LiteLLMBaseModel
|
||||
|
||||
_PROBE: Final = """
|
||||
from litellm.types.llms.base import LiteLLMBaseModel
|
||||
|
|
@ -71,3 +74,19 @@ print(Holder(item=validated).model_dump_json(serialize_as_any=True), Holder(item
|
|||
|
||||
def test_deferred_instances_created_without_their_own_init_still_serialize_as_any() -> None:
|
||||
assert _run_probe(_NESTED_PROBE, None) == '{"item":{"value":1}} {"item":{"value":2}}'
|
||||
|
||||
|
||||
def test_deferred_first_use_build_leaves_caller_locals_snapshot_untouched() -> None:
|
||||
class DeferredProbe(LiteLLMBaseModel):
|
||||
model_config = ConfigDict(defer_build=True)
|
||||
value: int
|
||||
|
||||
def build(model: type[DeferredProbe]) -> list[str]:
|
||||
local_vars: Final = locals()
|
||||
later: Final = 1
|
||||
_ = model(value=later)
|
||||
return sorted(local_vars)
|
||||
|
||||
assert not DeferredProbe.__pydantic_complete__
|
||||
assert build(DeferredProbe) == ["model"]
|
||||
assert DeferredProbe.__pydantic_complete__
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue