fix(rust_bridge): bind Python fallbacks at import so module patches do not leak into public entrypoints

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Yujong Lee 2026-09-16 23:23:36 +00:00
parent 13cb739089
commit 1f0cf4bf42
4 changed files with 39 additions and 32 deletions

View file

@ -41,8 +41,10 @@ def _python_acompletion() -> PythonAcompletion:
)
_COMPLETION: Final = signature(_python_completion())
_ACOMPLETION: Final = signature(_python_acompletion())
_PYTHON_COMPLETION: Final = _python_completion()
_COMPLETION: Final = signature(_PYTHON_COMPLETION)
_PYTHON_ACOMPLETION: Final = _python_acompletion()
_ACOMPLETION: Final = signature(_PYTHON_ACOMPLETION)
def _public_request(
@ -86,7 +88,7 @@ def completion(
*args: object,
**kwargs: object, # kwargs-ok: preserve the public chat completions call shape
) -> ChatResult | Coroutine[object, object, ChatResult]:
python: Final = _python_completion()
python: Final = _PYTHON_COMPLETION
return _DISPATCH.run(
args,
kwargs,
@ -97,7 +99,7 @@ def completion(
async def acompletion(*args: object, **kwargs: object) -> ChatResult: # kwargs-ok: preserve the public call shape
python: Final = _python_acompletion()
python: Final = _PYTHON_ACOMPLETION
return await _ADISPATCH.arun(
args,
kwargs,
@ -116,7 +118,7 @@ def _context(request: LiteLLMChatCompletionsRequest) -> Context:
)
completion.__doc__ = _python_completion().__doc__
completion.__wrapped__ = _python_completion() # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
acompletion.__doc__ = _python_acompletion().__doc__
acompletion.__wrapped__ = _python_acompletion() # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
completion.__doc__ = _PYTHON_COMPLETION.__doc__
completion.__wrapped__ = _PYTHON_COMPLETION # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
acompletion.__doc__ = _PYTHON_ACOMPLETION.__doc__
acompletion.__wrapped__ = _PYTHON_ACOMPLETION # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature

View file

@ -40,8 +40,10 @@ def _python_amessages() -> PythonAmessages:
)
_MESSAGES: Final = signature(_python_messages())
_AMESSAGES: Final = signature(_python_amessages())
_PYTHON_MESSAGES: Final = _python_messages()
_MESSAGES: Final = signature(_PYTHON_MESSAGES)
_PYTHON_AMESSAGES: Final = _python_amessages()
_AMESSAGES: Final = signature(_PYTHON_AMESSAGES)
def _public_request(
@ -85,7 +87,7 @@ def anthropic_messages_handler(
*args: object,
**kwargs: object, # kwargs-ok: preserve the public Anthropic Messages call shape
) -> MessagesResult | Coroutine[object, object, MessagesResult]:
python: Final = _python_messages()
python: Final = _PYTHON_MESSAGES
return _DISPATCH.run(
args,
kwargs,
@ -96,7 +98,7 @@ def anthropic_messages_handler(
async def anthropic_messages(*args: object, **kwargs: object) -> MessagesResult: # kwargs-ok: public call shape
python: Final = _python_amessages()
python: Final = _PYTHON_AMESSAGES
return await _ADISPATCH.arun(
args,
kwargs,
@ -115,7 +117,7 @@ def _context(request: LiteLLMMessagesRequest) -> Context:
)
anthropic_messages_handler.__doc__ = _python_messages().__doc__
anthropic_messages_handler.__wrapped__ = _python_messages() # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
anthropic_messages.__doc__ = _python_amessages().__doc__
anthropic_messages.__wrapped__ = _python_amessages() # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
anthropic_messages_handler.__doc__ = _PYTHON_MESSAGES.__doc__
anthropic_messages_handler.__wrapped__ = _PYTHON_MESSAGES # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
anthropic_messages.__doc__ = _PYTHON_AMESSAGES.__doc__
anthropic_messages.__wrapped__ = _PYTHON_AMESSAGES # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature

View file

@ -42,6 +42,13 @@ def _public_request(name: str, args: tuple[object, ...], kwargs: Mapping[str, ob
raise TypeError(str(error).replace("_bind_request()", f"{name}()")) from None
_PYTHON_OCR: Final = cast( # cast-ok: forward the original call shape through the Python @client decorator
Callable[..., OCRResponse | Coroutine[object, object, OCRResponse]], main.ocr
)
_PYTHON_AOCR: Final = cast( # cast-ok: forward the original call shape through the Python @client decorator
Callable[..., Awaitable[OCRResponse]], main.aocr
)
_DISPATCH: Final = PublicDispatch(
route=Route.OCR,
request=lambda args, kwargs: _public_request("ocr", args, kwargs),
@ -60,26 +67,20 @@ def ocr(
*args: object,
**kwargs: object, # kwargs-ok: preserve the public OCR call shape
) -> OCRResponse | Coroutine[object, object, OCRResponse]:
python_ocr: Final = cast( # cast-ok: forward the original call shape through the Python @client decorator
Callable[..., OCRResponse | Coroutine[object, object, OCRResponse]], main.ocr
)
return _DISPATCH.run(
args,
kwargs,
python=python_ocr,
python=_PYTHON_OCR,
binding=NATIVE_OCR,
native=lambda hook, request, call_args, call_kwargs: hook(request, call_args, call_kwargs),
)
async def aocr(*args: object, **kwargs: object) -> OCRResponse: # kwargs-ok: preserve the public OCR call shape
fallback: Final = cast( # cast-ok: forward the original call shape through the Python @client decorator
Callable[..., Awaitable[OCRResponse]], main.aocr
)
return await _ADISPATCH.arun(
args,
kwargs,
python=fallback,
python=_PYTHON_AOCR,
binding=NATIVE_AOCR,
native=lambda hook, request, call_args, call_kwargs: hook(request, call_args, call_kwargs),
)

View file

@ -34,8 +34,10 @@ def _python_aresponses() -> PythonAresponses:
)
_RESPONSES: Final = signature(_python_responses())
_ARESPONSES: Final = signature(_python_aresponses())
_PYTHON_RESPONSES: Final = _python_responses()
_RESPONSES: Final = signature(_PYTHON_RESPONSES)
_PYTHON_ARESPONSES: Final = _python_aresponses()
_ARESPONSES: Final = signature(_PYTHON_ARESPONSES)
def _public_request(
@ -78,7 +80,7 @@ def responses(
*args: object,
**kwargs: object, # kwargs-ok: preserve the public Responses call shape
) -> ResponsesResult | Coroutine[object, object, ResponsesResult]:
python: Final = _python_responses()
python: Final = _PYTHON_RESPONSES
return _DISPATCH.run(
args,
kwargs,
@ -89,7 +91,7 @@ def responses(
async def aresponses(*args: object, **kwargs: object) -> ResponsesResult: # kwargs-ok: preserve the public call shape
python: Final = _python_aresponses()
python: Final = _PYTHON_ARESPONSES
return await _ADISPATCH.arun(
args,
kwargs,
@ -108,7 +110,7 @@ def _context(request: LiteLLMResponsesRequest) -> Context:
)
responses.__doc__ = _python_responses().__doc__
responses.__wrapped__ = _python_responses() # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
aresponses.__doc__ = _python_aresponses().__doc__
aresponses.__wrapped__ = _python_aresponses() # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
responses.__doc__ = _PYTHON_RESPONSES.__doc__
responses.__wrapped__ = _PYTHON_RESPONSES # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature
aresponses.__doc__ = _PYTHON_ARESPONSES.__doc__
aresponses.__wrapped__ = _PYTHON_ARESPONSES # pyright: ignore[reportFunctionMemberAccess] # inspect.signature follows __wrapped__ to the legacy signature