From 25af094e27ba4b40ceabaccbae944528a807c3cf Mon Sep 17 00:00:00 2001 From: Yujong Lee Date: Mon, 21 Sep 2026 20:52:28 +0000 Subject: [PATCH] fix(python-bridge): allow instance attributes to shadow class defaults Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../crates/python-bridge/src/cache/facade.rs | 5 +- litellm/rust_bridge/_native.pyi | 64 ++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/litellm-rust/crates/python-bridge/src/cache/facade.rs b/litellm-rust/crates/python-bridge/src/cache/facade.rs index 58730857d60..d7ec2052dd0 100644 --- a/litellm-rust/crates/python-bridge/src/cache/facade.rs +++ b/litellm-rust/crates/python-bridge/src/cache/facade.rs @@ -117,7 +117,10 @@ impl ObjectGuard { return Ok(false); } for (name, value) in &expected.attributes { - if instance.contains(name)? || !attributes.get_item(name)?.is(value.bind(py)) { + if !attributes.get_item(name)?.is(value.bind(py)) { + return Ok(false); + } + if instance.contains(name)? && value.bind(py).is_callable() { return Ok(false); } } diff --git a/litellm/rust_bridge/_native.pyi b/litellm/rust_bridge/_native.pyi index 05a6df6d5af..7eb266d5a09 100644 --- a/litellm/rust_bridge/_native.pyi +++ b/litellm/rust_bridge/_native.pyi @@ -1,6 +1,6 @@ from asyncio import Future from collections.abc import AsyncIterator, Coroutine, Iterator, Mapping, Sequence -from typing import Never, final +from typing import Literal, Never, final from litellm.llms.base_llm.ocr.transformation import OCRResponse from litellm.rust_bridge.messages.entrypoints import LiteLLMMessagesRequest @@ -93,6 +93,68 @@ class ResponsesWebSocketConnection: def recv_text(self) -> Future[str | None]: ... def close(self) -> Future[None]: ... +@final +class _CacheTestHandle: + def __new__(cls, _uninstantiable: Never, /) -> Never: ... + @staticmethod + def memory( + *, + capacity: int = 200, + ttl_seconds: float = 600.0, + max_entry_bytes: int = 1048576, + ) -> _CacheTestHandle: ... + @staticmethod + def redis( + url: str, + *, + ttl_seconds: float = 60.0, + namespace: str | None = None, + ) -> _CacheTestHandle: ... + @staticmethod + def redis_semantic(backend: object) -> _CacheTestHandle: ... + @property + def backend(self) -> Literal["memory", "redis", "redis_semantic"]: ... + def _bind_facade(self, facade: object) -> None: ... + +@final +class _CacheTestBinding: + def __new__(cls, _uninstantiable: Never, /) -> Never: ... + @property + def kind(self) -> Literal["disabled", "native", "python_callback"]: ... + def lookup( + self, request: object, *, callback_kwargs: object = None + ) -> object: ... + def store( + self, request: object, response: object, *, callback_kwargs: object = None + ) -> None: ... + def lookup_batch( + self, requests: object, *, callback_kwargs: object = None + ) -> object: ... + def async_lookup( + self, request: object, *, callback_kwargs: object = None + ) -> Future[object]: ... + def async_store( + self, request: object, response: object, *, callback_kwargs: object = None + ) -> Future[object]: ... + def async_lookup_batch( + self, requests: object, *, callback_kwargs: object = None + ) -> Future[object]: ... + def async_store_batch( + self, + requests: object, + responses: object, + *, + callback_result: object = None, + callback_kwargs: object = None, + ) -> Future[object]: ... + def async_flush(self) -> Future[object]: ... + def ping(self) -> Future[object]: ... + +@final +class _CacheTestResolver: + def __new__(cls, namespace: object) -> _CacheTestResolver: ... + def resolve(self) -> _CacheTestBinding: ... + @final class TokenCounter: def __new__(cls, tokenizer_json: str) -> TokenCounter: ...