feat(client): Add experimental runtime support for HTTPX2 clients (#3524)
Refs https://github.com/openai/openai-python/issues/3375. ## Summary Adds experimental runtime support for using an HTTPX2 client with the 2.x SDK: ```sh pip install 'openai[httpx2]' ``` ```python from openai import OpenAI, AsyncOpenAI, DefaultHttpx2Client, DefaultAsyncHttpx2Client client = OpenAI(http_client=DefaultHttpx2Client()) async_client = AsyncOpenAI(http_client=DefaultAsyncHttpx2Client()) ``` HTTPX remains installed, imported, and authoritative for the SDK's public transport types. Existing HTTPX clients and helpers continue to work unchanged. This is an explicit runtime opt-in, not a default-transport or typing migration: generated/parsed API models remain accurately typed, while _raw requests, responses, streams, and transport exceptions can be HTTPX2 objects even where annotations still describe HTTPX_. The implementation keeps the compatibility boundary small: - accepts sync, async, and module-level HTTPX2 clients and preserves their native request/response/exception family; - supplies `DefaultHttpx2Client` and `DefaultAsyncHttpx2Client` with the SDK defaults, while retaining the existing HTTPX and aiohttp helpers; - handles the concrete request, timeout, URL, response-casting, retry, streaming, auth, and provider differences needed at runtime; - makes workload-identity token exchange follow an explicitly selected HTTPX2 client (including async clients, whose exchange still runs synchronously in the existing worker-thread path), without changing behavior merely because HTTPX2 happens to be installed. The `httpx2` extra is available on Python 3.10+ and scopes its resolver requirements to the opt-in path (`httpx>=0.25.1,<1`, `httpx2>=2.7,<3`, and `anyio>=4.10,<5`). Base installations retain the existing Python, HTTPX, and AnyIO floors. On Python 3.9 the extra is marker-skipped and invoking an HTTPX2 helper produces an actionable error. Intentionally mixed HTTPX/HTTPX2 transports or auth implementations are out of scope. ## Gaps - This pr does not address `aiohttp`+ `httpx2`; that can be a future addition if there is interest. This would require a separate addon and for us to vendor in some of the implementation; so avoiding in this PR. - Types stay on `httpx`, and `httpx` is still required to be an installed package. - reasoning: we considered `httpx | httpx2` as a migration shim, or returning `httpx2` type annotations. Will continue to evaluate the ecosystem, although `httpx2` types will unfortunately likely require many updates from downstream packages. Saving those considerations for potential future major versions. - For now, we do not address `httpx.timeout` annotations in generated code as well ## Testing The HTTPX2 CI lane runs the normal suite with native HTTPX2 sync/async clients in both Pydantic modes. Existing RESPX-backed cases are exercised through a small, test-only bridge: HTTPX2 uses a native `MockTransport`, the bridge translates only at the RESPX matching/callback boundary, and the SDK still builds and receives native HTTPX2 requests/responses. This keeps generated binary/raw/streaming, retry, auth, Azure, Bedrock, and snapshot coverage shared instead of maintaining duplicate tests; aiohttp remains a separate HTTPX-family path. Focused native tests also cover client defaults, direct injection, raw/SSE/multipart, retries and exception families, hooks/mounts/proxies, provider auth, workload-identity exchange/cache/401 refresh, and base-only/extra resolver behavior. Local full-suite runs pass with HTTPX2/Pydantic 2 and the HTTPX2 floor/Pydantic 1; the ordinary HTTPX suite and lint/type checks remain clean.
A
Alex Chang committed
e1925e9804aa1bbd33359d91ed3fee105cac103f
Parent: 7f4edb6
Committed by stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
on 7/22/2026, 5:46:08 PM