fix(python-bridge): allow instance attributes to shadow class defaults

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Yujong Lee 2026-09-21 20:52:28 +00:00
parent 10b977fe29
commit 25af094e27
2 changed files with 67 additions and 2 deletions

View file

@ -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);
}
}

View file

@ -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: ...