mirror of
https://github.com/hwchase17/langchain.git
synced 2026-06-09 10:17:00 +00:00
fix(openai): guard httpx finalizers (#37570)
Same shape as the merged anthropic patch in #37064, ported to `libs/partners/openai`. `_SyncHttpxClientWrapper.__del__` / `_AsyncHttpxClientWrapper.__del__` check `self.is_closed`, which reads `self._state`. When a wrapper is created without `__init__` running to completion — `copy.deepcopy` via `__new__` + `__setstate__`, or a constructor that raised partway through — `_state` is missing and the finalizer prints ``` Exception ignored in: <function _SyncHttpxClientWrapper.__del__ at 0x...> Traceback (most recent call last): File ".../langchain_openai/chat_models/_client_utils.py", line 366, in __del__ if self.is_closed: File ".../httpx/_client.py", line 228, in is_closed return self._state == ClientState.CLOSED AttributeError: '_SyncHttpxClientWrapper' object has no attribute '_state' ``` at GC time. Same noise pattern that #37064 fixed for the anthropic partner. Hoist the `is_closed` access inside the existing `try/except` so the `AttributeError` is swallowed alongside the `close()` / `aclose()` exceptions that block already handles. Tests: two new unit tests build the wrappers via `__new__` (no `__init__` → no `_state`) and call `__del__` directly, mirroring the tests added in #37064. Verified: - `cd libs/partners/openai && make format` -> all checks passed - `cd libs/partners/openai && make test TEST_FILE=tests/unit_tests/chat_models/test_client_utils.py` -> 37 passed, 1 skipped (linux-only) - `cd libs/partners/openai && make lint` -> all checks passed, mypy clean
This commit is contained in:
@@ -810,3 +810,21 @@ def test_client_build_applies_socket_options_when_user_opts_in(
|
||||
assert all(tuple(opts) == tuple(explicit) for opts in recorded), (
|
||||
f"expected user-supplied opts, got {recorded!r}"
|
||||
)
|
||||
|
||||
|
||||
def test_sync_client_wrapper_del_handles_uninitialized_client() -> None:
|
||||
"""Test sync wrapper finalizer handles clients without initialized state."""
|
||||
client = _client_utils._SyncHttpxClientWrapper.__new__(
|
||||
_client_utils._SyncHttpxClientWrapper
|
||||
)
|
||||
|
||||
client.__del__()
|
||||
|
||||
|
||||
async def test_async_client_wrapper_del_handles_uninitialized_client() -> None:
|
||||
"""Test async wrapper finalizer handles clients without initialized state."""
|
||||
client = _client_utils._AsyncHttpxClientWrapper.__new__(
|
||||
_client_utils._AsyncHttpxClientWrapper
|
||||
)
|
||||
|
||||
client.__del__()
|
||||
|
||||
Reference in New Issue
Block a user