diff --git a/.castiron.stats.yml b/.castiron.stats.yml
index 530b190a4f..7f2789e84c 100644
--- a/.castiron.stats.yml
+++ b/.castiron.stats.yml
@@ -1,6 +1,6 @@
schema_version: 1
-generation_id: e1943695-9da0-4ac1-ae5a-cc763f5d90be
+generation_id: 6f16b5a1-6b31-43ea-a1dd-a1a9fc37821e
openapi_spec_hash: 1faf0319c407c6534ef7c381614afbb6
openapi_transformed_spec_hash: 53eff50caa9d18046e4ff0615bc7512d
config_hash: 4617b0962f16d328804312ac81aac630
-codegen_sha: b97c76f867d26f99d0de01d6283fa6d511044141
+codegen_sha: 20f59b5cced5772bda4c6d6e3e19726d3805e4a1
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 5c2b1511f2..4191c8899b 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.54.0"
+ ".": "3.0.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 851881a834..c2e2c7ae29 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## [3.0.0](https://github.com/openai/openai-python/compare/v2.54.0...v3.0.0) (2026-08-12)
+
+
+### ⚠ BREAKING CHANGES
+
+* **api:** HTTPX2 is now the default HTTP client, and `httpx` is no longer installed automatically. Applications using custom HTTPX clients, transports, or configuration objects must migrate to their HTTPX2 equivalents or use the temporary, runtime-only legacy HTTPX escape hatch. See the [HTTPX2 migration guide](https://github.com/openai/openai-python/blob/main/httpx2.md).
+
+### Features
+
+* **api:** migrate to HTTPX2 ([#3594](https://github.com/openai/openai-python/pull/3594))
+
## [2.54.0](https://github.com/openai/openai-python/compare/v2.53.0...v2.54.0) (2026-08-11)
diff --git a/README.md b/README.md
index b5774f4c94..a8b39edfa7 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.10+
application. The library includes type definitions for all request params and response fields,
-and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
+and offers both synchronous and asynchronous clients powered by [HTTPX2](https://httpx2.pydantic.dev/).
It is generated from our [OpenAPI specification](https://github.com/openai/openai-openapi) with [Stainless](https://stainlessapi.com/).
@@ -244,9 +244,7 @@ Functionality between the synchronous and asynchronous clients is otherwise iden
### With aiohttp
-By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
-
-The `aiohttp` backend requires Python 3.10 or later.
+By default, the async client uses HTTPX2. For improved concurrency performance, you may also use `aiohttp` as the HTTPX2 transport.
You can enable this by installing `aiohttp`:
@@ -283,32 +281,9 @@ async def main() -> None:
asyncio.run(main())
```
-### Experimental HTTPX2 support
-
-To opt in to experimental HTTPX2 support, install the optional extra on Python 3.10 or later:
-
-```sh
-pip install 'openai[httpx2]'
-```
-
-```python
-from openai import OpenAI, AsyncOpenAI, DefaultHttpx2Client, DefaultAsyncHttpx2Client
-
-client = OpenAI(http_client=DefaultHttpx2Client())
-async_client = AsyncOpenAI(http_client=DefaultAsyncHttpx2Client())
-```
-
-See [`examples/httpx2_client.py`](examples/httpx2_client.py) for a minimal runnable example.
+### HTTPX2 migration
-The module-level client can be configured in the same way:
-
-```python
-import openai
-
-openai.http_client = openai.DefaultHttpx2Client()
-```
-
-Parsed API models are unchanged, but requests, raw and streaming responses, and transport-level exceptions may be HTTPX2 objects at runtime. Code that catches HTTPX exceptions or relies on HTTPX-specific mocks, transports, authentication, hooks, or instrumentation may need to be updated. Transport-facing type annotations may still describe HTTPX.
+HTTPX2 is the default HTTP client. If you configure a custom HTTP client, transport, timeout, authentication handler, event hook, or request mock, see the [HTTPX2 migration guide](httpx2.md).
## Streaming responses
@@ -636,7 +611,7 @@ try:
)
except openai.APIConnectionError as e:
print("The server could not be reached")
- print(e.__cause__) # an underlying Exception, likely raised within httpx.
+ print(e.__cause__) # an underlying Exception, likely raised within HTTPX2.
except openai.RateLimitError as e:
print("A 429 status code was received; we should back off a bit.")
except openai.APIStatusError as e:
@@ -723,9 +698,10 @@ client.with_options(max_retries=5).chat.completions.create(
## Timeouts
By default requests time out after 10 minutes. You can configure this with a `timeout` option,
-which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
+which accepts a float or an [`httpx2.Timeout`](https://httpx2.pydantic.dev/) object:
```python
+import httpx2
from openai import OpenAI
# Configure the default for all requests:
@@ -736,7 +712,7 @@ client = OpenAI(
# More granular control:
client = OpenAI(
- timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
+ timeout=httpx2.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
)
# Override per-request:
@@ -849,11 +825,11 @@ To make requests to undocumented endpoints, you can make requests using `client.
http verbs. Options on the client will be respected (such as retries) when making this request.
```py
-import httpx
+import httpx2
response = client.post(
"/foo",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
body={"my_param": True},
)
@@ -873,22 +849,18 @@ can also get all the extra fields on the Pydantic model as a dict with
### Configuring the HTTP client
-You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
-
-- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)
-- Custom [transports](https://www.python-httpx.org/advanced/transports/)
-- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality
+You can override the [HTTPX2 client](https://httpx2.pydantic.dev/) to customize proxies, transports, authentication, event hooks, and other advanced HTTP behavior. See the [HTTPX2 migration guide](httpx2.md) when updating an existing custom client.
```python
-import httpx
-from openai import OpenAI, DefaultHttpxClient
+import httpx2
+from openai import OpenAI, DefaultHttpx2Client
client = OpenAI(
# Or use the `OPENAI_BASE_URL` env var
base_url="http://my.test.server.example.com:8083/v1",
- http_client=DefaultHttpxClient(
+ http_client=DefaultHttpx2Client(
proxy="http://my.test.proxy.example.com",
- transport=httpx.HTTPTransport(local_address="0.0.0.0"),
+ transport=httpx2.HTTPTransport(local_address="0.0.0.0"),
),
)
```
@@ -896,7 +868,7 @@ client = OpenAI(
You can also customize the client on a per-request basis by using `with_options()`:
```python
-client.with_options(http_client=DefaultHttpxClient(...))
+client.with_options(http_client=DefaultHttpx2Client(...))
```
#### Mutual TLS
@@ -913,7 +885,7 @@ and pass it through the custom HTTP client:
import os
import ssl
-from openai import OpenAI, DefaultHttpxClient
+from openai import OpenAI, DefaultHttpx2Client
# Server trust is configured independently. Without `cafile`, this uses the
# operating system's normal trusted certificate authorities.
@@ -938,7 +910,7 @@ client = OpenAI(
),
# A client certificate belongs to the HTTP client, not the base URL.
# Disable redirects so it cannot follow a response to another origin.
- http_client=DefaultHttpxClient(
+ http_client=DefaultHttpx2Client(
verify=ssl_context,
follow_redirects=False,
),
@@ -951,7 +923,7 @@ The async configuration is equivalent:
import os
import ssl
-from openai import AsyncOpenAI, DefaultAsyncHttpxClient
+from openai import AsyncOpenAI, DefaultAsyncHttpx2Client
ssl_context = ssl.create_default_context(
cafile=os.environ.get("OPENAI_MTLS_CA_BUNDLE"),
@@ -968,27 +940,7 @@ client = AsyncOpenAI(
"OPENAI_BASE_URL",
"https://mtls.api.openai.com/v1",
),
- http_client=DefaultAsyncHttpxClient(
- verify=ssl_context,
- follow_redirects=False,
- ),
-)
-```
-
-Experimental HTTPX2 uses the same native `SSLContext`. Install the optional
-extra with `pip install 'openai[httpx2]'`, then use `DefaultHttpx2Client` or
-`DefaultAsyncHttpx2Client` in place of the corresponding HTTPX client above:
-
-```python
-from openai import OpenAI, DefaultHttpx2Client
-
-client = OpenAI(
- api_key=os.environ["OPENAI_API_KEY"],
- base_url=os.environ.get(
- "OPENAI_BASE_URL",
- "https://mtls.api.openai.com/v1",
- ),
- http_client=DefaultHttpx2Client(
+ http_client=DefaultAsyncHttpx2Client(
verify=ssl_context,
follow_redirects=False,
),
@@ -1001,7 +953,7 @@ See the complete [sync HTTPX2](examples/mtls_httpx2.py) and
The certificate-bearing HTTP client is transport-wide. Dedicate it to the
selected mTLS origin; do not reuse it for other services or pass it through
`with_options()` with a different `base_url`. If redirects are required, add an
-HTTPX request hook that rejects requests whose scheme, host, or port differs
+HTTPX2 request hook that rejects requests whose scheme, host, or port differs
from the configured mTLS origin before enabling `follow_redirects`.
`SSLContext.load_cert_chain()` raises during setup for unreadable or malformed
diff --git a/httpx2.md b/httpx2.md
new file mode 100644
index 0000000000..044be5a533
--- /dev/null
+++ b/httpx2.md
@@ -0,0 +1,301 @@
+# Migrating to HTTPX2
+
+The OpenAI Python SDK now uses [HTTPX2](https://httpx2.pydantic.dev/) for its
+synchronous and asynchronous HTTP clients. HTTPX2 is installed automatically
+with `openai`; the previous `httpx` package is not. This guide explains what
+changes for applications that interact with the SDK's HTTP layer.
+
+## If you use the SDK's default HTTP client
+
+If you construct an `OpenAI` or
+`AsyncOpenAI` client without providing `http_client`, your existing API calls,
+parsed response models, streaming APIs, authentication, retries, and numeric
+timeouts continue to work:
+
+```python
+from openai import OpenAI
+
+client = OpenAI(timeout=30.0)
+response = client.responses.create(model="gpt-5.5", input="Hello")
+```
+
+No HTTPX2 extra or separate installation is required:
+
+```sh
+pip install openai
+```
+
+If your application imported `httpx` only because an earlier SDK installed it
+transitively, add your own `httpx` dependency or migrate those imports to
+`httpx2`. Installing the SDK no longer installs `httpx` for you.
+
+## TLS certificates and trust stores
+
+**HTTPX2 changes the default TLS trust store, including for applications that
+use the SDK's default HTTP client.** HTTPX previously verified certificates
+against the CA bundle provided by `certifi`. HTTPX2 instead uses the
+operating-system trust store, and the SDK no longer installs `certifi`.
+
+This can break certificate verification in minimal container images without
+system CA certificates, environments using corporate TLS-inspecting proxies,
+and deployments that relied on a custom or modified `certifi` bundle. Install
+the required CA certificates in the operating-system trust store, or configure
+an explicit certificate bundle:
+
+```sh
+export SSL_CERT_FILE=/path/to/ca-bundle.pem
+```
+
+Alternatively, configure a directory of trusted CA certificates:
+
+```sh
+export SSL_CERT_DIR=/path/to/ca-directory
+```
+
+These environment variables are honored when `trust_env=True`, which is the
+default. To control trust explicitly on a custom client, pass an
+`ssl.SSLContext` through `verify`:
+
+```python
+import ssl
+from openai import OpenAI, DefaultHttpx2Client
+
+ssl_context = ssl.create_default_context(cafile="/path/to/ca-bundle.pem")
+client = OpenAI(http_client=DefaultHttpx2Client(verify=ssl_context))
+```
+
+Use `DefaultAsyncHttpx2Client(verify=ssl_context)` for the equivalent async
+configuration. The SDK's aiohttp transport uses the same HTTPX2 TLS settings.
+
+## If you provide a custom HTTP client
+
+Use HTTPX2 clients and HTTPX2 configuration objects. The SDK provides helpers
+that preserve its recommended timeout, connection-pool, and redirect defaults:
+
+```python
+import httpx2
+from openai import OpenAI, AsyncOpenAI, DefaultHttpx2Client, DefaultAsyncHttpx2Client
+
+proxy_client = OpenAI(http_client=DefaultHttpx2Client(proxy="http://proxy.example.com:8080"))
+
+transport_client = OpenAI(
+ http_client=DefaultHttpx2Client(
+ transport=httpx2.HTTPTransport(local_address="0.0.0.0"),
+ timeout=httpx2.Timeout(30.0, connect=5.0),
+ )
+)
+
+async_client = AsyncOpenAI(http_client=DefaultAsyncHttpx2Client(timeout=httpx2.Timeout(30.0)))
+```
+
+Directly constructed `httpx2.Client` and `httpx2.AsyncClient` instances are
+also supported. When you construct a client directly, its own HTTPX2 defaults
+apply unless you configure them yourself.
+
+The existing `DefaultHttpxClient` and `DefaultAsyncHttpxClient` names continue
+to work, but now construct HTTPX2 clients. Prefer `DefaultHttpx2Client` and
+`DefaultAsyncHttpx2Client` when making the HTTP client family explicit.
+
+Module-level configuration follows the same rule:
+
+```python
+import openai
+
+openai.http_client = openai.DefaultHttpx2Client()
+```
+
+## Timeouts, URLs, transports, and connection settings
+
+Replace HTTPX-specific objects with the corresponding HTTPX2 objects:
+
+| Previous object | HTTPX2 object |
+| --- | --- |
+| `httpx.Client` | `httpx2.Client` |
+| `httpx.AsyncClient` | `httpx2.AsyncClient` |
+| `httpx.Timeout` | `httpx2.Timeout` |
+| `httpx.URL` | `httpx2.URL` |
+| `httpx.Limits` | `httpx2.Limits` |
+| `httpx.HTTPTransport` | `httpx2.HTTPTransport` |
+| `httpx.AsyncHTTPTransport` | `httpx2.AsyncHTTPTransport` |
+| `httpx.MockTransport` | `httpx2.MockTransport` |
+
+For example, a granular SDK timeout becomes:
+
+```python
+import httpx2
+from openai import OpenAI
+
+client = OpenAI(timeout=httpx2.Timeout(60.0, connect=5.0, read=20.0))
+```
+
+Numeric timeout values do not change. Existing string URLs do not change.
+Custom transport subclasses, mounted transports, proxy integrations, and
+connection-pool instrumentation must target HTTPX2's transport interfaces.
+
+## Authentication and event hooks
+
+Authentication handlers and hooks receive HTTPX2 request and response objects.
+Update custom auth classes and annotations accordingly:
+
+```python
+import httpx2
+from openai import OpenAI, DefaultHttpx2Client
+
+
+def log_request(request: httpx2.Request) -> None:
+ print(request.method, request.url)
+
+
+client = OpenAI(http_client=DefaultHttpx2Client(event_hooks={"request": [log_request]}))
+```
+
+If you subclass an HTTP authentication or transport interface, subclass the
+matching `httpx2` class. Third-party instrumentation, tracing middleware, and
+auth integrations must explicitly support HTTPX2.
+
+## Raw responses, streaming, and exceptions
+
+Parsed SDK response models are unchanged. When using a native HTTPX2 client,
+transport-facing objects belong to HTTPX2:
+
+```python
+import httpx2
+from openai import OpenAI
+
+client = OpenAI()
+response = client.models.with_raw_response.list()
+
+assert isinstance(response.http_response, httpx2.Response)
+assert isinstance(response.http_request, httpx2.Request)
+```
+
+With a native client, use `cast_to=httpx2.Response` when requesting an unparsed
+HTTP response. Streaming response wrappers also expose HTTPX2 response objects.
+Application code should usually catch SDK exceptions such as
+`openai.APITimeoutError` and `openai.APIConnectionError`; with a native client,
+an exception's underlying transport cause is an HTTPX2 exception.
+
+These type guarantees apply only to native HTTPX2 clients. An injected legacy
+HTTPX client produces `httpx.Request`, `httpx.Response`, and HTTPX transport
+exceptions instead, even if `cast_to=httpx2.Response` is supplied.
+
+## aiohttp
+
+The supported aiohttp extra uses an HTTPX2-native transport. It does not
+install legacy HTTPX or the external `httpx-aiohttp` adapter:
+
+```sh
+pip install 'openai[aiohttp]'
+```
+
+```python
+from openai import AsyncOpenAI, DefaultAioHttpClient
+
+client = AsyncOpenAI(http_client=DefaultAioHttpClient())
+```
+
+`DefaultAioHttpClient()` is an `httpx2.AsyncClient`. Applications using this
+helper do not need to construct or import the transport directly.
+
+## Request mocking and tests
+
+Mocks must intercept HTTPX2 requests and return HTTPX2 responses. For example:
+
+```python
+import httpx2
+from openai import OpenAI
+
+
+def handler(request: httpx2.Request) -> httpx2.Response:
+ return httpx2.Response(
+ 200,
+ request=request,
+ json={"object": "list", "data": []},
+ )
+
+
+client = OpenAI(http_client=httpx2.Client(transport=httpx2.MockTransport(handler)))
+assert client.models.list().data == []
+```
+
+If your test suite uses RESPX, update to an HTTPX2-compatible RESPX version or
+fork. A RESPX version that patches only legacy HTTPX cannot intercept the SDK's
+default HTTPX2 client. If you cannot migrate that integration immediately, the
+temporary legacy-client escape hatch below lets existing HTTPX-only RESPX
+setups continue to work while you migrate.
+
+## Temporary escape hatch: a legacy HTTPX client
+
+Applications that depend on an HTTPX-only transport, integration, or mocking
+library can explicitly install legacy HTTPX and inject a legacy client:
+
+```sh
+pip install openai httpx
+```
+
+**Legacy HTTPX support is runtime-only.** The SDK's public type annotations
+accept HTTPX2 clients, so passing a legacy client directly fails static type
+checking in mypy, Pyright, and similar tools. Use `cast(Any, ...)` or a
+targeted type-ignore when deliberately choosing this compatibility path:
+
+```python
+from typing import Any, cast
+
+import httpx
+from openai import OpenAI
+
+client = OpenAI(http_client=cast(Any, httpx.Client()))
+```
+
+The asynchronous form requires the same workaround:
+
+```python
+from typing import Any, cast
+
+import httpx
+from openai import AsyncOpenAI
+
+client = AsyncOpenAI(http_client=cast(Any, httpx.AsyncClient()))
+```
+
+Legacy clients preserve the HTTPX request, response, and exception families.
+Request raw responses as `httpx.Response`, using the same type-checking
+workaround for the legacy response class:
+
+```python
+from typing import Any, cast
+
+import httpx
+from openai import OpenAI
+
+client = OpenAI(http_client=cast(Any, httpx.Client()))
+response = client.get("/models", cast_to=cast(Any, httpx.Response))
+
+assert isinstance(response, httpx.Response)
+```
+
+Passing `cast_to=httpx2.Response` does not convert a legacy HTTPX response into
+an HTTPX2 response. Install and maintain the legacy dependency yourself.
+Legacy HTTPX support is provided as a migration aid and may be discontinued.
+
+### Existing legacy aiohttp adapters
+
+If you must retain an existing `httpx-aiohttp` integration, install it
+explicitly and inject its legacy client:
+
+```sh
+pip install openai httpx-aiohttp
+```
+
+```python
+from typing import Any, cast
+
+from httpx_aiohttp import HttpxAiohttpClient
+from openai import AsyncOpenAI
+
+client = AsyncOpenAI(http_client=cast(Any, HttpxAiohttpClient()))
+```
+
+This path is covered by dedicated compatibility tests, including a real
+request through the aiohttp transport, but remains a temporary escape hatch.
+Prefer `openai[aiohttp]` and `DefaultAioHttpClient()` for new code.
diff --git a/pyproject.toml b/pyproject.toml
index aa51d75238..4a38bd11e7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openai"
-version = "2.54.0"
+version = "3.0.0"
description = "The official Python library for the openai API"
dynamic = ["readme"]
license = "Apache-2.0"
@@ -9,10 +9,10 @@ authors = [
]
dependencies = [
- "httpx>=0.23.0, <1",
+ "httpx2>=2.7.0, <3",
"pydantic>=1.9.0, <3",
"typing-extensions>=4.14, <5",
- "anyio>=3.5.0, <5",
+ "anyio>=4.10.0, <5",
"distro>=1.7.0, <2",
"sniffio",
"tqdm > 4",
@@ -44,12 +44,6 @@ Repository = "https://github.com/openai/openai-python"
[project.optional-dependencies]
aiohttp = [
"aiohttp>=3.14.1",
- "httpx_aiohttp>=0.1.9",
-]
-httpx2 = [
- "httpx>=0.25.1, <1",
- "httpx2>=2.7.0, <3",
- "anyio>=4.10.0, <5",
]
realtime = ["websockets >= 13, < 16"]
datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"]
@@ -64,7 +58,6 @@ managed = true
dev-dependencies = [
"pyright==1.1.399",
"mypy==1.17",
- "respx",
"pytest",
"pytest-asyncio",
"jsonschema>=4.23.0",
@@ -177,6 +170,8 @@ exclude = [
".venv",
".nox",
".git",
+ "tests/respx2",
+ "src/openai/_vendor",
# uses inline `uv` script dependencies
# which means it can't be type checked
@@ -205,6 +200,7 @@ show_error_codes = true
# which means it can't be type checked
exclude = [
'src/openai/_files.py',
+ 'src/openai/_vendor/.*',
'_dev/.*.py',
'tests/.*',
'src/openai/_utils/_logs.py',
@@ -252,6 +248,7 @@ ignore_errors = true
ignore_missing_imports = true
[tool.ruff]
+extend-exclude = ["tests/respx2", "src/openai/_vendor"]
line-length = 120
output-format = "grouped"
target-version = "py310"
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 40db36e36c..efb71cd787 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -13,14 +13,12 @@
aiohappyeyeballs==2.7.1
# via aiohttp
aiohttp==3.14.1
- # via httpx-aiohttp
# via openai
aiosignal==1.4.0
# via aiohttp
annotated-types==0.7.0
# via pydantic
anyio==4.12.1
- # via httpx
# via httpx2
# via openai
argcomplete==3.6.3
@@ -44,8 +42,6 @@ backports-asyncio-runner==1.2.0 ; python_full_version < '3.11'
botocore==1.42.97
# via openai
certifi==2026.1.4
- # via httpcore
- # via httpx
# via requests
cffi==2.0.0
# via cryptography
@@ -86,25 +82,15 @@ frozenlist==1.8.0
# via aiosignal
griffe==1.14.0
h11==0.16.0
- # via httpcore
# via httpcore2
-httpcore==1.0.9
- # via httpx
httpcore2==2.7.0
# via httpx2
-httpx==0.28.1
- # via httpx-aiohttp
- # via openai
- # via respx
-httpx-aiohttp==0.1.12
- # via openai
httpx2==2.7.0
# via openai
humanize==4.13.0
# via nox
idna==3.18
# via anyio
- # via httpx
# via httpx2
# via requests
# via trio
@@ -196,7 +182,6 @@ referencing==0.36.2
requests==2.32.5
# via azure-core
# via msal
-respx==0.22.0
rich==14.2.0
# via inline-snapshot
rpds-py==0.27.1
diff --git a/requirements.lock b/requirements.lock
index 7ec347011b..0323bd6066 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -13,14 +13,12 @@
aiohappyeyeballs==2.7.1
# via aiohttp
aiohttp==3.14.1
- # via httpx-aiohttp
# via openai
aiosignal==1.4.0
# via aiohttp
annotated-types==0.7.0
# via pydantic
anyio==4.12.1
- # via httpx
# via httpx2
# via openai
async-timeout==5.0.1 ; python_full_version < '3.11'
@@ -29,9 +27,6 @@ attrs==26.1.0
# via aiohttp
botocore==1.42.97
# via openai
-certifi==2026.1.4
- # via httpcore
- # via httpx
cffi==2.0.0
# via sounddevice
colorama==0.4.6 ; sys_platform == 'win32'
@@ -44,22 +39,13 @@ frozenlist==1.8.0
# via aiohttp
# via aiosignal
h11==0.16.0
- # via httpcore
# via httpcore2
-httpcore==1.0.9
- # via httpx
httpcore2==2.7.0
# via httpx2
-httpx==0.28.1
- # via httpx-aiohttp
- # via openai
-httpx-aiohttp==0.1.12
- # via openai
httpx2==2.7.0
# via openai
idna==3.18
# via anyio
- # via httpx
# via httpx2
# via yarl
jiter==0.12.0
diff --git a/scripts/check-python-version-policy.py b/scripts/check-python-version-policy.py
index 16217267c0..ca74199485 100644
--- a/scripts/check-python-version-policy.py
+++ b/scripts/check-python-version-policy.py
@@ -8,10 +8,8 @@
MINIMUM = SUPPORTED[0]
CURRENT_STABLE = SUPPORTED[-1]
PRERELEASE = "3.15"
-UNMARKED_OPTIONAL_DEPENDENCIES = (
+UNMARKED_DEPENDENCIES = (
"aiohttp>=3.14.1",
- "httpx_aiohttp>=0.1.9",
- "httpx>=0.25.1, <1",
"httpx2>=2.7.0, <3",
"anyio>=4.10.0, <5",
"botocore>=1.40.0,<2",
@@ -124,7 +122,7 @@ def main() -> None:
)
project_metadata = pyproject.split("[tool.rye]", 1)[0]
- for requirement in UNMARKED_OPTIONAL_DEPENDENCIES:
+ for requirement in UNMARKED_DEPENDENCIES:
require(
f'"{requirement}"' in project_metadata,
f"Package metadata does not contain the unmarked requirement {requirement!r}",
diff --git a/scripts/utils/validate-bedrock-wheel.py b/scripts/utils/validate-bedrock-wheel.py
index ea4abdc74e..e0bf4f5890 100644
--- a/scripts/utils/validate-bedrock-wheel.py
+++ b/scripts/utils/validate-bedrock-wheel.py
@@ -14,7 +14,7 @@
import importlib.abc
from pathlib import Path
-import httpx
+import httpx2
class BlockBotocore(importlib.abc.MetaPathFinder):
@@ -39,22 +39,22 @@ def find_spec(self, fullname, path=None, target=None):
def handler(request):
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
-http_client = httpx.Client(transport=httpx.MockTransport(handler), trust_env=False)
+http_client = httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False)
with OpenAI(
provider=bedrock(region="us-east-1", api_key="bearer-token"),
http_client=http_client,
) as client:
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert requests[0].headers["Authorization"] == "Bearer bearer-token"
assert not any(name == "botocore" or name.startswith("botocore.") for name in sys.modules)
sys.meta_path.remove(blocker)
requests.clear()
-http_client = httpx.Client(transport=httpx.MockTransport(handler), trust_env=False)
+http_client = httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False)
with OpenAI(
provider=bedrock(
region="us-east-1",
@@ -64,7 +64,7 @@ def handler(request):
),
http_client=http_client,
) as client:
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert "Credential=fixture-access-key/" in requests[0].headers["Authorization"]
assert requests[0].headers["X-Amz-Security-Token"] == "fixture-session-token"
diff --git a/scripts/utils/validate-httpx2-wheel.py b/scripts/utils/validate-httpx2-wheel.py
index e8b12147c9..8e0642efba 100644
--- a/scripts/utils/validate-httpx2-wheel.py
+++ b/scripts/utils/validate-httpx2-wheel.py
@@ -1,6 +1,7 @@
from __future__ import annotations
import os
+import re
import sys
import email
import zipfile
@@ -11,12 +12,20 @@
ROOT = Path(__file__).resolve().parents[2]
BASE_TEST = ROOT / "tests/test_httpx2_base.py"
HTTPX2_TEST = ROOT / "tests/test_httpx2.py"
+LEGACY_TEST = ROOT / "tests/test_httpx_compat.py"
def venv_python(environment_path: Path) -> Path:
return environment_path / ("Scripts/python.exe" if sys.platform == "win32" else "bin/python")
+def requirement_name(requirement: str) -> str:
+ match = re.match(r"[A-Za-z0-9_.-]+", requirement)
+ if match is None:
+ raise RuntimeError(f"Cannot determine the package name for {requirement!r}")
+ return match.group().replace("_", "-").lower()
+
+
def validate_metadata(wheel: Path) -> None:
with zipfile.ZipFile(wheel) as archive:
metadata_names = [name for name in archive.namelist() if name.endswith(".dist-info/METADATA")]
@@ -24,39 +33,40 @@ def validate_metadata(wheel: Path) -> None:
raise RuntimeError(f"Expected exactly one METADATA file in {wheel}, found: {metadata_names}")
metadata = email.message_from_bytes(archive.read(metadata_names[0]))
+ for name in ("LICENSE", "README.md", "FORK.md"):
+ if f"openai/_vendor/httpx_aiohttp/{name}" not in archive.namelist():
+ raise RuntimeError(f"The wheel omitted the vendored aiohttp adapter's {name}")
+
requirements = metadata.get_all("Requires-Dist", [])
base = [value for value in requirements if "extra ==" not in value]
- httpx2 = [value for value in requirements if "extra == 'httpx2'" in value]
aiohttp = [value for value in requirements if "extra == 'aiohttp'" in value]
+ extras = set(metadata.get_all("Provides-Extra", []))
if metadata["Requires-Python"] != ">=3.10":
raise RuntimeError(f"Expected Python >=3.10, found: {metadata['Requires-Python']}")
- if not any(value.startswith("httpx<1,>=0.23.0") for value in base):
- raise RuntimeError(f"Expected the base wheel to require HTTPX >=0.23.0,<1: {base}")
- if not any(value.startswith("anyio<5,>=3.5.0") for value in base):
- raise RuntimeError(f"Expected the base wheel to require AnyIO >=3.5.0,<5: {base}")
- if any(value.startswith("httpx2") for value in base):
- raise RuntimeError(f"HTTPX2 leaked into the base wheel requirements: {base}")
-
- for expected in ("httpx<1,>=0.25.1", "httpx2<3,>=2.7.0", "anyio<5,>=4.10.0"):
- if not any(value.startswith(expected) for value in httpx2):
- raise RuntimeError(f"Expected the HTTPX2 extra to require {expected}: {httpx2}")
- if any("python_version" in value for value in httpx2):
- raise RuntimeError(f"HTTPX2 requirements have redundant Python markers: {httpx2}")
-
+ for expected in ("httpx2<3,>=2.7.0", "anyio<5,>=4.10.0"):
+ if not any(value.startswith(expected) for value in base):
+ raise RuntimeError(f"Expected the base wheel to require {expected}: {base}")
+ if any(requirement_name(value) == "httpx" for value in requirements):
+ raise RuntimeError(f"Legacy HTTPX must not be installed by any SDK extra: {requirements}")
+ if any(requirement_name(value) == "httpx-aiohttp" for value in requirements):
+ raise RuntimeError(f"The aiohttp extra must not install the legacy adapter package: {requirements}")
+ if {"httpx", "httpx2"} & extras:
+ raise RuntimeError(f"HTTP client selection must not require or expose an SDK extra: {extras}")
if not any(value.startswith("aiohttp>=3.14.1") for value in aiohttp):
- raise RuntimeError(f"Expected the unchanged aiohttp requirement: {aiohttp}")
- if not any(value.startswith("httpx-aiohttp>=0.1.9") for value in aiohttp):
- raise RuntimeError(f"Expected the unchanged httpx-aiohttp requirement: {aiohttp}")
+ raise RuntimeError(f"Expected the aiohttp extra to require a patched aiohttp release: {aiohttp}")
-def run_case(wheel: Path, *, extra: str | None, tests: list[Path], dependencies: list[str]) -> None:
+def run_case(
+ wheel: Path, *, extra: str | None, tests: list[Path], dependencies: list[str], legacy: bool = False
+) -> None:
with tempfile.TemporaryDirectory(prefix="openai-httpx2-wheel-") as directory:
environment_path = Path(directory) / "venv"
subprocess.run([sys.executable, "-m", "venv", str(environment_path)], check=True)
python = venv_python(environment_path)
requirement = str(wheel.resolve()) if extra is None else f"{wheel.resolve()}[{extra}]"
environment = os.environ.copy()
+ environment.pop("PYTHONPATH", None)
environment.setdefault("PIP_DISABLE_CLIENT_CERTIFICATE", "1")
subprocess.run(
[str(python), "-m", "pip", "install", "--quiet", requirement, *dependencies],
@@ -64,9 +74,20 @@ def run_case(wheel: Path, *, extra: str | None, tests: list[Path], dependencies:
env=environment,
check=True,
)
+
+ if not legacy:
+ subprocess.run(
+ [str(python), "-c", "import importlib.util; assert importlib.util.find_spec('httpx') is None"],
+ cwd=directory,
+ env=environment,
+ check=True,
+ )
+
test_environment = environment.copy()
for name in ("ALL_PROXY", "HTTPS_PROXY", "HTTP_PROXY", "all_proxy", "https_proxy", "http_proxy"):
test_environment.pop(name, None)
+ if legacy:
+ test_environment["OPENAI_TEST_LEGACY_HTTPX"] = "1"
subprocess.run(
[str(python), "-m", "pytest", "-o", "addopts=", *(str(test) for test in tests)],
cwd=directory,
@@ -75,34 +96,6 @@ def run_case(wheel: Path, *, extra: str | None, tests: list[Path], dependencies:
)
-def assert_incompatible_pin_fails(wheel: Path) -> None:
- with tempfile.TemporaryDirectory(prefix="openai-httpx2-conflict-") as directory:
- environment_path = Path(directory) / "venv"
- subprocess.run([sys.executable, "-m", "venv", str(environment_path)], check=True)
- python = venv_python(environment_path)
- result = subprocess.run(
- [
- str(python),
- "-m",
- "pip",
- "install",
- "--no-input",
- f"{wheel.resolve()}[httpx2]",
- "httpx==0.25.0",
- ],
- cwd=directory,
- env=os.environ.copy(),
- capture_output=True,
- text=True,
- check=False,
- )
- if result.returncode == 0:
- raise RuntimeError("Expected openai[httpx2] with httpx==0.25.0 to fail dependency resolution")
- output = result.stdout + result.stderr
- if "ResolutionImpossible" not in output and "conflicting dependencies" not in output:
- raise RuntimeError(f"The incompatible resolution failed for an unexpected reason:\n{output}")
-
-
def main() -> None:
wheels = list((ROOT / "dist").glob("*.whl"))
if len(wheels) != 1:
@@ -110,32 +103,17 @@ def main() -> None:
wheel = wheels[0]
validate_metadata(wheel)
- common = ["pytest==8.4.1", "pytest-asyncio==1.1.0", "respx==0.22.0"]
- run_case(wheel, extra=None, tests=[BASE_TEST], dependencies=common)
- if sys.version_info[:2] == (3, 10):
- run_case(
- wheel,
- extra=None,
- tests=[BASE_TEST],
- dependencies=[
- "pytest==8.4.1",
- "pytest-asyncio==1.1.0",
- "respx==0.20.2",
- "httpx==0.23.0",
- "anyio==3.5.0",
- ],
- )
-
+ common = ["pytest==8.4.1", "pytest-asyncio==1.1.0"]
+ run_case(wheel, extra=None, tests=[BASE_TEST, HTTPX2_TEST], dependencies=common)
run_case(wheel, extra="aiohttp", tests=[BASE_TEST], dependencies=common)
- run_case(wheel, extra="httpx2", tests=[BASE_TEST, HTTPX2_TEST], dependencies=common)
run_case(
wheel,
- extra="httpx2",
- tests=[BASE_TEST, HTTPX2_TEST],
- dependencies=[*common, "httpx==0.25.1", "anyio==4.10.0", "pydantic<2", "botocore==1.42.97"],
+ extra=None,
+ tests=[LEGACY_TEST],
+ dependencies=[*common, "httpx-aiohttp>=0.2.0,<0.3"],
+ legacy=True,
)
- assert_incompatible_pin_fails(wheel)
- print("Validated base, aiohttp, native HTTPX2, supported floors, Pydantic modes, and resolver conflicts")
+ print("Validated HTTPX2-only base and aiohttp installs plus isolated legacy HTTPX/aiohttp compatibility")
if __name__ == "__main__":
diff --git a/src/openai/__init__.py b/src/openai/__init__.py
index d433ac4318..5a8621cf4c 100644
--- a/src/openai/__init__.py
+++ b/src/openai/__init__.py
@@ -130,7 +130,7 @@
import typing as _t
import typing_extensions as _te
-import httpx as _httpx
+import httpx2 as _httpx
from ._base_client import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES
diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py
index 10d7b9f7ca..b6e2f2839d 100644
--- a/src/openai/_base_client.py
+++ b/src/openai/_base_client.py
@@ -34,10 +34,10 @@
from typing_extensions import Unpack, Literal, override, get_origin
import anyio
-import httpx
import distro
+import httpx2
import pydantic
-from httpx import URL
+from httpx2 import URL
from pydantic import PrivateAttr
from . import _exceptions
@@ -67,12 +67,17 @@
from ._httpx2 import (
status_exceptions,
timeout_exceptions,
+ http_response_types,
normalize_httpx_url,
is_httpx2_sync_client,
normalize_httpx2_auth,
is_httpx2_async_client,
normalize_httpx_timeout,
normalize_httpx2_timeout,
+ is_legacy_httpx_sync_client,
+ normalize_legacy_httpx_auth,
+ is_legacy_httpx_async_client,
+ normalize_legacy_httpx_timeout,
)
from ._models import GenericModel, SecurityOptions, FinalRequestOptions, validate_type, construct_type
from ._response import (
@@ -117,14 +122,14 @@
_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any])
if TYPE_CHECKING:
- from httpx._config import (
+ from httpx2._config import (
DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage]
)
HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG
else:
try:
- from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT
+ from httpx2._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT
except ImportError:
# taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366
HTTPX_DEFAULT_TIMEOUT = Timeout(5.0)
@@ -207,9 +212,9 @@ def next_page_info(self) -> Optional[PageInfo]: ...
def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body]
...
- def _params_from_url(self, url: URL) -> httpx.QueryParams:
+ def _params_from_url(self, url: URL) -> httpx2.QueryParams:
# TODO: do we have to preprocess params here?
- return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params)
+ return httpx2.QueryParams(cast(Any, self._options.params)).merge(url.params)
def _info_to_options(self, info: PageInfo) -> FinalRequestOptions:
options = model_copy(self._options)
@@ -371,7 +376,7 @@ async def get_next_page(self: AsyncPageT) -> AsyncPageT:
return await self._client._request_api_list(self._model, page=self.__class__, options=options)
-_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient])
+_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx2.Client, httpx2.AsyncClient])
_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])
@@ -418,7 +423,7 @@ def _enforce_trailing_slash(self, url: URL) -> URL:
def _make_status_error_from_response(
self,
- response: httpx.Response,
+ response: httpx2.Response,
) -> APIStatusError:
if response.is_closed and not response.is_stream_consumed:
# We can't read the response body as it has been closed
@@ -443,7 +448,7 @@ def _make_status_error(
err_msg: str,
*,
body: object,
- response: httpx.Response,
+ response: httpx2.Response,
) -> _exceptions.APIStatusError:
raise NotImplementedError()
@@ -462,16 +467,16 @@ def _auth_query(
def _custom_auth(
self,
security: SecurityOptions, # noqa: ARG002
- ) -> httpx.Auth | None:
+ ) -> httpx2.Auth | None:
return None
- def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers:
+ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx2.Headers:
custom_headers = options.headers or {}
headers_dict = _merge_mappings({**self._auth_headers(options.security), **self.default_headers}, custom_headers)
self._validate_headers(headers_dict, custom_headers)
# headers are case-insensitive while dictionaries are not.
- headers = httpx.Headers(headers_dict)
+ headers = httpx2.Headers(headers_dict)
idempotency_header = self._idempotency_header
if idempotency_header and options.idempotency_key and idempotency_header not in headers:
@@ -514,7 +519,7 @@ def _build_request(
options: FinalRequestOptions,
*,
retries_taken: int = 0,
- ) -> httpx.Request:
+ ) -> httpx2.Request:
if log.isEnabledFor(logging.DEBUG):
log.debug(
"Request options: %s",
@@ -604,11 +609,11 @@ def _build_request(
kwargs.pop("data", None)
timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout
- request_url: str | URL = prepared_url
- request_headers: httpx.Headers | list[tuple[str, str]] = headers
- if is_httpx2_sync_client(self._client) or is_httpx2_async_client(self._client):
- request_url = str(prepared_url)
- request_headers = list(headers.multi_items())
+ request_url = str(prepared_url)
+ request_headers = list(headers.multi_items())
+ if is_legacy_httpx_sync_client(self._client) or is_legacy_httpx_async_client(self._client):
+ timeout = normalize_legacy_httpx_timeout(timeout)
+ else:
timeout = normalize_httpx2_timeout(timeout)
# TODO: report this error to httpx
@@ -672,7 +677,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques
return cast_to
- def _should_stream_response_body(self, request: httpx.Request) -> bool:
+ def _should_stream_response_body(self, request: httpx2.Request) -> bool:
return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return]
def _process_response_data(
@@ -680,7 +685,7 @@ def _process_response_data(
*,
data: object,
cast_to: type[ResponseT],
- response: httpx.Response,
+ response: httpx2.Response,
) -> ResponseT:
if data is None:
return cast(ResponseT, None)
@@ -704,7 +709,7 @@ def qs(self) -> Querystring:
return Querystring()
@property
- def custom_auth(self) -> httpx.Auth | None:
+ def custom_auth(self) -> httpx2.Auth | None:
return None
@property
@@ -756,7 +761,7 @@ def platform_headers(self) -> Dict[str, str]:
# https://github.com/python/cpython/issues/88476
return platform_headers(self._version, platform=self._platform)
- def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None:
+ def _parse_retry_after_header(self, response_headers: Optional[httpx2.Headers] = None) -> float | None:
"""Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified.
About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
@@ -798,7 +803,7 @@ def _calculate_retry_timeout(
self,
remaining_retries: int,
options: FinalRequestOptions,
- response_headers: Optional[httpx.Headers] = None,
+ response_headers: Optional[httpx2.Headers] = None,
) -> float:
max_retries = options.get_max_retries(self.max_retries)
@@ -818,7 +823,7 @@ def _calculate_retry_timeout(
timeout = sleep_seconds * jitter
return timeout if timeout >= 0 else 0
- def _should_retry(self, response: httpx.Response) -> bool:
+ def _should_retry(self, response: httpx2.Response) -> bool:
retry_after = self._parse_retry_after_header(response.headers)
if retry_after is not None and math.isfinite(retry_after) and retry_after > MAX_RETRY_AFTER_DELAY:
log.debug(
@@ -866,7 +871,7 @@ def _idempotency_key(self) -> str:
return f"stainless-python-retry-{uuid.uuid4()}"
-class _DefaultHttpxClient(httpx.Client):
+class _DefaultHttpxClient(httpx2.Client):
def __init__(self, **kwargs: Any) -> None:
kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
@@ -875,12 +880,12 @@ def __init__(self, **kwargs: Any) -> None:
if TYPE_CHECKING:
- DefaultHttpxClient = httpx.Client
- """An alias to `httpx.Client` that provides the same defaults that this SDK
+ DefaultHttpxClient = httpx2.Client
+ """An alias to `httpx2.Client` that provides the same defaults that this SDK
uses internally.
This is useful because overriding the `http_client` with your own instance of
- `httpx.Client` will result in httpx's defaults being used, not ours.
+ `httpx2.Client` will result in HTTPX2's defaults being used, not ours.
"""
else:
DefaultHttpxClient = _DefaultHttpxClient
@@ -897,8 +902,8 @@ def __del__(self) -> None:
pass
-class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
- _client: httpx.Client
+class SyncAPIClient(BaseClient[httpx2.Client, Stream[Any]]):
+ _client: httpx2.Client
_default_stream_cls: type[Stream[Any]] | None = None
def __init__(
@@ -908,7 +913,7 @@ def __init__(
base_url: str | URL,
max_retries: int = DEFAULT_MAX_RETRIES,
timeout: float | Timeout | None | NotGiven = not_given,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
custom_headers: Mapping[str, str] | None = None,
custom_query: Mapping[str, object] | None = None,
_strict_response_validation: bool,
@@ -930,7 +935,7 @@ def __init__(
if (
http_client is not None
and not is_httpx2_sync_client(http_client)
- and not isinstance(http_client, httpx.Client) # pyright: ignore[reportUnnecessaryIsInstance]
+ and not is_legacy_httpx_sync_client(http_client)
):
raise TypeError(
"Invalid `http_client` argument; Expected an instance of `httpx.Client` or `httpx2.Client` "
@@ -986,7 +991,7 @@ def _prepare_options(
def _prepare_request(
self,
- request: httpx.Request, # noqa: ARG002
+ request: httpx2.Request, # noqa: ARG002
) -> None:
"""This method is used as a callback for mutating the `Request` object
after it has been constructed.
@@ -997,11 +1002,11 @@ def _prepare_request(
def _send_request(
self,
- request: httpx.Request,
+ request: httpx2.Request,
*,
stream: bool,
**kwargs: Unpack[HttpxSendArgs],
- ) -> httpx.Response:
+ ) -> httpx2.Response:
return self._client.send(request, stream=stream, **kwargs)
@overload
@@ -1051,7 +1056,7 @@ def request(
# ensure the idempotency key is reused between requests
input_options.idempotency_key = self._idempotency_key()
- response: httpx.Response | None = None
+ response: httpx2.Response | None = None
max_retries = input_options.get_max_retries(self.max_retries)
retries_taken = 0
@@ -1067,7 +1072,9 @@ def request(
custom_auth = self._custom_auth(options.security)
if custom_auth is not None:
kwargs["auth"] = (
- normalize_httpx2_auth(custom_auth) if is_httpx2_sync_client(self._client) else custom_auth
+ normalize_httpx2_auth(custom_auth)
+ if is_httpx2_sync_client(self._client)
+ else normalize_legacy_httpx_auth(custom_auth)
)
if options.follow_redirects is not None:
@@ -1160,7 +1167,7 @@ def request(
)
def _sleep_for_retry(
- self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None
+ self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx2.Response | None
) -> None:
remaining_retries = max_retries - retries_taken
if remaining_retries == 1:
@@ -1178,7 +1185,7 @@ def _process_response(
*,
cast_to: Type[ResponseT],
options: FinalRequestOptions,
- response: httpx.Response,
+ response: httpx2.Response,
stream: bool,
stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
retries_taken: int = 0,
@@ -1224,7 +1231,7 @@ def _process_response(
),
)
- if cast_to == httpx.Response:
+ if cast_to in http_response_types():
return cast(ResponseT, response)
api_response = APIResponse(
@@ -1461,7 +1468,7 @@ def get_api_list(
return self._request_api_list(model, page, opts)
-class _DefaultAsyncHttpxClient(httpx.AsyncClient):
+class _DefaultAsyncHttpxClient(httpx2.AsyncClient):
def __init__(self, **kwargs: Any) -> None:
kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
@@ -1469,43 +1476,40 @@ def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
-if sys.version_info < (3, 10):
+_DefaultAioHttpClient: type[httpx2.AsyncClient]
+
+try:
+ from ._vendor.httpx_aiohttp import Httpx2AiohttpClient
+except ImportError:
- class _DefaultAioHttpClient(httpx.AsyncClient):
+ class _MissingAioHttpClient(httpx2.AsyncClient):
def __init__(self, **_kwargs: Any) -> None:
- raise RuntimeError("The aiohttp client requires Python 3.10 or later")
-else:
- try:
- import httpx_aiohttp
- except ImportError:
+ raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
- class _DefaultAioHttpClient(httpx.AsyncClient):
- def __init__(self, **_kwargs: Any) -> None:
- raise RuntimeError(
- "To use the aiohttp client you must have installed the package with the `aiohttp` extra"
- )
- else:
+ _DefaultAioHttpClient = _MissingAioHttpClient
+else:
- class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
- def __init__(self, **kwargs: Any) -> None:
- kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
- kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
- kwargs.setdefault("follow_redirects", True)
+ class _InstalledAioHttpClient(Httpx2AiohttpClient):
+ def __init__(self, **kwargs: Any) -> None:
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
+ kwargs.setdefault("follow_redirects", True)
+ super().__init__(**kwargs)
- super().__init__(**kwargs)
+ _DefaultAioHttpClient = _InstalledAioHttpClient
if TYPE_CHECKING:
- DefaultAsyncHttpxClient = httpx.AsyncClient
- """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
+ DefaultAsyncHttpxClient = httpx2.AsyncClient
+ """An alias to `httpx2.AsyncClient` that provides the same defaults that this SDK
uses internally.
This is useful because overriding the `http_client` with your own instance of
- `httpx.AsyncClient` will result in httpx's defaults being used, not ours.
+ `httpx2.AsyncClient` will result in HTTPX2's defaults being used, not ours.
"""
- DefaultAioHttpClient = httpx.AsyncClient
- """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
+ DefaultAioHttpClient = httpx2.AsyncClient
+ """An alias to `httpx2.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
else:
DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
DefaultAioHttpClient = _DefaultAioHttpClient
@@ -1523,8 +1527,8 @@ def __del__(self) -> None:
pass
-class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
- _client: httpx.AsyncClient
+class AsyncAPIClient(BaseClient[httpx2.AsyncClient, AsyncStream[Any]]):
+ _client: httpx2.AsyncClient
_default_stream_cls: type[AsyncStream[Any]] | None = None
def __init__(
@@ -1535,7 +1539,7 @@ def __init__(
_strict_response_validation: bool,
max_retries: int = DEFAULT_MAX_RETRIES,
timeout: float | Timeout | None | NotGiven = not_given,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
custom_headers: Mapping[str, str] | None = None,
custom_query: Mapping[str, object] | None = None,
) -> None:
@@ -1556,7 +1560,7 @@ def __init__(
if (
http_client is not None
and not is_httpx2_async_client(http_client)
- and not isinstance(http_client, httpx.AsyncClient) # pyright: ignore[reportUnnecessaryIsInstance]
+ and not is_legacy_httpx_async_client(http_client)
):
raise TypeError(
"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` or "
@@ -1609,7 +1613,7 @@ async def _prepare_options(
async def _prepare_request(
self,
- request: httpx.Request, # noqa: ARG002
+ request: httpx2.Request, # noqa: ARG002
) -> None:
"""This method is used as a callback for mutating the `Request` object
after it has been constructed.
@@ -1620,11 +1624,11 @@ async def _prepare_request(
async def _send_request(
self,
- request: httpx.Request,
+ request: httpx2.Request,
*,
stream: bool,
**kwargs: Unpack[HttpxSendArgs],
- ) -> httpx.Response:
+ ) -> httpx2.Response:
return await self._client.send(request, stream=stream, **kwargs)
@overload
@@ -1679,7 +1683,7 @@ async def request(
# ensure the idempotency key is reused between requests
input_options.idempotency_key = self._idempotency_key()
- response: httpx.Response | None = None
+ response: httpx2.Response | None = None
max_retries = input_options.get_max_retries(self.max_retries)
retries_taken = 0
@@ -1696,7 +1700,7 @@ async def request(
kwargs["auth"] = (
normalize_httpx2_auth(self.custom_auth)
if is_httpx2_async_client(self._client)
- else self.custom_auth
+ else normalize_legacy_httpx_auth(self.custom_auth)
)
if options.follow_redirects is not None:
@@ -1789,7 +1793,7 @@ async def request(
)
async def _sleep_for_retry(
- self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None
+ self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx2.Response | None
) -> None:
remaining_retries = max_retries - retries_taken
if remaining_retries == 1:
@@ -1807,7 +1811,7 @@ async def _process_response(
*,
cast_to: Type[ResponseT],
options: FinalRequestOptions,
- response: httpx.Response,
+ response: httpx2.Response,
stream: bool,
stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
retries_taken: int = 0,
@@ -1853,7 +1857,7 @@ async def _process_response(
),
)
- if cast_to == httpx.Response:
+ if cast_to in http_response_types():
return cast(ResponseT, response)
api_response = AsyncAPIResponse(
@@ -2090,7 +2094,7 @@ def make_request_options(
extra_query: Query | None = None,
extra_body: Body | None = None,
idempotency_key: str | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
post_parser: PostParser | NotGiven = not_given,
security: SecurityOptions | None = None,
synthesize_event_and_data: bool | None = None,
diff --git a/src/openai/_client.py b/src/openai/_client.py
index a12a871f18..5f980c8cb6 100644
--- a/src/openai/_client.py
+++ b/src/openai/_client.py
@@ -6,7 +6,7 @@
from typing import TYPE_CHECKING, Any, Mapping, Callable, Awaitable
from typing_extensions import Self, Unpack, override
-import httpx
+import httpx2
from . import _exceptions
from ._qs import Querystring
@@ -117,7 +117,7 @@ class OpenAI(SyncAPIClient):
_provider: _Provider | None
_provider_runtime: _ProviderRuntime | None
- websocket_base_url: str | httpx.URL | None
+ websocket_base_url: str | httpx2.URL | None
"""Base URL for WebSocket connections.
If not specified, the default base URL will be used, with 'wss://' replacing the
@@ -135,16 +135,16 @@ def __init__(
project: str | None = None,
webhook_secret: str | None = None,
provider: _Provider | None = None,
- base_url: str | httpx.URL | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- # Configure a custom httpx client.
+ # Configure a custom httpx2 client.
# We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`.
- # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
- http_client: httpx.Client | None = None,
+ # See the [httpx2 documentation](https://httpx2.pydantic.dev/api/#client) for more details.
+ http_client: httpx2.Client | None = None,
# Enable or disable schema validation for data returned by the API.
# When enabled an error APIResponseValidationError is raised
# if the API responds with invalid data for the expected schema.
@@ -452,12 +452,12 @@ def qs(self) -> Querystring:
def _send_with_auth_retry(
self,
- request: httpx.Request,
+ request: httpx2.Request,
*,
stream: bool,
retried: bool = False,
**kwargs: Unpack[HttpxSendArgs],
- ) -> httpx.Response:
+ ) -> httpx2.Response:
used_workload_identity_auth = False
if self._workload_identity_auth is not None:
@@ -483,11 +483,11 @@ def _send_with_auth_retry(
@override
def _send_request(
self,
- request: httpx.Request,
+ request: httpx2.Request,
*,
stream: bool,
**kwargs: Unpack[HttpxSendArgs],
- ) -> httpx.Response:
+ ) -> httpx2.Response:
response = self._send_with_auth_retry(request, stream=stream, **kwargs)
if self._provider_runtime is not None and self._provider_runtime.normalize_response is not None:
response = self._provider_runtime.normalize_response(response)
@@ -566,14 +566,14 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
return super()._prepare_options(options)
@override
- def _prepare_request(self, request: httpx.Request) -> None:
+ def _prepare_request(self, request: httpx2.Request) -> None:
if self._provider_runtime is not None and self._provider_runtime.prepare_request is not None:
self._provider_runtime.prepare_request(request)
@override
- def _custom_auth(self, security: SecurityOptions) -> httpx.Auth | None:
+ def _custom_auth(self, security: SecurityOptions) -> httpx2.Auth | None:
if self._provider_runtime is not None:
- return httpx.Auth()
+ return httpx2.Auth()
return super()._custom_auth(security)
@@ -593,10 +593,10 @@ def copy(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
- base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
max_retries: int | NotGiven = not_given,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
@@ -682,7 +682,7 @@ def _make_status_error(
err_msg: str,
*,
body: object,
- response: httpx.Response,
+ response: httpx2.Response,
) -> APIStatusError:
data = body.get("error", body) if is_mapping(body) else body
if response.status_code == 400:
@@ -723,7 +723,7 @@ class AsyncOpenAI(AsyncAPIClient):
_provider: _Provider | None
_provider_runtime: _ProviderRuntime | None
- websocket_base_url: str | httpx.URL | None
+ websocket_base_url: str | httpx2.URL | None
"""Base URL for WebSocket connections.
If not specified, the default base URL will be used, with 'wss://' replacing the
@@ -741,16 +741,16 @@ def __init__(
project: str | None = None,
webhook_secret: str | None = None,
provider: _Provider | None = None,
- base_url: str | httpx.URL | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- # Configure a custom httpx client.
+ # Configure a custom httpx2 client.
# We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`.
- # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details.
- http_client: httpx.AsyncClient | None = None,
+ # See the [httpx2 documentation](https://httpx2.pydantic.dev/api/#asyncclient) for more details.
+ http_client: httpx2.AsyncClient | None = None,
# Enable or disable schema validation for data returned by the API.
# When enabled an error APIResponseValidationError is raised
# if the API responds with invalid data for the expected schema.
@@ -1058,12 +1058,12 @@ def qs(self) -> Querystring:
async def _send_with_auth_retry(
self,
- request: httpx.Request,
+ request: httpx2.Request,
*,
stream: bool,
retried: bool = False,
**kwargs: Unpack[HttpxSendArgs],
- ) -> httpx.Response:
+ ) -> httpx2.Response:
used_workload_identity_auth = False
if self._workload_identity_auth is not None:
@@ -1089,11 +1089,11 @@ async def _send_with_auth_retry(
@override
async def _send_request(
self,
- request: httpx.Request,
+ request: httpx2.Request,
*,
stream: bool,
**kwargs: Unpack[HttpxSendArgs],
- ) -> httpx.Response:
+ ) -> httpx2.Response:
response = await self._send_with_auth_retry(request, stream=stream, **kwargs)
if self._provider_runtime is not None:
if self._provider_runtime.normalize_async_response is not None:
@@ -1177,7 +1177,7 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp
return await super()._prepare_options(options)
@override
- async def _prepare_request(self, request: httpx.Request) -> None:
+ async def _prepare_request(self, request: httpx2.Request) -> None:
if self._provider_runtime is None:
return
@@ -1188,9 +1188,9 @@ async def _prepare_request(self, request: httpx.Request) -> None:
@property
@override
- def custom_auth(self) -> httpx.Auth | None:
+ def custom_auth(self) -> httpx2.Auth | None:
if self._provider_runtime is not None:
- return httpx.Auth()
+ return httpx2.Auth()
return super().custom_auth
@@ -1210,10 +1210,10 @@ def copy(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
- base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
max_retries: int | NotGiven = not_given,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
@@ -1298,7 +1298,7 @@ def _make_status_error(
err_msg: str,
*,
body: object,
- response: httpx.Response,
+ response: httpx2.Response,
) -> APIStatusError:
data = body.get("error", body) if is_mapping(body) else body
if response.status_code == 400:
diff --git a/src/openai/_constants.py b/src/openai/_constants.py
index fd73c6485d..fa137439f1 100644
--- a/src/openai/_constants.py
+++ b/src/openai/_constants.py
@@ -1,14 +1,14 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import httpx
+import httpx2
RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response"
OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to"
# default timeout is 10 minutes
-DEFAULT_TIMEOUT = httpx.Timeout(timeout=600, connect=5.0)
+DEFAULT_TIMEOUT = httpx2.Timeout(timeout=600, connect=5.0)
DEFAULT_MAX_RETRIES = 2
-DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=1000, max_keepalive_connections=100)
+DEFAULT_CONNECTION_LIMITS = httpx2.Limits(max_connections=1000, max_keepalive_connections=100)
INITIAL_RETRY_DELAY = 0.5
MAX_RETRY_DELAY = 8.0
diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py
index 86f44b0e15..b7be6a07e0 100644
--- a/src/openai/_exceptions.py
+++ b/src/openai/_exceptions.py
@@ -5,7 +5,7 @@
from typing import TYPE_CHECKING, Any, Optional, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from ._utils import is_dict
from ._models import construct_type
@@ -38,16 +38,16 @@ class OpenAIError(Exception):
class SubjectTokenProviderError(OpenAIError):
- response: httpx.Response | None
+ response: httpx2.Response | None
- def __init__(self, message: str, *, response: httpx.Response | None = None) -> None:
+ def __init__(self, message: str, *, response: httpx2.Response | None = None) -> None:
super().__init__(message)
self.response = response
class APIError(OpenAIError):
message: str
- request: httpx.Request
+ request: httpx2.Request
body: object | None
"""The API response body.
@@ -64,7 +64,7 @@ class APIError(OpenAIError):
param: Optional[str] = None
type: Optional[str]
- def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None:
+ def __init__(self, message: str, request: httpx2.Request, *, body: object | None) -> None:
super().__init__(message)
self.request = request
self.message = message
@@ -81,10 +81,10 @@ def __init__(self, message: str, request: httpx.Request, *, body: object | None)
class APIResponseValidationError(APIError):
- response: httpx.Response
+ response: httpx2.Response
status_code: int
- def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None:
+ def __init__(self, response: httpx2.Response, body: object | None, *, message: str | None = None) -> None:
super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body)
self.response = response
self.status_code = response.status_code
@@ -93,11 +93,11 @@ def __init__(self, response: httpx.Response, body: object | None, *, message: st
class APIStatusError(APIError):
"""Raised when an API response has a status code of 4xx or 5xx."""
- response: httpx.Response
+ response: httpx2.Response
status_code: int
request_id: str | None
- def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None:
+ def __init__(self, message: str, *, response: httpx2.Response, body: object | None) -> None:
super().__init__(message, response.request, body=body)
self.response = response
self.status_code = response.status_code
@@ -105,12 +105,12 @@ def __init__(self, message: str, *, response: httpx.Response, body: object | Non
class APIConnectionError(APIError):
- def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None:
+ def __init__(self, *, message: str = "Connection error.", request: httpx2.Request) -> None:
super().__init__(message, request, body=None)
class APITimeoutError(APIConnectionError):
- def __init__(self, request: httpx.Request) -> None:
+ def __init__(self, request: httpx2.Request) -> None:
super().__init__(message="Request timed out.", request=request)
@@ -125,7 +125,7 @@ class AuthenticationError(APIStatusError):
class OAuthError(AuthenticationError):
error: Optional[OAuthErrorCode]
- def __init__(self, *, response: httpx.Response, body: object | None) -> None:
+ def __init__(self, *, response: httpx2.Response, body: object | None) -> None:
message = "OAuth authentication error."
error = None
diff --git a/src/openai/_httpx2.py b/src/openai/_httpx2.py
index 7dd3d8d6d9..491398b43c 100644
--- a/src/openai/_httpx2.py
+++ b/src/openai/_httpx2.py
@@ -1,151 +1,141 @@
from __future__ import annotations
import sys
-import importlib
from typing import Any, Protocol, cast
-import httpx
+import httpx2
from ._constants import DEFAULT_TIMEOUT, DEFAULT_CONNECTION_LIMITS
-class _Httpx2Module(Protocol):
- Auth: type[httpx.Auth]
- Client: type[httpx.Client]
- AsyncClient: type[httpx.AsyncClient]
- URL: type[httpx.URL]
- Response: type[httpx.Response]
- Timeout: type[httpx.Timeout]
- Limits: type[httpx.Limits]
- TimeoutException: type[httpx.TimeoutException]
- HTTPStatusError: type[httpx.HTTPStatusError]
- StreamConsumed: type[httpx.StreamConsumed]
- RequestNotRead: type[httpx.RequestNotRead]
+class _LegacyHttpxModule(Protocol):
+ Auth: type[httpx2.Auth]
+ Client: type[httpx2.Client]
+ AsyncClient: type[httpx2.AsyncClient]
+ URL: type[httpx2.URL]
+ Response: type[httpx2.Response]
+ Timeout: type[httpx2.Timeout]
+ Limits: type[httpx2.Limits]
+ TimeoutException: type[httpx2.TimeoutException]
+ HTTPStatusError: type[httpx2.HTTPStatusError]
+ StreamConsumed: type[httpx2.StreamConsumed]
+ RequestNotRead: type[httpx2.RequestNotRead]
-def _loaded_httpx2() -> _Httpx2Module | None:
- module = sys.modules.get("httpx2")
- if module is None:
- return None
- return cast(_Httpx2Module, module)
+def _loaded_legacy_httpx() -> _LegacyHttpxModule | None:
+ module = sys.modules.get("httpx")
+ return cast(_LegacyHttpxModule, module) if module is not None else None
-def _supports_httpx2() -> bool:
- return sys.version_info >= (3, 10)
-
-
-def _require_httpx2() -> _Httpx2Module:
- if not _supports_httpx2():
- raise RuntimeError(
- "HTTPX2 requires Python 3.10 or later; install the httpx2 extra on a supported interpreter: "
- "pip install 'openai[httpx2]'"
- )
+def is_httpx2_sync_client(value: object) -> bool:
+ return isinstance(value, httpx2.Client)
- try:
- module = importlib.import_module("httpx2")
- except ImportError:
- raise RuntimeError("To use HTTPX2, install the httpx2 extra: pip install 'openai[httpx2]'") from None
- return cast(_Httpx2Module, module)
+def is_httpx2_async_client(value: object) -> bool:
+ return isinstance(value, httpx2.AsyncClient)
-def is_httpx2_sync_client(value: object) -> bool:
- module = _loaded_httpx2()
+def is_legacy_httpx_sync_client(value: object) -> bool:
+ module = _loaded_legacy_httpx()
return module is not None and isinstance(value, module.Client)
-def is_httpx2_async_client(value: object) -> bool:
- module = _loaded_httpx2()
+def is_legacy_httpx_async_client(value: object) -> bool:
+ module = _loaded_legacy_httpx()
return module is not None and isinstance(value, module.AsyncClient)
-def normalize_httpx_url(value: str | httpx.URL) -> httpx.URL:
- module = _loaded_httpx2()
- if module is not None and isinstance(value, module.URL):
- return httpx.URL(str(value))
- if isinstance(value, httpx.URL):
+def normalize_httpx_url(value: str | httpx2.URL) -> httpx2.URL:
+ if isinstance(value, httpx2.URL):
return value
- return httpx.URL(value)
+ module = _loaded_legacy_httpx()
+ legacy_value: object = value
+ if module is not None and isinstance(legacy_value, module.URL):
+ return httpx2.URL(str(legacy_value))
+
+ return httpx2.URL(value)
-def http_response_types() -> tuple[type[httpx.Response], ...]:
- module = _loaded_httpx2()
- if module is None:
- return (httpx.Response,)
- return (httpx.Response, module.Response)
+def http_response_types() -> tuple[type[httpx2.Response], ...]:
+ module = _loaded_legacy_httpx()
+ return (httpx2.Response,) if module is None else (httpx2.Response, module.Response)
-def normalize_httpx_timeout(value: float | httpx.Timeout | None) -> float | httpx.Timeout | None:
- module = _loaded_httpx2()
+
+def normalize_httpx_timeout(value: float | httpx2.Timeout | None) -> float | httpx2.Timeout | None:
+ module = _loaded_legacy_httpx()
if module is not None and isinstance(value, module.Timeout):
- return httpx.Timeout(**value.as_dict())
+ return httpx2.Timeout(**value.as_dict())
return value
-def normalize_httpx2_timeout(value: float | httpx.Timeout | None) -> float | httpx.Timeout | None:
- if isinstance(value, httpx.Timeout):
- return _require_httpx2().Timeout(**value.as_dict())
+def normalize_httpx2_timeout(value: float | httpx2.Timeout | None) -> float | httpx2.Timeout | None:
+ return normalize_httpx_timeout(value)
+
+
+def normalize_legacy_httpx_timeout(value: float | httpx2.Timeout | None) -> float | httpx2.Timeout | None:
+ module = _loaded_legacy_httpx()
+ if module is not None and isinstance(value, httpx2.Timeout):
+ return module.Timeout(**value.as_dict())
return value
-def normalize_httpx2_auth(value: httpx.Auth) -> httpx.Auth:
- if type(value) is httpx.Auth:
- return _require_httpx2().Auth()
+def normalize_httpx2_auth(value: httpx2.Auth) -> httpx2.Auth:
+ module = _loaded_legacy_httpx()
+ if module is not None and type(value) is module.Auth:
+ return httpx2.Auth()
return value
-def timeout_exceptions() -> tuple[type[httpx.TimeoutException], ...]:
- module = _loaded_httpx2()
- if module is None:
- return (httpx.TimeoutException,)
- return (httpx.TimeoutException, module.TimeoutException)
+def normalize_legacy_httpx_auth(value: httpx2.Auth) -> httpx2.Auth:
+ module = _loaded_legacy_httpx()
+ if module is not None and type(value) is httpx2.Auth:
+ return module.Auth()
+ return value
-def status_exceptions() -> tuple[type[httpx.HTTPStatusError], ...]:
- module = _loaded_httpx2()
- if module is None:
- return (httpx.HTTPStatusError,)
- return (httpx.HTTPStatusError, module.HTTPStatusError)
+def timeout_exceptions() -> tuple[type[httpx2.TimeoutException], ...]:
+ module = _loaded_legacy_httpx()
+ return (httpx2.TimeoutException,) if module is None else (httpx2.TimeoutException, module.TimeoutException)
-def stream_consumed_exceptions() -> tuple[type[httpx.StreamConsumed], ...]:
- module = _loaded_httpx2()
- if module is None:
- return (httpx.StreamConsumed,)
- return (httpx.StreamConsumed, module.StreamConsumed)
+def status_exceptions() -> tuple[type[httpx2.HTTPStatusError], ...]:
+ module = _loaded_legacy_httpx()
+ return (httpx2.HTTPStatusError,) if module is None else (httpx2.HTTPStatusError, module.HTTPStatusError)
-def request_not_read_exceptions() -> tuple[type[httpx.RequestNotRead], ...]:
- module = _loaded_httpx2()
- if module is None:
- return (httpx.RequestNotRead,)
- return (httpx.RequestNotRead, module.RequestNotRead)
+def stream_consumed_exceptions() -> tuple[type[httpx2.StreamConsumed], ...]:
+ module = _loaded_legacy_httpx()
+ return (httpx2.StreamConsumed,) if module is None else (httpx2.StreamConsumed, module.StreamConsumed)
-def _set_httpx2_defaults(kwargs: dict[str, Any]) -> _Httpx2Module:
- module = _require_httpx2()
- timeout = kwargs.get("timeout", DEFAULT_TIMEOUT)
- kwargs["timeout"] = normalize_httpx2_timeout(timeout)
+def request_not_read_exceptions() -> tuple[type[httpx2.RequestNotRead], ...]:
+ module = _loaded_legacy_httpx()
+ return (httpx2.RequestNotRead,) if module is None else (httpx2.RequestNotRead, module.RequestNotRead)
+
+
+def _set_httpx2_defaults(kwargs: dict[str, Any]) -> None:
+ kwargs["timeout"] = normalize_httpx2_timeout(kwargs.get("timeout", DEFAULT_TIMEOUT))
limits = kwargs.get("limits", DEFAULT_CONNECTION_LIMITS)
- if isinstance(limits, httpx.Limits):
- kwargs["limits"] = module.Limits(
+ module = _loaded_legacy_httpx()
+ if module is not None and isinstance(limits, module.Limits):
+ limits = httpx2.Limits(
max_connections=limits.max_connections,
max_keepalive_connections=limits.max_keepalive_connections,
keepalive_expiry=limits.keepalive_expiry,
)
-
+ kwargs["limits"] = limits
kwargs.setdefault("follow_redirects", True)
- return module
-def DefaultHttpx2Client(**kwargs: Any) -> httpx.Client:
- """Create an experimental HTTPX2 client with the SDK's recommended defaults."""
- module = _set_httpx2_defaults(kwargs)
- return module.Client(**kwargs)
+def DefaultHttpx2Client(**kwargs: Any) -> httpx2.Client:
+ """Create an HTTPX2 client with the SDK's recommended defaults."""
+ _set_httpx2_defaults(kwargs)
+ return httpx2.Client(**kwargs)
-def DefaultAsyncHttpx2Client(**kwargs: Any) -> httpx.AsyncClient:
- """Create an experimental async HTTPX2 client with the SDK's recommended defaults."""
- module = _set_httpx2_defaults(kwargs)
- return module.AsyncClient(**kwargs)
+def DefaultAsyncHttpx2Client(**kwargs: Any) -> httpx2.AsyncClient:
+ """Create an async HTTPX2 client with the SDK's recommended defaults."""
+ _set_httpx2_defaults(kwargs)
+ return httpx2.AsyncClient(**kwargs)
diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py
index 542bd6c660..04a927c430 100644
--- a/src/openai/_legacy_response.py
+++ b/src/openai/_legacy_response.py
@@ -20,7 +20,7 @@
from typing_extensions import Awaitable, ParamSpec, override, deprecated, get_origin
import anyio
-import httpx
+import httpx2
import pydantic
from ._types import NoneType
@@ -63,7 +63,7 @@ class LegacyAPIResponse(Generic[R]):
_stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None
_options: FinalRequestOptions
- http_response: httpx.Response
+ http_response: httpx2.Response
retries_taken: int
"""The number of retries made. If no retries happened this will be `0`"""
@@ -71,7 +71,7 @@ class LegacyAPIResponse(Generic[R]):
def __init__(
self,
*,
- raw: httpx.Response,
+ raw: httpx2.Response,
cast_to: type[R],
client: BaseClient[Any, Any],
stream: bool,
@@ -128,7 +128,7 @@ class MyModel(BaseModel):
- `str`
- `int`
- `float`
- - `httpx.Response`
+ - `httpx2.Response`
"""
cache_key = to if to is not None else self._cast_to
cached = self._parsed_by_type.get(cache_key)
@@ -146,11 +146,11 @@ class MyModel(BaseModel):
return cast(R, parsed)
@property
- def headers(self) -> httpx.Headers:
+ def headers(self) -> httpx2.Headers:
return self.http_response.headers
@property
- def http_request(self) -> httpx.Request:
+ def http_request(self) -> httpx2.Request:
return self.http_response.request
@property
@@ -158,7 +158,7 @@ def status_code(self) -> int:
return self.http_response.status_code
@property
- def url(self) -> httpx.URL:
+ def url(self) -> httpx2.URL:
return self.http_response.url
@property
@@ -303,7 +303,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
and not issubclass(origin, BaseModel)
):
raise RuntimeError(
- f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}."
+ f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx2.Response}."
)
# split is required to handle cases where additional information is included
@@ -389,9 +389,9 @@ async def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]:
class HttpxBinaryResponseContent:
- response: httpx.Response
+ response: httpx2.Response
- def __init__(self, response: httpx.Response) -> None:
+ def __init__(self, response: httpx2.Response) -> None:
self.response = response
@property
diff --git a/src/openai/_provider.py b/src/openai/_provider.py
index 2874d11ff3..8a6c83e502 100644
--- a/src/openai/_provider.py
+++ b/src/openai/_provider.py
@@ -4,7 +4,7 @@
from weakref import WeakKeyDictionary
from dataclasses import dataclass
-import httpx
+import httpx2
from ._models import FinalRequestOptions
from ._exceptions import OpenAIError
@@ -19,13 +19,13 @@ class _Provider:
@dataclass
class _ProviderRuntime:
name: str
- base_url: str | httpx.URL
+ base_url: str | httpx2.URL
transform_request: Callable[[FinalRequestOptions], FinalRequestOptions] | None = None
transform_async_request: Callable[[FinalRequestOptions], Awaitable[FinalRequestOptions]] | None = None
- prepare_request: Callable[[httpx.Request], None] | None = None
- prepare_async_request: Callable[[httpx.Request], Awaitable[None]] | None = None
- normalize_response: Callable[[httpx.Response], httpx.Response] | None = None
- normalize_async_response: Callable[[httpx.Response], Awaitable[httpx.Response]] | None = None
+ prepare_request: Callable[[httpx2.Request], None] | None = None
+ prepare_async_request: Callable[[httpx2.Request], Awaitable[None]] | None = None
+ normalize_response: Callable[[httpx2.Response], httpx2.Response] | None = None
+ normalize_async_response: Callable[[httpx2.Response], Awaitable[httpx2.Response]] | None = None
class _ProviderDefinition(Protocol):
diff --git a/src/openai/_response.py b/src/openai/_response.py
index 5a790d69a2..373b7bc9f4 100644
--- a/src/openai/_response.py
+++ b/src/openai/_response.py
@@ -21,7 +21,7 @@
from typing_extensions import Awaitable, ParamSpec, override, get_origin
import anyio
-import httpx
+import httpx2
import pydantic
from ._types import NoneType
@@ -54,7 +54,7 @@ class BaseAPIResponse(Generic[R]):
_stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None
_options: FinalRequestOptions
- http_response: httpx.Response
+ http_response: httpx2.Response
retries_taken: int
"""The number of retries made. If no retries happened this will be `0`"""
@@ -62,7 +62,7 @@ class BaseAPIResponse(Generic[R]):
def __init__(
self,
*,
- raw: httpx.Response,
+ raw: httpx2.Response,
cast_to: type[R],
client: BaseClient[Any, Any],
stream: bool,
@@ -80,12 +80,12 @@ def __init__(
self.retries_taken = retries_taken
@property
- def headers(self) -> httpx.Headers:
+ def headers(self) -> httpx2.Headers:
return self.http_response.headers
@property
- def http_request(self) -> httpx.Request:
- """Returns the httpx Request instance associated with the current response."""
+ def http_request(self) -> httpx2.Request:
+ """Returns the HTTPX2 Request instance associated with the current response."""
return self.http_response.request
@property
@@ -93,7 +93,7 @@ def status_code(self) -> int:
return self.http_response.status_code
@property
- def url(self) -> httpx.URL:
+ def url(self) -> httpx2.URL:
"""Returns the URL for which the request was made."""
return self.http_response.url
@@ -236,7 +236,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
and not issubclass(origin, BaseModel)
):
raise RuntimeError(
- f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}."
+ f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx2.Response}."
)
# split is required to handle cases where additional information is included
@@ -315,7 +315,7 @@ class MyModel(BaseModel):
- `str`
- `int`
- `float`
- - `httpx.Response`
+ - `httpx2.Response`
"""
cache_key = to if to is not None else self._cast_to
cached = self._parsed_by_type.get(cache_key)
@@ -422,7 +422,7 @@ class MyModel(BaseModel):
- `list`
- `Union`
- `str`
- - `httpx.Response`
+ - `httpx2.Response`
"""
cache_key = to if to is not None else self._cast_to
cached = self._parsed_by_type.get(cache_key)
diff --git a/src/openai/_streaming.py b/src/openai/_streaming.py
index 45c13cc11d..61ed058bd1 100644
--- a/src/openai/_streaming.py
+++ b/src/openai/_streaming.py
@@ -7,7 +7,7 @@
from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast
from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable
-import httpx
+import httpx2
from ._utils import is_mapping, extract_type_var_from_base
from ._exceptions import APIError
@@ -23,7 +23,7 @@
class Stream(Generic[_T]):
"""Provides the core interface to iterate over a synchronous stream response."""
- response: httpx.Response
+ response: httpx2.Response
_options: Optional[FinalRequestOptions] = None
_decoder: SSEBytesDecoder
@@ -31,7 +31,7 @@ def __init__(
self,
*,
cast_to: type[_T],
- response: httpx.Response,
+ response: httpx2.Response,
client: OpenAI,
options: Optional[FinalRequestOptions] = None,
) -> None:
@@ -132,7 +132,7 @@ def close(self) -> None:
class AsyncStream(Generic[_T]):
"""Provides the core interface to iterate over an asynchronous stream response."""
- response: httpx.Response
+ response: httpx2.Response
_options: Optional[FinalRequestOptions] = None
_decoder: SSEDecoder | SSEBytesDecoder
@@ -140,7 +140,7 @@ def __init__(
self,
*,
cast_to: type[_T],
- response: httpx.Response,
+ response: httpx2.Response,
client: AsyncOpenAI,
options: Optional[FinalRequestOptions] = None,
) -> None:
diff --git a/src/openai/_types.py b/src/openai/_types.py
index 9936b00f73..d49aab29d5 100644
--- a/src/openai/_types.py
+++ b/src/openai/_types.py
@@ -31,9 +31,9 @@
runtime_checkable,
)
-import httpx
+import httpx2
import pydantic
-from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport
+from httpx2 import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport
if TYPE_CHECKING:
from ._models import BaseModel, SecurityOptions
@@ -251,7 +251,7 @@ class _GenericAlias(Protocol):
class HttpxSendArgs(TypedDict, total=False):
- auth: httpx.Auth
+ auth: httpx2.Auth
follow_redirects: bool
diff --git a/src/openai/_utils/_logs.py b/src/openai/_utils/_logs.py
index eaffa5ec7a..a997609314 100644
--- a/src/openai/_utils/_logs.py
+++ b/src/openai/_utils/_logs.py
@@ -5,7 +5,7 @@
from ._utils import is_dict
logger: logging.Logger = logging.getLogger("openai")
-httpx_logger: logging.Logger = logging.getLogger("httpx")
+httpx2_logger: logging.Logger = logging.getLogger("httpx2")
SENSITIVE_HEADERS = {"api-key", "authorization", "x-amz-security-token"}
@@ -24,11 +24,11 @@ def setup_logging() -> None:
if env == "debug":
_basic_config()
logger.setLevel(logging.DEBUG)
- httpx_logger.setLevel(logging.DEBUG)
+ httpx2_logger.setLevel(logging.DEBUG)
elif env == "info":
_basic_config()
logger.setLevel(logging.INFO)
- httpx_logger.setLevel(logging.INFO)
+ httpx2_logger.setLevel(logging.INFO)
class SensitiveHeadersFilter(logging.Filter):
diff --git a/src/openai/_vendor/__init__.py b/src/openai/_vendor/__init__.py
new file mode 100644
index 0000000000..16d93a5f02
--- /dev/null
+++ b/src/openai/_vendor/__init__.py
@@ -0,0 +1 @@
+"""Small attributed third-party components required by optional SDK integrations."""
diff --git a/src/openai/_vendor/httpx_aiohttp/FORK.md b/src/openai/_vendor/httpx_aiohttp/FORK.md
new file mode 100644
index 0000000000..d66699bce0
--- /dev/null
+++ b/src/openai/_vendor/httpx_aiohttp/FORK.md
@@ -0,0 +1,13 @@
+# HTTPX2-native aiohttp adapter
+
+This directory vendors the HTTPX2-specific adapter from httpx-aiohttp 0.2.0.
+
+- Upstream: https://github.com/karpetrosyan/httpx-aiohttp
+- Upstream tag: `0.2.0`
+- Upstream commit: `52266a66f6bd73f828133d0fd09114179fd45b60`
+- License: BSD 3-Clause; the original license is preserved in `LICENSE`.
+- The upstream README is preserved without modification in `README.md`.
+
+The upstream distribution always installs and imports legacy HTTPX even when only its HTTPX2 adapter is used. Vendoring the three HTTPX2-specific modules lets `openai[aiohttp]` depend only on HTTPX2 and aiohttp while preserving the upstream transport behavior. No functional changes have been made to the upstream adapter.
+
+The fork may be removed when upstream provides an HTTPX2-only distribution or makes legacy HTTPX genuinely optional.
diff --git a/src/openai/_vendor/httpx_aiohttp/LICENSE b/src/openai/_vendor/httpx_aiohttp/LICENSE
new file mode 100644
index 0000000000..f12539fab7
--- /dev/null
+++ b/src/openai/_vendor/httpx_aiohttp/LICENSE
@@ -0,0 +1,27 @@
+Copyright © 2025, Karen Petrosyan.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/openai/_vendor/httpx_aiohttp/README.md b/src/openai/_vendor/httpx_aiohttp/README.md
new file mode 100644
index 0000000000..938283c9f9
--- /dev/null
+++ b/src/openai/_vendor/httpx_aiohttp/README.md
@@ -0,0 +1,25 @@
+
+
httpx-aiohttp - provides transports for httpx to work on top of aiohttp, handling all high-level features like authentication, retries, and cookies through httpx, while delegating low-level socket-level HTTP messaging to aiohttp
+
+
+
+
+
+
+
+
+## Installation
+
+```shell
+uv pip install httpx-aiohttp
+```
+
+For [httpx2](https://github.com/pydantic/httpx2) support, install the `httpx2` extra and use `httpx_aiohttp.httpx2.Httpx2AiohttpClient` / `httpx_aiohttp.httpx2.AiohttpTransport`:
+
+```shell
+uv pip install httpx-aiohttp[httpx2]
+```
+
+## Documentation
+
+Project documentation is available at https://karpetrosyan.github.io/httpx-aiohttp/
diff --git a/src/openai/_vendor/httpx_aiohttp/__init__.py b/src/openai/_vendor/httpx_aiohttp/__init__.py
new file mode 100644
index 0000000000..3029b3b72c
--- /dev/null
+++ b/src/openai/_vendor/httpx_aiohttp/__init__.py
@@ -0,0 +1,9 @@
+"""Variant of httpx_aiohttp for `httpx2 `_.
+
+Requires the optional ``httpx2`` dependency: ``pip install httpx-aiohttp[httpx2]``.
+"""
+
+from .client import Httpx2AiohttpClient
+from .transport import AiohttpTransport
+
+__all__ = ["AiohttpTransport", "Httpx2AiohttpClient"]
diff --git a/src/openai/_vendor/httpx_aiohttp/client.py b/src/openai/_vendor/httpx_aiohttp/client.py
new file mode 100644
index 0000000000..1187fcb1da
--- /dev/null
+++ b/src/openai/_vendor/httpx_aiohttp/client.py
@@ -0,0 +1,62 @@
+from __future__ import annotations
+
+import ssl
+import typing as t
+
+import httpx2 as httpx
+
+SOCKET_OPTION = t.Union[
+ t.Tuple[int, int, int],
+ t.Tuple[int, int, t.Union[bytes, bytearray]],
+ t.Tuple[int, int, None, int],
+]
+
+
+class Httpx2AiohttpClient(httpx.AsyncClient):
+ def _init_transport(
+ self,
+ verify: ssl.SSLContext | str | bool = True,
+ cert: t.Union[str, t.Tuple[str, str], t.Tuple[str, str, str], None] = None,
+ trust_env: bool = True,
+ http1: bool = True,
+ http2: bool = False,
+ limits: httpx.Limits = httpx.Limits(max_connections=100, max_keepalive_connections=20),
+ transport: httpx.AsyncBaseTransport | None = None,
+ **kwargs: t.Any,
+ ) -> httpx.AsyncBaseTransport:
+ from .transport import AiohttpTransport
+
+ if transport is not None:
+ return transport
+
+ return AiohttpTransport(
+ verify=verify,
+ cert=cert,
+ trust_env=trust_env,
+ http1=http1,
+ http2=http2,
+ limits=limits,
+ )
+
+ def _init_proxy_transport(
+ self,
+ proxy: httpx.Proxy,
+ verify: ssl.SSLContext | str | bool = True,
+ cert: t.Union[str, t.Tuple[str, str], t.Tuple[str, str, str], None] = None,
+ trust_env: bool = True,
+ http1: bool = True,
+ http2: bool = False,
+ limits: httpx.Limits = httpx.Limits(max_connections=100, max_keepalive_connections=20),
+ **kwargs: t.Any,
+ ) -> httpx.AsyncBaseTransport:
+ from .transport import AiohttpTransport
+
+ return AiohttpTransport(
+ verify=verify,
+ cert=cert,
+ trust_env=trust_env,
+ http1=http1,
+ http2=http2,
+ limits=limits,
+ proxy=proxy,
+ )
diff --git a/src/openai/_vendor/httpx_aiohttp/transport.py b/src/openai/_vendor/httpx_aiohttp/transport.py
new file mode 100644
index 0000000000..263bfe106d
--- /dev/null
+++ b/src/openai/_vendor/httpx_aiohttp/transport.py
@@ -0,0 +1,201 @@
+from __future__ import annotations
+
+import contextlib
+import ssl
+import typing
+import typing as t
+from importlib import metadata
+from logging import warning
+
+import aiohttp
+import httpx2 as httpx
+from aiohttp import BasicAuth, ClientTimeout
+from aiohttp.client import ClientResponse, ClientSession
+
+AIOHTTP_EXC_MAP = {
+ aiohttp.ServerTimeoutError: httpx.TimeoutException,
+ aiohttp.SocketTimeoutError: httpx.ReadTimeout,
+ aiohttp.ClientConnectionError: httpx.ConnectTimeout,
+ aiohttp.ClientConnectorError: httpx.ConnectError,
+ aiohttp.ClientPayloadError: httpx.ReadError,
+ aiohttp.ClientProxyConnectionError: httpx.ProxyError,
+ aiohttp.ClientHttpProxyError: httpx.ProxyError,
+}
+
+if metadata.version("aiohttp") >= "3.10.0":
+ AIOHTTP_EXC_MAP.update(
+ {
+ aiohttp.client_exceptions.NonHttpUrlClientError: httpx.UnsupportedProtocol, # type: ignore[reportAttributeAccessIssue]
+ aiohttp.client_exceptions.InvalidUrlClientError: httpx.UnsupportedProtocol, # type: ignore[reportAttributeAccessIssue]
+ }
+ )
+
+SOCKET_OPTION = t.Union[
+ t.Tuple[int, int, int],
+ t.Tuple[int, int, t.Union[bytes, bytearray]],
+ t.Tuple[int, int, None, int],
+]
+
+
+@contextlib.contextmanager
+def map_aiohttp_exceptions() -> typing.Iterator[None]:
+ try:
+ yield
+ except Exception as exc:
+ mapped_exc = None
+
+ for from_exc, to_exc in AIOHTTP_EXC_MAP.items():
+ if not isinstance(exc, from_exc): # type: ignore
+ continue
+ if mapped_exc is None or issubclass(to_exc, mapped_exc):
+ mapped_exc = to_exc
+
+ if mapped_exc is None: # pragma: no cover
+ raise
+
+ message = str(exc)
+ raise mapped_exc(message) from exc
+
+
+class AiohttpResponseStream(httpx.AsyncByteStream):
+ CHUNK_SIZE = 1024 * 16
+
+ def __init__(self, aiohttp_response: ClientResponse) -> None:
+ self._aiohttp_response = aiohttp_response
+
+ async def __aiter__(self) -> typing.AsyncIterator[bytes]:
+ with map_aiohttp_exceptions():
+ async for chunk in self._aiohttp_response.content.iter_chunked(self.CHUNK_SIZE):
+ yield chunk
+
+ async def aclose(self) -> None:
+ with map_aiohttp_exceptions():
+ await self._aiohttp_response.__aexit__(None, None, None)
+
+
+class AiohttpTransport(httpx.AsyncBaseTransport):
+ def __init__(
+ self,
+ verify: ssl.SSLContext | str | bool = True,
+ cert: t.Union[str, t.Tuple[str, str], t.Tuple[str, str, str], None] = None,
+ trust_env: bool = True,
+ http1: bool = True,
+ http2: bool = False,
+ limits: httpx.Limits = httpx.Limits(max_connections=100, max_keepalive_connections=20),
+ proxy: httpx.Proxy | None = None,
+ uds: str | None = None,
+ local_address: str | None = None,
+ retries: int = 0,
+ socket_options: typing.Iterable[SOCKET_OPTION] | None = None,
+ client: ClientSession | t.Callable[[], ClientSession] | None = None,
+ # Additional keyword arguments for future compatibility
+ # If httpx decides to add one, we won't break the API
+ **kwargs: t.Dict[str, t.Any],
+ ) -> None:
+ if http2:
+ if not http1:
+ raise httpx.UnsupportedProtocol("HTTP/2 is not supported by aiohttp transport, use HTTP/1.1 instead.")
+ warning("HTTP/2 is not supported by aiohttp transport, using HTTP/1.1 instead.")
+
+ ssl_context = httpx.create_ssl_context(
+ verify=verify,
+ cert=cert,
+ trust_env=trust_env,
+ )
+
+ self.ssl_context = ssl_context
+ self.proxy = proxy
+ self.limits = limits
+ self.retries = retries
+ self.socket_options = socket_options or []
+ self.uds = uds
+ self.local_address = local_address
+
+ self.client = client
+
+ def get_client(self) -> ClientSession:
+ if callable(self.client):
+ return self.client()
+ elif isinstance(self.client, ClientSession):
+ return self.client
+ else:
+ limit_kwarg = (
+ {
+ "limit": self.limits.max_connections,
+ }
+ if self.limits.max_connections is not None
+ else {}
+ )
+ if self.uds:
+ connector = aiohttp.UnixConnector(
+ path=self.uds,
+ keepalive_timeout=self.limits.keepalive_expiry,
+ **limit_kwarg, # type: ignore
+ )
+ else:
+ connector = aiohttp.TCPConnector(
+ keepalive_timeout=self.limits.keepalive_expiry,
+ ssl=self.ssl_context,
+ local_addr=(self.local_address, 0) if self.local_address else None,
+ **limit_kwarg, # type: ignore
+ )
+ return ClientSession(connector=connector)
+
+ async def handle_async_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ if not isinstance(self.client, ClientSession):
+ self.client = self.get_client()
+
+ timeout = request.extensions.get("timeout", {})
+ sni_hostname = request.extensions.get("sni_hostname")
+
+ with map_aiohttp_exceptions():
+ data: t.Union[bytes, httpx.AsyncByteStream, None]
+ try:
+ data = request.content
+ if data == b"":
+ data = None
+
+ except httpx.RequestNotRead:
+ data = request.stream # type: ignore
+ request.headers.pop("transfer-encoding", None) # handled by aiohttp
+
+ response = await self.client.request(
+ method=request.method,
+ url=str(request.url) if request.url else "https://127.0.0.1:8000/",
+ headers=request.headers,
+ data=data,
+ allow_redirects=False,
+ auto_decompress=False,
+ compress=False,
+ timeout=ClientTimeout(
+ sock_connect=timeout.get("connect"),
+ sock_read=timeout.get("read"),
+ connect=timeout.get("pool"),
+ ),
+ server_hostname=sni_hostname,
+ proxy=str(self.proxy.url) if self.proxy else None,
+ proxy_auth=BasicAuth(self.proxy.auth[0], self.proxy.auth[1])
+ if self.proxy and self.proxy.auth
+ else None,
+ proxy_headers=self.proxy.headers if self.proxy else None,
+ ).__aenter__()
+
+ extensions = {"http_version": b"HTTP/1.1"}
+
+ if response.reason:
+ extensions["reason_phrase"] = response.reason.encode()
+
+ return httpx.Response(
+ status_code=response.status,
+ headers=response.raw_headers,
+ stream=AiohttpResponseStream(response),
+ request=request,
+ extensions=extensions,
+ )
+
+ async def aclose(self) -> None:
+ if isinstance(self.client, ClientSession):
+ await self.client.close()
diff --git a/src/openai/_version.py b/src/openai/_version.py
index 4f283c8b56..8889c08af5 100644
--- a/src/openai/_version.py
+++ b/src/openai/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "openai"
-__version__ = "2.54.0" # x-release-please-version
+__version__ = "3.0.0" # x-release-please-version
diff --git a/src/openai/auth/_workload.py b/src/openai/auth/_workload.py
index 1c1efe536d..73b110b445 100644
--- a/src/openai/auth/_workload.py
+++ b/src/openai/auth/_workload.py
@@ -6,9 +6,9 @@
from pathlib import Path
from typing_extensions import Literal, NotRequired
-import httpx
+import httpx2
-from .._httpx2 import DefaultHttpx2Client
+from .._httpx2 import DefaultHttpx2Client, _loaded_legacy_httpx
from .._exceptions import OAuthError, OpenAIError, SubjectTokenProviderError
from .._utils._sync import to_thread
@@ -75,7 +75,7 @@ def azure_managed_identity_token_provider(
msi_res_id: str | None = None,
api_version: str = "2018-02-01",
timeout: float = 10.0,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
) -> SubjectTokenProvider:
"""
Get a subject token provider for Azure Managed Identities.
@@ -89,7 +89,7 @@ def azure_managed_identity_token_provider(
msi_res_id: the ARM resource ID of the managed identity to use, when multiple are assigned.
api_version: the Azure IMDS API version. Defaults to `2018-02-01`.
timeout: the request timeout in seconds. Defaults to 10.0.
- http_client: optional httpx.Client instance to use for requests. If not provided, a new client will be created for each request.
+ http_client: optional httpx2.Client instance to use for requests. If not provided, a new client will be created for each request.
"""
def get_token() -> str:
@@ -106,7 +106,7 @@ def get_token() -> str:
if http_client is not None:
response = http_client.get(url, params=params, headers={"Metadata": "true"}, timeout=timeout)
else:
- with httpx.Client() as client:
+ with httpx2.Client() as client:
response = client.get(url, params=params, headers={"Metadata": "true"}, timeout=timeout)
if response.is_error:
@@ -131,7 +131,7 @@ def gcp_id_token_provider(
audience: str = "https://api.openai.com/v1",
*,
timeout: float = 10.0,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
) -> SubjectTokenProvider:
"""
Get a subject token provider for GCP VM instances using the instance metadata server.
@@ -142,7 +142,7 @@ def gcp_id_token_provider(
audience: the unique URI agreed upon by both the instance and the system verifying
the instance's identity. Defaults to `https://api.openai.com/v1`.
timeout: the request timeout in seconds. Defaults to 10.0.
- http_client: optional httpx.Client instance to use for requests. If not provided, a new client will be created for each request.
+ http_client: optional httpx2.Client instance to use for requests. If not provided, a new client will be created for each request.
"""
def get_token() -> str:
@@ -153,7 +153,7 @@ def get_token() -> str:
if http_client is not None:
response = http_client.get(url, params=params, headers={"Metadata-Flavor": "Google"}, timeout=timeout)
else:
- with httpx.Client() as client:
+ with httpx2.Client() as client:
response = client.get(url, params=params, headers={"Metadata-Flavor": "Google"}, timeout=timeout)
if response.is_error:
@@ -177,7 +177,7 @@ def __init__(
*,
workload_identity: WorkloadIdentity,
token_exchange_url: str = DEFAULT_TOKEN_EXCHANGE_URL,
- _use_httpx2: bool = False,
+ _use_httpx2: bool = True,
):
self.workload_identity = workload_identity
self.token_exchange_url = token_exchange_url
@@ -248,7 +248,10 @@ def _fetch_token_from_exchange(self) -> dict[str, Any]:
f"Unsupported token type: {token_type!r}. Supported types: {', '.join(SUBJECT_TOKEN_TYPES.keys())}"
)
- exchange_client = DefaultHttpx2Client(follow_redirects=False) if self._use_httpx2 else httpx.Client()
+ legacy_httpx = _loaded_legacy_httpx() if not self._use_httpx2 else None
+ exchange_client = (
+ legacy_httpx.Client() if legacy_httpx is not None else DefaultHttpx2Client(follow_redirects=False)
+ )
with exchange_client as client:
response = client.post(
self.token_exchange_url,
@@ -263,7 +266,7 @@ def _fetch_token_from_exchange(self) -> dict[str, Any]:
)
return self._handle_token_response(response)
- def _handle_token_response(self, response: httpx.Response) -> dict[str, Any]:
+ def _handle_token_response(self, response: httpx2.Response) -> dict[str, Any]:
try:
body = response.json() if response.content else None
except ValueError:
diff --git a/src/openai/lib/_realtime.py b/src/openai/lib/_realtime.py
index 3771b52986..e894d8e451 100644
--- a/src/openai/lib/_realtime.py
+++ b/src/openai/lib/_realtime.py
@@ -3,7 +3,7 @@
import json
from typing_extensions import override
-import httpx
+import httpx2
from openai import _legacy_response
from openai._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -28,7 +28,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
if session is omit:
extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})}
@@ -65,7 +65,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
if session is omit:
extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})}
diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py
index 4ebe0a98aa..5e0b6f5203 100644
--- a/src/openai/lib/azure.py
+++ b/src/openai/lib/azure.py
@@ -5,7 +5,7 @@
from typing import Any, Union, Mapping, TypeVar, Callable, Awaitable, cast, overload
from typing_extensions import Self, override
-import httpx
+import httpx2
from ..auth import WorkloadIdentity
from .._types import NOT_GIVEN, Omit, Query, Headers, Timeout, NotGiven
@@ -35,7 +35,7 @@
AzureADTokenProvider = Callable[[], str]
AsyncAzureADTokenProvider = Callable[[], "str | Awaitable[str]"]
-_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient])
+_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx2.Client, httpx2.AsyncClient])
_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]])
@@ -62,7 +62,7 @@ def __init__(self) -> None:
class BaseAzureClient(BaseClient[_HttpxClientT, _DefaultStreamT]):
- _azure_endpoint: httpx.URL | None
+ _azure_endpoint: httpx2.URL | None
_azure_deployment: str | None
@override
@@ -71,7 +71,7 @@ def _build_request(
options: FinalRequestOptions,
*,
retries_taken: int = 0,
- ) -> httpx.Request:
+ ) -> httpx2.Request:
if options.url in _deployments_endpoints and is_mapping(options.json_data):
model = options.json_data.get("model")
if model is not None and "/deployments" not in str(self.base_url.path):
@@ -80,13 +80,13 @@ def _build_request(
return super()._build_request(options, retries_taken=retries_taken)
@override
- def _prepare_url(self, url: str) -> httpx.URL:
+ def _prepare_url(self, url: str) -> httpx2.URL:
"""Adjust the URL if the client was configured with an Azure endpoint + deployment
and the API feature being called is **not** a deployments-based endpoint
(i.e. requires /deployments/deployment-name in the URL path).
"""
if self._azure_deployment and self._azure_endpoint and url not in _deployments_endpoints:
- merge_url = httpx.URL(url)
+ merge_url = httpx2.URL(url)
if merge_url.is_relative_url:
merge_raw_path = (
self._azure_endpoint.raw_path.rstrip(b"/") + b"/openai/" + merge_url.raw_path.lstrip(b"/")
@@ -98,7 +98,7 @@ def _prepare_url(self, url: str) -> httpx.URL:
return super()._prepare_url(url)
-class AzureOpenAI(BaseAzureClient[httpx.Client, Stream[Any]], OpenAI):
+class AzureOpenAI(BaseAzureClient[httpx2.Client, Stream[Any]], OpenAI):
@overload
def __init__(
self,
@@ -112,12 +112,12 @@ def __init__(
azure_ad_token_provider: AzureADTokenProvider | None = None,
organization: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None: ...
@@ -134,12 +134,12 @@ def __init__(
azure_ad_token_provider: AzureADTokenProvider | None = None,
organization: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None: ...
@@ -156,12 +156,12 @@ def __init__(
azure_ad_token_provider: AzureADTokenProvider | None = None,
organization: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None: ...
@@ -181,13 +181,13 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
base_url: str | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None:
@@ -276,7 +276,7 @@ def __init__(
self._azure_ad_token = azure_ad_token
self._azure_ad_token_provider = azure_ad_token_provider
self._azure_deployment = azure_deployment if azure_endpoint else None
- self._azure_endpoint = httpx.URL(azure_endpoint) if azure_endpoint else None
+ self._azure_endpoint = httpx2.URL(azure_endpoint) if azure_endpoint else None
@override
def copy(
@@ -289,13 +289,13 @@ def copy(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
api_version: str | None = None,
azure_ad_token: str | None = None,
azure_ad_token_provider: AzureADTokenProvider | None = None,
- base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
max_retries: int | NotGiven = NOT_GIVEN,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
@@ -393,7 +393,7 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
return options
- def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL, dict[str, str]]:
+ def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx2.URL, dict[str, str]]:
auth_headers = {}
query = {
**extra_query,
@@ -419,7 +419,7 @@ def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL
return url, auth_headers
-class AsyncAzureOpenAI(BaseAzureClient[httpx.AsyncClient, AsyncStream[Any]], AsyncOpenAI):
+class AsyncAzureOpenAI(BaseAzureClient[httpx2.AsyncClient, AsyncStream[Any]], AsyncOpenAI):
@overload
def __init__(
self,
@@ -434,12 +434,12 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None: ...
@@ -457,12 +457,12 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None: ...
@@ -480,12 +480,12 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None: ...
@@ -506,12 +506,12 @@ def __init__(
project: str | None = None,
webhook_secret: str | None = None,
base_url: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
) -> None:
@@ -600,7 +600,7 @@ def __init__(
self._azure_ad_token = azure_ad_token
self._azure_ad_token_provider = azure_ad_token_provider
self._azure_deployment = azure_deployment if azure_endpoint else None
- self._azure_endpoint = httpx.URL(azure_endpoint) if azure_endpoint else None
+ self._azure_endpoint = httpx2.URL(azure_endpoint) if azure_endpoint else None
@override
def copy(
@@ -613,13 +613,13 @@ def copy(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
api_version: str | None = None,
azure_ad_token: str | None = None,
azure_ad_token_provider: AsyncAzureADTokenProvider | None = None,
- base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
max_retries: int | NotGiven = NOT_GIVEN,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
@@ -719,7 +719,7 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp
return options
- async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL, dict[str, str]]:
+ async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx2.URL, dict[str, str]]:
auth_headers = {}
query = {
**extra_query,
diff --git a/src/openai/lib/bedrock.py b/src/openai/lib/bedrock.py
index 466e8ed75e..25a4a56453 100644
--- a/src/openai/lib/bedrock.py
+++ b/src/openai/lib/bedrock.py
@@ -8,7 +8,7 @@
from dataclasses import field, replace, dataclass
from typing_extensions import Self, override
-import httpx
+import httpx2
from ..auth import WorkloadIdentity
from .._types import NOT_GIVEN, Timeout, NotGiven
@@ -71,7 +71,7 @@ def _configured_region(region: str | None) -> str | None:
return configured.strip() if configured is not None and configured.strip() else None
-def _uses_region_derived_base_url(base_url: str | httpx.URL | None) -> bool:
+def _uses_region_derived_base_url(base_url: str | httpx2.URL | None) -> bool:
if isinstance(base_url, str) and not base_url.strip():
base_url = None
if base_url is not None:
@@ -121,7 +121,7 @@ def _legacy_provider(
aws_secret_access_key: str | None,
aws_session_token: str | None,
aws_credentials_provider: AwsCredentialsProvider | None,
- base_url: str | httpx.URL | None,
+ base_url: str | httpx2.URL | None,
region_was_explicit: bool | None = None,
) -> tuple[_Provider, _LegacyBedrockState, str]:
if callable(cast(object, api_key)):
@@ -154,7 +154,7 @@ def _legacy_provider(
resolved_region = _configured_region(aws_region)
uses_region_derived_base_url = _uses_region_derived_base_url(base_url)
- provider_base_url: str | httpx.URL | None | NotGiven
+ provider_base_url: str | httpx2.URL | None | NotGiven
if isinstance(base_url, str) and not base_url.strip():
provider_base_url = None
elif base_url is None:
@@ -203,7 +203,7 @@ def _copy_configuration(
aws_secret_access_key: str | None,
aws_session_token: str | None,
aws_credentials_provider: AwsCredentialsProvider | None,
- base_url: str | httpx.URL | None,
+ base_url: str | httpx2.URL | None,
) -> tuple[dict[str, object], _Provider | None, _LegacyBedrockState | None]:
_synchronize_legacy_routing_state(client)
state = client._bedrock_state
@@ -271,7 +271,7 @@ def _copy_configuration(
next_region = None
if base_url is not None:
- next_base_url: str | httpx.URL | None = base_url
+ next_base_url: str | httpx2.URL | None = base_url
elif state.uses_region_derived_base_url:
next_base_url = ""
else:
@@ -406,13 +406,13 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- base_url: str | httpx.URL | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
_provider: _Provider | None = None,
@@ -525,10 +525,10 @@ def copy(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
- base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
max_retries: int | NotGiven = NOT_GIVEN,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
@@ -640,13 +640,13 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- base_url: str | httpx.URL | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
default_headers: Mapping[str, str] | None = None,
default_query: Mapping[str, object] | None = None,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
_strict_response_validation: bool = False,
_enforce_credentials: bool = True,
_provider: _Provider | None = None,
@@ -761,10 +761,10 @@ def copy(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- websocket_base_url: str | httpx.URL | None = None,
- base_url: str | httpx.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
- http_client: httpx.AsyncClient | None = None,
+ http_client: httpx2.AsyncClient | None = None,
max_retries: int | NotGiven = NOT_GIVEN,
default_headers: Mapping[str, str] | None = None,
set_default_headers: Mapping[str, str] | None = None,
diff --git a/src/openai/providers/bedrock.py b/src/openai/providers/bedrock.py
index ed6be81c9e..e6dafaeaf2 100644
--- a/src/openai/providers/bedrock.py
+++ b/src/openai/providers/bedrock.py
@@ -6,7 +6,7 @@
from typing import Literal, Callable, Awaitable, cast
from dataclasses import field, dataclass
-import httpx
+import httpx2
from .._types import NOT_GIVEN, NotGiven
from .._utils import asyncify
@@ -34,7 +34,7 @@ def _normalize_optional_string(value: str | None) -> str | None:
return normalized or None
-def _normalize_base_url(base_url: str | httpx.URL) -> httpx.URL:
+def _normalize_base_url(base_url: str | httpx2.URL) -> httpx2.URL:
url = normalize_httpx_url(base_url)
path = url.path.rstrip("/")
responses_match = re.search(r"/responses(?:/.*)?$", path)
@@ -44,11 +44,11 @@ def _normalize_base_url(base_url: str | httpx.URL) -> httpx.URL:
return url.copy_with(path=path or "/")
-def _same_origin(left: httpx.URL, right: httpx.URL) -> bool:
+def _same_origin(left: httpx2.URL, right: httpx2.URL) -> bool:
return (left.scheme, left.host, left.port) == (right.scheme, right.host, right.port)
-def _body_for_signing(request: httpx.Request) -> bytes:
+def _body_for_signing(request: httpx2.Request) -> bytes:
try:
return request.content
except request_not_read_exceptions() as exc:
@@ -58,7 +58,7 @@ def _body_for_signing(request: httpx.Request) -> bytes:
) from exc
-def _assert_provider_owns_authorization(request: httpx.Request) -> None:
+def _assert_provider_owns_authorization(request: httpx2.Request) -> None:
if "Authorization" in request.headers:
raise OpenAIError("Bedrock provider authentication cannot be combined with a custom `Authorization` header.")
@@ -74,11 +74,11 @@ def _without_redirects(options: FinalRequestOptions) -> FinalRequestOptions:
class _BedrockBearerAuth:
- def __init__(self, token_provider: BedrockTokenProvider, *, base_url: httpx.URL) -> None:
+ def __init__(self, token_provider: BedrockTokenProvider, *, base_url: httpx2.URL) -> None:
self._token_provider = token_provider
self._base_url = base_url
- def _validate_request(self, request: httpx.Request) -> None:
+ def _validate_request(self, request: httpx2.Request) -> None:
_assert_provider_owns_authorization(request)
if not _same_origin(request.url, self._base_url):
raise OpenAIError(
@@ -116,11 +116,11 @@ async def _resolve_token_async(self) -> str:
raise OpenAIError("The Bedrock bearer credential provider must return a non-empty string.")
return token
- def prepare_request(self, request: httpx.Request) -> None:
+ def prepare_request(self, request: httpx2.Request) -> None:
self._validate_request(request)
request.headers["Authorization"] = f"Bearer {self._resolve_token()}"
- async def prepare_async_request(self, request: httpx.Request) -> None:
+ async def prepare_async_request(self, request: httpx2.Request) -> None:
self._validate_request(request)
request.headers["Authorization"] = f"Bearer {await self._resolve_token_async()}"
@@ -130,14 +130,14 @@ def __init__(
self,
*,
config: BedrockAwsAuthConfig,
- base_url: httpx.URL,
+ base_url: httpx2.URL,
auth: BedrockAwsAuth | None = None,
) -> None:
self._config = config
self._base_url = base_url
self._auth = auth
- def _validate_request(self, request: httpx.Request) -> bytes:
+ def _validate_request(self, request: httpx2.Request) -> bytes:
_assert_provider_owns_authorization(request)
if not _same_origin(request.url, self._base_url):
raise OpenAIError(
@@ -153,7 +153,7 @@ def _validate_request(self, request: httpx.Request) -> bytes:
return _body_for_signing(request)
- def _sign(self, request: httpx.Request, *, auth: BedrockAwsAuth, body: bytes) -> None:
+ def _sign(self, request: httpx2.Request, *, auth: BedrockAwsAuth, body: bytes) -> None:
for header in _AWS_SIGNING_HEADERS:
request.headers.pop(header, None)
@@ -166,13 +166,13 @@ def _sign(self, request: httpx.Request, *, auth: BedrockAwsAuth, body: bytes) ->
request.headers.clear()
request.headers.update(signed_headers)
- def prepare_request(self, request: httpx.Request) -> None:
+ def prepare_request(self, request: httpx2.Request) -> None:
body = self._validate_request(request)
if self._auth is None:
self._auth = BedrockAwsAuth(self._config)
self._sign(request, auth=self._auth, body=body)
- async def prepare_async_request(self, request: httpx.Request) -> None:
+ async def prepare_async_request(self, request: httpx2.Request) -> None:
body = self._validate_request(request)
if self._auth is None:
self._auth = await asyncify(BedrockAwsAuth)(self._config)
@@ -198,7 +198,7 @@ class _BedrockProviderRuntime(_ProviderRuntime):
class _BedrockProviderDefinition:
configured_region: str | None
region_source: Literal["explicit", "environment"] | None
- configured_base_url: httpx.URL | None
+ configured_base_url: httpx2.URL | None
api_key: str | None = field(default=None, repr=False)
token_provider: BedrockTokenProvider | None = field(default=None, repr=False, compare=False)
use_environment_bearer: bool = False
@@ -309,7 +309,7 @@ def environment_token() -> str:
def bedrock(
*,
region: str | None = None,
- base_url: str | httpx.URL | None | NotGiven = NOT_GIVEN,
+ base_url: str | httpx2.URL | None | NotGiven = NOT_GIVEN,
api_key: str | None | NotGiven = NOT_GIVEN,
token_provider: BedrockTokenProvider | None = None,
access_key_id: str | None = None,
@@ -334,7 +334,7 @@ def bedrock(
if normalized_region is not None:
region_source = "environment"
- configured_base_url: httpx.URL | None
+ configured_base_url: httpx2.URL | None
if isinstance(base_url, NotGiven):
environment_base_url = _normalize_optional_string(os.environ.get("AWS_BEDROCK_BASE_URL"))
configured_base_url = _normalize_base_url(environment_base_url) if environment_base_url else None
diff --git a/src/openai/resources/admin/organization/admin_api_keys.py b/src/openai/resources/admin/organization/admin_api_keys.py
index b521393f2e..518413e4ee 100644
--- a/src/openai/resources/admin/organization/admin_api_keys.py
+++ b/src/openai/resources/admin/organization/admin_api_keys.py
@@ -5,7 +5,7 @@
from typing import Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AdminAPIKeyCreateResponse:
"""
Create an organization admin API key
@@ -98,7 +98,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AdminAPIKey:
"""
Retrieve a single organization API key
@@ -139,7 +139,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[AdminAPIKey]:
"""
List organization API keys
@@ -189,7 +189,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AdminAPIKeyDeleteResponse:
"""
Delete an organization admin API key
@@ -250,7 +250,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AdminAPIKeyCreateResponse:
"""
Create an organization admin API key
@@ -295,7 +295,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AdminAPIKey:
"""
Retrieve a single organization API key
@@ -336,7 +336,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[AdminAPIKey, AsyncCursorPage[AdminAPIKey]]:
"""
List organization API keys
@@ -386,7 +386,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AdminAPIKeyDeleteResponse:
"""
Delete an organization admin API key
diff --git a/src/openai/resources/admin/organization/audit_logs.py b/src/openai/resources/admin/organization/audit_logs.py
index 9c8ec62543..5fc61feae3 100644
--- a/src/openai/resources/admin/organization/audit_logs.py
+++ b/src/openai/resources/admin/organization/audit_logs.py
@@ -5,7 +5,7 @@
from typing import List
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -208,7 +208,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[AuditLogListResponse]:
"""
List user actions and configuration changes within this organization.
@@ -473,7 +473,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[AuditLogListResponse, AsyncConversationCursorPage[AuditLogListResponse]]:
"""
List user actions and configuration changes within this organization.
diff --git a/src/openai/resources/admin/organization/certificates.py b/src/openai/resources/admin/organization/certificates.py
index 025c493368..e2f0c08e8f 100644
--- a/src/openai/resources/admin/organization/certificates.py
+++ b/src/openai/resources/admin/organization/certificates.py
@@ -5,7 +5,7 @@
from typing import List
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -62,7 +62,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Certificate:
"""Upload a certificate to the organization.
@@ -113,7 +113,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Certificate:
"""
Get a certificate that has been uploaded to the organization.
@@ -157,7 +157,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Certificate:
"""Modify a certificate.
@@ -200,7 +200,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[CertificateListResponse]:
"""
List uploaded certificates for this organization.
@@ -255,7 +255,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> CertificateDeleteResponse:
"""
Delete a certificate from the organization.
@@ -294,7 +294,7 @@ def activate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[CertificateActivateResponse]:
"""
Activate certificates at the organization level.
@@ -336,7 +336,7 @@ def deactivate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[CertificateDeactivateResponse]:
"""
Deactivate certificates at the organization level.
@@ -400,7 +400,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Certificate:
"""Upload a certificate to the organization.
@@ -451,7 +451,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Certificate:
"""
Get a certificate that has been uploaded to the organization.
@@ -497,7 +497,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Certificate:
"""Modify a certificate.
@@ -540,7 +540,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CertificateListResponse, AsyncConversationCursorPage[CertificateListResponse]]:
"""
List uploaded certificates for this organization.
@@ -595,7 +595,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> CertificateDeleteResponse:
"""
Delete a certificate from the organization.
@@ -634,7 +634,7 @@ def activate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CertificateActivateResponse, AsyncPage[CertificateActivateResponse]]:
"""
Activate certificates at the organization level.
@@ -676,7 +676,7 @@ def deactivate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CertificateDeactivateResponse, AsyncPage[CertificateDeactivateResponse]]:
"""
Deactivate certificates at the organization level.
diff --git a/src/openai/resources/admin/organization/data_retention.py b/src/openai/resources/admin/organization/data_retention.py
index 1b353c7c18..cb2ff611d6 100644
--- a/src/openai/resources/admin/organization/data_retention.py
+++ b/src/openai/resources/admin/organization/data_retention.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Query, Headers, NotGiven, not_given
@@ -47,7 +47,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationDataRetention:
"""Retrieves organization data retention controls."""
return self._get(
@@ -76,7 +76,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationDataRetention:
"""
Updates organization data retention controls.
@@ -136,7 +136,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationDataRetention:
"""Retrieves organization data retention controls."""
return await self._get(
@@ -165,7 +165,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationDataRetention:
"""
Updates organization data retention controls.
diff --git a/src/openai/resources/admin/organization/groups/groups.py b/src/openai/resources/admin/organization/groups/groups.py
index 7c7f1dc5cd..24e44f4a19 100644
--- a/src/openai/resources/admin/organization/groups/groups.py
+++ b/src/openai/resources/admin/organization/groups/groups.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from .roles import (
@@ -75,7 +75,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Group:
"""
Creates a new group in the organization.
@@ -113,7 +113,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Group:
"""
Retrieves a group.
@@ -151,7 +151,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GroupUpdateResponse:
"""
Updates a group's information.
@@ -193,7 +193,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[Group]:
"""
Lists all groups in the organization.
@@ -247,7 +247,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GroupDeleteResponse:
"""
Deletes a group from the organization.
@@ -313,7 +313,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Group:
"""
Creates a new group in the organization.
@@ -351,7 +351,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Group:
"""
Retrieves a group.
@@ -389,7 +389,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GroupUpdateResponse:
"""
Updates a group's information.
@@ -431,7 +431,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Group, AsyncNextCursorPage[Group]]:
"""
Lists all groups in the organization.
@@ -485,7 +485,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GroupDeleteResponse:
"""
Deletes a group from the organization.
diff --git a/src/openai/resources/admin/organization/groups/roles.py b/src/openai/resources/admin/organization/groups/roles.py
index e7054d5f0c..b6f0e85909 100644
--- a/src/openai/resources/admin/organization/groups/roles.py
+++ b/src/openai/resources/admin/organization/groups/roles.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns an organization role to a group within the organization.
@@ -94,7 +94,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves an organization role assigned to a group.
@@ -136,7 +136,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[RoleListResponse]:
"""
Lists the organization roles assigned to a group within the organization.
@@ -190,7 +190,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns an organization role from a group within the organization.
@@ -251,7 +251,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns an organization role to a group within the organization.
@@ -292,7 +292,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves an organization role assigned to a group.
@@ -334,7 +334,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]:
"""
Lists the organization roles assigned to a group within the organization.
@@ -388,7 +388,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns an organization role from a group within the organization.
diff --git a/src/openai/resources/admin/organization/groups/users.py b/src/openai/resources/admin/organization/groups/users.py
index 0e40f772b2..9dd8feb1ca 100644
--- a/src/openai/resources/admin/organization/groups/users.py
+++ b/src/openai/resources/admin/organization/groups/users.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserCreateResponse:
"""
Adds a user to a group.
@@ -94,7 +94,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserRetrieveResponse:
"""
Retrieves a user in a group.
@@ -136,7 +136,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[OrganizationGroupUser]:
"""
Lists the users assigned to a group.
@@ -191,7 +191,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserDeleteResponse:
"""
Removes a user from a group.
@@ -252,7 +252,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserCreateResponse:
"""
Adds a user to a group.
@@ -293,7 +293,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserRetrieveResponse:
"""
Retrieves a user in a group.
@@ -335,7 +335,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[OrganizationGroupUser, AsyncNextCursorPage[OrganizationGroupUser]]:
"""
Lists the users assigned to a group.
@@ -390,7 +390,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserDeleteResponse:
"""
Removes a user from a group.
diff --git a/src/openai/resources/admin/organization/invites.py b/src/openai/resources/admin/organization/invites.py
index b06e4be2aa..cfe63a946a 100644
--- a/src/openai/resources/admin/organization/invites.py
+++ b/src/openai/resources/admin/organization/invites.py
@@ -5,7 +5,7 @@
from typing import Iterable
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Invite:
"""Create an invite for a user to the organization.
@@ -107,7 +107,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Invite:
"""
Retrieves an invite.
@@ -145,7 +145,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[Invite]:
"""
Returns a list of invites in the organization.
@@ -196,7 +196,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> InviteDeleteResponse:
"""Delete an invite.
@@ -257,7 +257,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Invite:
"""Create an invite for a user to the organization.
@@ -311,7 +311,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Invite:
"""
Retrieves an invite.
@@ -349,7 +349,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Invite, AsyncConversationCursorPage[Invite]]:
"""
Returns a list of invites in the organization.
@@ -400,7 +400,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> InviteDeleteResponse:
"""Delete an invite.
diff --git a/src/openai/resources/admin/organization/projects/api_keys.py b/src/openai/resources/admin/organization/projects/api_keys.py
index 0bc16e807c..50ba64f81d 100644
--- a/src/openai/resources/admin/organization/projects/api_keys.py
+++ b/src/openai/resources/admin/organization/projects/api_keys.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -51,7 +51,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectAPIKey:
"""
Retrieves an API key in the project.
@@ -97,7 +97,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ProjectAPIKey]:
"""
Returns a list of API keys in the project.
@@ -158,7 +158,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> APIKeyDeleteResponse:
"""
Deletes an API key from the project.
@@ -226,7 +226,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectAPIKey:
"""
Retrieves an API key in the project.
@@ -272,7 +272,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProjectAPIKey, AsyncConversationCursorPage[ProjectAPIKey]]:
"""
Returns a list of API keys in the project.
@@ -333,7 +333,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> APIKeyDeleteResponse:
"""
Deletes an API key from the project.
diff --git a/src/openai/resources/admin/organization/projects/certificates.py b/src/openai/resources/admin/organization/projects/certificates.py
index 0bd8c02601..c57f1d58f1 100644
--- a/src/openai/resources/admin/organization/projects/certificates.py
+++ b/src/openai/resources/admin/organization/projects/certificates.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -58,7 +58,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[CertificateListResponse]:
"""
List certificates for this project.
@@ -116,7 +116,7 @@ def activate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[CertificateActivateResponse]:
"""
Activate certificates at the project level.
@@ -161,7 +161,7 @@ def deactivate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[CertificateDeactivateResponse]:
"""Deactivate certificates at the project level.
@@ -229,7 +229,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CertificateListResponse, AsyncConversationCursorPage[CertificateListResponse]]:
"""
List certificates for this project.
@@ -287,7 +287,7 @@ def activate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CertificateActivateResponse, AsyncPage[CertificateActivateResponse]]:
"""
Activate certificates at the project level.
@@ -332,7 +332,7 @@ def deactivate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[CertificateDeactivateResponse, AsyncPage[CertificateDeactivateResponse]]:
"""Deactivate certificates at the project level.
diff --git a/src/openai/resources/admin/organization/projects/data_retention.py b/src/openai/resources/admin/organization/projects/data_retention.py
index 14c9c8c4a0..90ab30d2b9 100644
--- a/src/openai/resources/admin/organization/projects/data_retention.py
+++ b/src/openai/resources/admin/organization/projects/data_retention.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Query, Headers, NotGiven, not_given
@@ -48,7 +48,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectDataRetention:
"""
Retrieves project data retention controls.
@@ -93,7 +93,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectDataRetention:
"""
Updates project data retention controls.
@@ -156,7 +156,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectDataRetention:
"""
Retrieves project data retention controls.
@@ -201,7 +201,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectDataRetention:
"""
Updates project data retention controls.
diff --git a/src/openai/resources/admin/organization/projects/groups/groups.py b/src/openai/resources/admin/organization/projects/groups/groups.py
index 2b8ad6fd55..e86700c26c 100644
--- a/src/openai/resources/admin/organization/projects/groups/groups.py
+++ b/src/openai/resources/admin/organization/projects/groups/groups.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ...... import _legacy_response
from .roles import (
@@ -64,7 +64,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectGroup:
"""
Grants a group access to a project.
@@ -114,7 +114,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectGroup:
"""
Retrieves a project's group.
@@ -161,7 +161,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[ProjectGroup]:
"""
Lists the groups that have access to a project.
@@ -215,7 +215,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GroupDeleteResponse:
"""
Revokes a group's access to a project.
@@ -283,7 +283,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectGroup:
"""
Grants a group access to a project.
@@ -333,7 +333,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectGroup:
"""
Retrieves a project's group.
@@ -382,7 +382,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProjectGroup, AsyncNextCursorPage[ProjectGroup]]:
"""
Lists the groups that have access to a project.
@@ -436,7 +436,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GroupDeleteResponse:
"""
Revokes a group's access to a project.
diff --git a/src/openai/resources/admin/organization/projects/groups/roles.py b/src/openai/resources/admin/organization/projects/groups/roles.py
index 70c5e93363..a3f9cff121 100644
--- a/src/openai/resources/admin/organization/projects/groups/roles.py
+++ b/src/openai/resources/admin/organization/projects/groups/roles.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ...... import _legacy_response
from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -54,7 +54,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns a project role to a group within a project.
@@ -98,7 +98,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves a project role assigned to a group.
@@ -148,7 +148,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[RoleListResponse]:
"""
Lists the project roles assigned to a group within a project.
@@ -205,7 +205,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns a project role from a group within a project.
@@ -274,7 +274,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns a project role to a group within a project.
@@ -318,7 +318,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves a project role assigned to a group.
@@ -368,7 +368,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]:
"""
Lists the project roles assigned to a group within a project.
@@ -425,7 +425,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns a project role from a group within a project.
diff --git a/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py b/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py
index 05737e8860..60ad9e830a 100644
--- a/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py
+++ b/src/openai/resources/admin/organization/projects/hosted_tool_permissions.py
@@ -4,7 +4,7 @@
from typing import Optional
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -48,7 +48,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectHostedToolPermissions:
"""
Returns hosted tool permissions for a project.
@@ -90,7 +90,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectHostedToolPermissions:
"""
Updates hosted tool permissions for a project.
@@ -168,7 +168,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectHostedToolPermissions:
"""
Returns hosted tool permissions for a project.
@@ -210,7 +210,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectHostedToolPermissions:
"""
Updates hosted tool permissions for a project.
diff --git a/src/openai/resources/admin/organization/projects/model_permissions.py b/src/openai/resources/admin/organization/projects/model_permissions.py
index 7320109a72..9f9fcb468e 100644
--- a/src/openai/resources/admin/organization/projects/model_permissions.py
+++ b/src/openai/resources/admin/organization/projects/model_permissions.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Query, Headers, NotGiven, SequenceNotStr, not_given
@@ -49,7 +49,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectModelPermissions:
"""
Returns model permissions for a project.
@@ -88,7 +88,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectModelPermissions:
"""
Updates model permissions for a project.
@@ -136,7 +136,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectModelPermissionsDeleted:
"""
Deletes model permissions for a project.
@@ -194,7 +194,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectModelPermissions:
"""
Returns model permissions for a project.
@@ -233,7 +233,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectModelPermissions:
"""
Updates model permissions for a project.
@@ -281,7 +281,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectModelPermissionsDeleted:
"""
Deletes model permissions for a project.
diff --git a/src/openai/resources/admin/organization/projects/projects.py b/src/openai/resources/admin/organization/projects/projects.py
index ea2fb51613..7696f2e9cb 100644
--- a/src/openai/resources/admin/organization/projects/projects.py
+++ b/src/openai/resources/admin/organization/projects/projects.py
@@ -4,7 +4,7 @@
from typing import Optional
-import httpx
+import httpx2
from ..... import _legacy_response
from .roles import (
@@ -195,7 +195,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""Create a new project in the organization.
@@ -249,7 +249,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""
Retrieves a project.
@@ -289,7 +289,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""
Modifies a project in the organization.
@@ -342,7 +342,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[Project]:
"""Returns a list of projects.
@@ -398,7 +398,7 @@ def archive(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""Archives a project in the organization.
@@ -508,7 +508,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""Create a new project in the organization.
@@ -562,7 +562,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""
Retrieves a project.
@@ -602,7 +602,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""
Modifies a project in the organization.
@@ -655,7 +655,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Project, AsyncConversationCursorPage[Project]]:
"""Returns a list of projects.
@@ -711,7 +711,7 @@ async def archive(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Project:
"""Archives a project in the organization.
diff --git a/src/openai/resources/admin/organization/projects/rate_limits.py b/src/openai/resources/admin/organization/projects/rate_limits.py
index 7f33d07414..f40ea76cf8 100644
--- a/src/openai/resources/admin/organization/projects/rate_limits.py
+++ b/src/openai/resources/admin/organization/projects/rate_limits.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def list_rate_limits(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ProjectRateLimit]:
"""
Returns the rate limits per model for a project.
@@ -118,7 +118,7 @@ def update_rate_limit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectRateLimit:
"""
Updates a project rate limit.
@@ -208,7 +208,7 @@ def list_rate_limits(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProjectRateLimit, AsyncConversationCursorPage[ProjectRateLimit]]:
"""
Returns the rate limits per model for a project.
@@ -273,7 +273,7 @@ async def update_rate_limit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectRateLimit:
"""
Updates a project rate limit.
diff --git a/src/openai/resources/admin/organization/projects/roles.py b/src/openai/resources/admin/organization/projects/roles.py
index 754a487b52..bb93cfe742 100644
--- a/src/openai/resources/admin/organization/projects/roles.py
+++ b/src/openai/resources/admin/organization/projects/roles.py
@@ -5,7 +5,7 @@
from typing import Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -54,7 +54,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Creates a custom role for a project.
@@ -106,7 +106,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Retrieves a project role.
@@ -149,7 +149,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Updates an existing project role.
@@ -205,7 +205,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[Role]:
"""Lists the roles configured for a project.
@@ -260,7 +260,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Deletes a custom role from a project.
@@ -323,7 +323,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Creates a custom role for a project.
@@ -375,7 +375,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Retrieves a project role.
@@ -418,7 +418,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Updates an existing project role.
@@ -474,7 +474,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Role, AsyncNextCursorPage[Role]]:
"""Lists the roles configured for a project.
@@ -529,7 +529,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Deletes a custom role from a project.
diff --git a/src/openai/resources/admin/organization/projects/service_accounts/api_keys.py b/src/openai/resources/admin/organization/projects/service_accounts/api_keys.py
index d25b1e8bf0..96f38b544d 100644
--- a/src/openai/resources/admin/organization/projects/service_accounts/api_keys.py
+++ b/src/openai/resources/admin/organization/projects/service_accounts/api_keys.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from ...... import _legacy_response
from ......_types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -49,7 +49,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> APIKeyCreateResponse:
"""
Creates an API key for a service account in the project.
@@ -131,7 +131,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> APIKeyCreateResponse:
"""
Creates an API key for a service account in the project.
diff --git a/src/openai/resources/admin/organization/projects/service_accounts/service_accounts.py b/src/openai/resources/admin/organization/projects/service_accounts/service_accounts.py
index e7aa6f0f4e..c1618d4ae6 100644
--- a/src/openai/resources/admin/organization/projects/service_accounts/service_accounts.py
+++ b/src/openai/resources/admin/organization/projects/service_accounts/service_accounts.py
@@ -5,7 +5,7 @@
from typing import Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ...... import _legacy_response
from .api_keys import (
@@ -70,7 +70,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ServiceAccountCreateResponse:
"""Creates a new service account in the project.
@@ -121,7 +121,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectServiceAccount:
"""
Retrieves a service account in the project.
@@ -167,7 +167,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectServiceAccount:
"""
Updates a service account in the project.
@@ -223,7 +223,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ProjectServiceAccount]:
"""
Returns a list of service accounts in the project.
@@ -277,7 +277,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ServiceAccountDeleteResponse:
"""
Deletes a service account from the project.
@@ -350,7 +350,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ServiceAccountCreateResponse:
"""Creates a new service account in the project.
@@ -401,7 +401,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectServiceAccount:
"""
Retrieves a service account in the project.
@@ -447,7 +447,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectServiceAccount:
"""
Updates a service account in the project.
@@ -503,7 +503,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProjectServiceAccount, AsyncConversationCursorPage[ProjectServiceAccount]]:
"""
Returns a list of service accounts in the project.
@@ -557,7 +557,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ServiceAccountDeleteResponse:
"""
Deletes a service account from the project.
diff --git a/src/openai/resources/admin/organization/projects/spend_alerts.py b/src/openai/resources/admin/organization/projects/spend_alerts.py
index be0ed1bae6..3fab082ed7 100644
--- a/src/openai/resources/admin/organization/projects/spend_alerts.py
+++ b/src/openai/resources/admin/organization/projects/spend_alerts.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -58,7 +58,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlert:
"""
Creates a project spend alert.
@@ -113,7 +113,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlert:
"""
Retrieves a project spend alert.
@@ -159,7 +159,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlert:
"""
Updates a project spend alert.
@@ -221,7 +221,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ProjectSpendAlert]:
"""Lists project spend alerts.
@@ -280,7 +280,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlertDeleted:
"""
Deletes a project spend alert.
@@ -346,7 +346,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlert:
"""
Creates a project spend alert.
@@ -401,7 +401,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlert:
"""
Retrieves a project spend alert.
@@ -447,7 +447,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlert:
"""
Updates a project spend alert.
@@ -509,7 +509,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProjectSpendAlert, AsyncConversationCursorPage[ProjectSpendAlert]]:
"""Lists project spend alerts.
@@ -568,7 +568,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendAlertDeleted:
"""
Deletes a project spend alert.
diff --git a/src/openai/resources/admin/organization/projects/spend_limit.py b/src/openai/resources/admin/organization/projects/spend_limit.py
index 41497b2838..8eec885a08 100644
--- a/src/openai/resources/admin/organization/projects/spend_limit.py
+++ b/src/openai/resources/admin/organization/projects/spend_limit.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Query, Headers, NotGiven, not_given
@@ -49,7 +49,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendLimit:
"""
Get a project's hard spend limit.
@@ -89,7 +89,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendLimit:
"""
Create or replace a project's hard spend limit.
@@ -141,7 +141,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendLimitDeleted:
"""
Delete a project's hard spend limit.
@@ -199,7 +199,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendLimit:
"""
Get a project's hard spend limit.
@@ -239,7 +239,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendLimit:
"""
Create or replace a project's hard spend limit.
@@ -291,7 +291,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectSpendLimitDeleted:
"""
Delete a project's hard spend limit.
diff --git a/src/openai/resources/admin/organization/projects/users/roles.py b/src/openai/resources/admin/organization/projects/users/roles.py
index 59ee68f135..d7ede48ec5 100644
--- a/src/openai/resources/admin/organization/projects/users/roles.py
+++ b/src/openai/resources/admin/organization/projects/users/roles.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ...... import _legacy_response
from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -54,7 +54,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns a project role to a user within a project.
@@ -98,7 +98,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves a project role assigned to a user.
@@ -148,7 +148,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[RoleListResponse]:
"""
Lists the project roles assigned to a user within a project.
@@ -205,7 +205,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns a project role from a user within a project.
@@ -274,7 +274,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns a project role to a user within a project.
@@ -318,7 +318,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves a project role assigned to a user.
@@ -368,7 +368,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]:
"""
Lists the project roles assigned to a user within a project.
@@ -425,7 +425,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns a project role from a user within a project.
diff --git a/src/openai/resources/admin/organization/projects/users/users.py b/src/openai/resources/admin/organization/projects/users/users.py
index a1633968df..e714b86196 100644
--- a/src/openai/resources/admin/organization/projects/users/users.py
+++ b/src/openai/resources/admin/organization/projects/users/users.py
@@ -4,7 +4,7 @@
from typing import Optional
-import httpx
+import httpx2
from ...... import _legacy_response
from .roles import (
@@ -65,7 +65,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectUser:
"""Adds a user to the project.
@@ -119,7 +119,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectUser:
"""
Retrieves a user in the project.
@@ -162,7 +162,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectUser:
"""
Modifies a user's role in the project.
@@ -208,7 +208,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ProjectUser]:
"""
Returns a list of users in the project.
@@ -262,7 +262,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserDeleteResponse:
"""
Deletes a user from the project.
@@ -334,7 +334,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectUser:
"""Adds a user to the project.
@@ -388,7 +388,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectUser:
"""
Retrieves a user in the project.
@@ -431,7 +431,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ProjectUser:
"""
Modifies a user's role in the project.
@@ -477,7 +477,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ProjectUser, AsyncConversationCursorPage[ProjectUser]]:
"""
Returns a list of users in the project.
@@ -531,7 +531,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserDeleteResponse:
"""
Deletes a user from the project.
diff --git a/src/openai/resources/admin/organization/roles.py b/src/openai/resources/admin/organization/roles.py
index aa4f19f504..5ecd2f7626 100644
--- a/src/openai/resources/admin/organization/roles.py
+++ b/src/openai/resources/admin/organization/roles.py
@@ -5,7 +5,7 @@
from typing import Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Creates a custom role for the organization.
@@ -102,7 +102,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Retrieves an organization role.
@@ -142,7 +142,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Updates an existing organization role.
@@ -195,7 +195,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[Role]:
"""
Lists the roles configured for the organization.
@@ -246,7 +246,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Deletes a custom role from the organization.
@@ -306,7 +306,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Creates a custom role for the organization.
@@ -355,7 +355,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Retrieves an organization role.
@@ -395,7 +395,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Role:
"""
Updates an existing organization role.
@@ -448,7 +448,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Role, AsyncNextCursorPage[Role]]:
"""
Lists the roles configured for the organization.
@@ -499,7 +499,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Deletes a custom role from the organization.
diff --git a/src/openai/resources/admin/organization/spend_alerts.py b/src/openai/resources/admin/organization/spend_alerts.py
index fc36554617..8b601835f7 100644
--- a/src/openai/resources/admin/organization/spend_alerts.py
+++ b/src/openai/resources/admin/organization/spend_alerts.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlert:
"""
Creates an organization spend alert.
@@ -105,7 +105,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlert:
"""
Retrieves an organization spend alert.
@@ -146,7 +146,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlert:
"""
Updates an organization spend alert.
@@ -203,7 +203,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[OrganizationSpendAlert]:
"""Lists organization spend alerts.
@@ -259,7 +259,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlertDeleted:
"""
Deletes an organization spend alert.
@@ -320,7 +320,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlert:
"""
Creates an organization spend alert.
@@ -372,7 +372,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlert:
"""
Retrieves an organization spend alert.
@@ -413,7 +413,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlert:
"""
Updates an organization spend alert.
@@ -470,7 +470,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[OrganizationSpendAlert, AsyncConversationCursorPage[OrganizationSpendAlert]]:
"""Lists organization spend alerts.
@@ -526,7 +526,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendAlertDeleted:
"""
Deletes an organization spend alert.
diff --git a/src/openai/resources/admin/organization/spend_limit.py b/src/openai/resources/admin/organization/spend_limit.py
index b7f2745d2a..fd79775853 100644
--- a/src/openai/resources/admin/organization/spend_limit.py
+++ b/src/openai/resources/admin/organization/spend_limit.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Query, Headers, NotGiven, not_given
@@ -48,7 +48,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendLimit:
"""Get the organization's hard spend limit."""
return self._get(
@@ -74,7 +74,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendLimit:
"""
Create or replace the organization's hard spend limit.
@@ -123,7 +123,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendLimitDeleted:
"""Delete the organization's hard spend limit."""
return self._delete(
@@ -167,7 +167,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendLimit:
"""Get the organization's hard spend limit."""
return await self._get(
@@ -193,7 +193,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendLimit:
"""
Create or replace the organization's hard spend limit.
@@ -242,7 +242,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationSpendLimitDeleted:
"""Delete the organization's hard spend limit."""
return await self._delete(
diff --git a/src/openai/resources/admin/organization/usage.py b/src/openai/resources/admin/organization/usage.py
index 5c2f2b5947..5dbda76f3c 100644
--- a/src/openai/resources/admin/organization/usage.py
+++ b/src/openai/resources/admin/organization/usage.py
@@ -5,7 +5,7 @@
from typing import List
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -80,7 +80,7 @@ def audio_speeches(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageAudioSpeechesResponse:
"""
Get audio speeches usage details for the organization.
@@ -166,7 +166,7 @@ def audio_transcriptions(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageAudioTranscriptionsResponse:
"""
Get audio transcriptions usage details for the organization.
@@ -249,7 +249,7 @@ def code_interpreter_sessions(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageCodeInterpreterSessionsResponse:
"""
Get code interpreter sessions usage details for the organization.
@@ -327,7 +327,7 @@ def completions(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageCompletionsResponse:
"""
Get completions usage details for the organization.
@@ -416,7 +416,7 @@ def costs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageCostsResponse:
"""
Get costs details for the organization.
@@ -493,7 +493,7 @@ def embeddings(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageEmbeddingsResponse:
"""
Get embeddings usage details for the organization.
@@ -579,7 +579,7 @@ def file_search_calls(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageFileSearchCallsResponse:
"""
Get file search calls usage details for the organization.
@@ -668,7 +668,7 @@ def images(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageImagesResponse:
"""
Get images usage details for the organization.
@@ -763,7 +763,7 @@ def moderations(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageModerationsResponse:
"""
Get moderations usage details for the organization.
@@ -846,7 +846,7 @@ def vector_stores(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageVectorStoresResponse:
"""
Get vector stores usage details for the organization.
@@ -924,7 +924,7 @@ def web_search_calls(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageWebSearchCallsResponse:
"""
Get web search calls usage details for the organization.
@@ -1035,7 +1035,7 @@ async def audio_speeches(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageAudioSpeechesResponse:
"""
Get audio speeches usage details for the organization.
@@ -1121,7 +1121,7 @@ async def audio_transcriptions(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageAudioTranscriptionsResponse:
"""
Get audio transcriptions usage details for the organization.
@@ -1204,7 +1204,7 @@ async def code_interpreter_sessions(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageCodeInterpreterSessionsResponse:
"""
Get code interpreter sessions usage details for the organization.
@@ -1282,7 +1282,7 @@ async def completions(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageCompletionsResponse:
"""
Get completions usage details for the organization.
@@ -1371,7 +1371,7 @@ async def costs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageCostsResponse:
"""
Get costs details for the organization.
@@ -1448,7 +1448,7 @@ async def embeddings(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageEmbeddingsResponse:
"""
Get embeddings usage details for the organization.
@@ -1534,7 +1534,7 @@ async def file_search_calls(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageFileSearchCallsResponse:
"""
Get file search calls usage details for the organization.
@@ -1623,7 +1623,7 @@ async def images(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageImagesResponse:
"""
Get images usage details for the organization.
@@ -1718,7 +1718,7 @@ async def moderations(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageModerationsResponse:
"""
Get moderations usage details for the organization.
@@ -1801,7 +1801,7 @@ async def vector_stores(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageVectorStoresResponse:
"""
Get vector stores usage details for the organization.
@@ -1879,7 +1879,7 @@ async def web_search_calls(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UsageWebSearchCallsResponse:
"""
Get web search calls usage details for the organization.
diff --git a/src/openai/resources/admin/organization/users/roles.py b/src/openai/resources/admin/organization/users/roles.py
index 5baff40973..bc9304e4ec 100644
--- a/src/openai/resources/admin/organization/users/roles.py
+++ b/src/openai/resources/admin/organization/users/roles.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -53,7 +53,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns an organization role to a user within the organization.
@@ -94,7 +94,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves an organization role assigned to a user.
@@ -136,7 +136,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncNextCursorPage[RoleListResponse]:
"""
Lists the organization roles assigned to a user within the organization.
@@ -190,7 +190,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns an organization role from a user within the organization.
@@ -251,7 +251,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleCreateResponse:
"""
Assigns an organization role to a user within the organization.
@@ -292,7 +292,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleRetrieveResponse:
"""
Retrieves an organization role assigned to a user.
@@ -334,7 +334,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[RoleListResponse, AsyncNextCursorPage[RoleListResponse]]:
"""
Lists the organization roles assigned to a user within the organization.
@@ -388,7 +388,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RoleDeleteResponse:
"""
Unassigns an organization role from a user within the organization.
diff --git a/src/openai/resources/admin/organization/users/users.py b/src/openai/resources/admin/organization/users/users.py
index 5ee162a903..4a66571663 100644
--- a/src/openai/resources/admin/organization/users/users.py
+++ b/src/openai/resources/admin/organization/users/users.py
@@ -4,7 +4,7 @@
from typing import Optional
-import httpx
+import httpx2
from ..... import _legacy_response
from .roles import (
@@ -62,7 +62,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationUser:
"""
Retrieves a user by their identifier.
@@ -103,7 +103,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationUser:
"""
Modifies a user's role in the organization.
@@ -159,7 +159,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[OrganizationUser]:
"""
Lists all of the users in the organization.
@@ -213,7 +213,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserDeleteResponse:
"""
Deletes a user from the organization.
@@ -275,7 +275,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationUser:
"""
Retrieves a user by their identifier.
@@ -316,7 +316,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OrganizationUser:
"""
Modifies a user's role in the organization.
@@ -372,7 +372,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[OrganizationUser, AsyncConversationCursorPage[OrganizationUser]]:
"""
Lists all of the users in the organization.
@@ -426,7 +426,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UserDeleteResponse:
"""
Deletes a user from the organization.
diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py
index 91ac32ab96..d0b255b4fb 100644
--- a/src/openai/resources/audio/speech.py
+++ b/src/openai/resources/audio/speech.py
@@ -5,7 +5,7 @@
from typing import Union
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -62,7 +62,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Generates audio from the input text.
@@ -166,7 +166,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Generates audio from the input text.
diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py
index b7f3a9ba35..80b7cbdcf6 100644
--- a/src/openai/resources/audio/transcriptions.py
+++ b/src/openai/resources/audio/transcriptions.py
@@ -6,7 +6,7 @@
from typing import TYPE_CHECKING, List, Union, Mapping, Optional, cast
from typing_extensions import Literal, overload, assert_never
-import httpx
+import httpx2
from ... import _legacy_response
from ..._files import deepcopy_with_paths
@@ -85,7 +85,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Transcription:
"""
Transcribes audio into the input language.
@@ -180,7 +180,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranscriptionVerbose: ...
@overload
@@ -203,7 +203,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str: ...
@overload
@@ -226,7 +226,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranscriptionDiarized: ...
@overload
@@ -252,7 +252,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[TranscriptionStreamEvent]:
"""
Transcribes audio into the input language.
@@ -373,7 +373,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranscriptionCreateResponse | Stream[TranscriptionStreamEvent]:
"""
Transcribes audio into the input language.
@@ -494,7 +494,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str | Transcription | TranscriptionDiarized | TranscriptionVerbose | Stream[TranscriptionStreamEvent]:
body = deepcopy_with_paths(
{
@@ -587,7 +587,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranscriptionCreateResponse:
"""
Transcribes audio into the input language.
@@ -700,7 +700,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranscriptionVerbose: ...
@overload
@@ -723,7 +723,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str: ...
@overload
@@ -749,7 +749,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[TranscriptionStreamEvent]:
"""
Transcribes audio into the input language.
@@ -870,7 +870,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranscriptionCreateResponse | AsyncStream[TranscriptionStreamEvent]:
"""
Transcribes audio into the input language.
@@ -991,7 +991,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Transcription | TranscriptionVerbose | TranscriptionDiarized | str | AsyncStream[TranscriptionStreamEvent]:
body = deepcopy_with_paths(
{
diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py
index 8b8f16d051..60b746b5f2 100644
--- a/src/openai/resources/audio/translations.py
+++ b/src/openai/resources/audio/translations.py
@@ -6,7 +6,7 @@
from typing import TYPE_CHECKING, Union, Mapping, cast
from typing_extensions import Literal, overload, assert_never
-import httpx
+import httpx2
from ... import _legacy_response
from ..._files import deepcopy_with_paths
@@ -63,7 +63,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Translation: ...
@overload
@@ -80,7 +80,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranslationVerbose: ...
@overload
@@ -97,7 +97,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str: ...
def create(
@@ -113,7 +113,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Translation | TranslationVerbose | str:
"""
Translates audio into English.
@@ -215,7 +215,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Translation: ...
@overload
@@ -232,7 +232,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> TranslationVerbose: ...
@overload
@@ -249,7 +249,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str: ...
async def create(
@@ -265,7 +265,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Translation | TranslationVerbose | str:
"""
Translates audio into English.
diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py
index 08b3754ed7..9e7381a30f 100644
--- a/src/openai/resources/batches.py
+++ b/src/openai/resources/batches.py
@@ -5,7 +5,7 @@
from typing import Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import batch_list_params, batch_create_params
@@ -66,7 +66,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Batch:
"""
Creates and executes a batch from an uploaded file of requests
@@ -141,7 +141,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Batch:
"""
Retrieves a batch.
@@ -179,7 +179,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[Batch]:
"""List your organization's batches.
@@ -231,7 +231,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Batch:
"""Cancels an in-progress batch.
@@ -307,7 +307,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Batch:
"""
Creates and executes a batch from an uploaded file of requests
@@ -382,7 +382,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Batch:
"""
Retrieves a batch.
@@ -420,7 +420,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Batch, AsyncCursorPage[Batch]]:
"""List your organization's batches.
@@ -472,7 +472,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Batch:
"""Cancels an in-progress batch.
diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py
index ea536d29e6..6c67501a07 100644
--- a/src/openai/resources/beta/assistants.py
+++ b/src/openai/resources/beta/assistants.py
@@ -6,7 +6,7 @@
from typing import Union, Iterable, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -74,7 +74,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Assistant:
"""
Create an assistant with a model and instructions.
@@ -194,7 +194,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Assistant:
"""
Retrieves an assistant.
@@ -291,7 +291,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Assistant:
"""Modifies an assistant.
@@ -417,7 +417,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[Assistant]:
"""Returns a list of assistants.
@@ -481,7 +481,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AssistantDeleted:
"""
Delete an assistant.
@@ -553,7 +553,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Assistant:
"""
Create an assistant with a model and instructions.
@@ -673,7 +673,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Assistant:
"""
Retrieves an assistant.
@@ -770,7 +770,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Assistant:
"""Modifies an assistant.
@@ -896,7 +896,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Assistant, AsyncCursorPage[Assistant]]:
"""Returns a list of assistants.
@@ -960,7 +960,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AssistantDeleted:
"""
Delete an assistant.
diff --git a/src/openai/resources/beta/chatkit/sessions.py b/src/openai/resources/beta/chatkit/sessions.py
index 41906ad7f7..6b02637bec 100644
--- a/src/openai/resources/beta/chatkit/sessions.py
+++ b/src/openai/resources/beta/chatkit/sessions.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -60,7 +60,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatSession:
"""
Create a ChatKit session.
@@ -118,7 +118,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatSession:
"""
Cancel an active ChatKit session and return its most recent metadata.
@@ -183,7 +183,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatSession:
"""
Create a ChatKit session.
@@ -241,7 +241,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatSession:
"""
Cancel an active ChatKit session and return its most recent metadata.
diff --git a/src/openai/resources/beta/chatkit/threads.py b/src/openai/resources/beta/chatkit/threads.py
index 42d17a64d5..28c493a7eb 100644
--- a/src/openai/resources/beta/chatkit/threads.py
+++ b/src/openai/resources/beta/chatkit/threads.py
@@ -5,7 +5,7 @@
from typing import Any, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -52,7 +52,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatKitThread:
"""
Retrieve a ChatKit thread by its identifier.
@@ -94,7 +94,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ChatKitThread]:
"""
List ChatKit threads with optional pagination and user filters.
@@ -154,7 +154,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ThreadDeleteResponse:
"""
Delete a ChatKit thread along with its items and stored attachments.
@@ -196,7 +196,7 @@ def list_items(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[Data]:
"""
List items that belong to a ChatKit thread.
@@ -275,7 +275,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatKitThread:
"""
Retrieve a ChatKit thread by its identifier.
@@ -317,7 +317,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ChatKitThread, AsyncConversationCursorPage[ChatKitThread]]:
"""
List ChatKit threads with optional pagination and user filters.
@@ -377,7 +377,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ThreadDeleteResponse:
"""
Delete a ChatKit thread along with its items and stored attachments.
@@ -419,7 +419,7 @@ def list_items(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Data, AsyncConversationCursorPage[Data]]:
"""
List items that belong to a ChatKit thread.
diff --git a/src/openai/resources/beta/realtime/realtime.py b/src/openai/resources/beta/realtime/realtime.py
index 98b717a184..6d1ef956ed 100644
--- a/src/openai/resources/beta/realtime/realtime.py
+++ b/src/openai/resources/beta/realtime/realtime.py
@@ -8,7 +8,7 @@
from typing import TYPE_CHECKING, Any, Iterator, cast
from typing_extensions import AsyncIterator
-import httpx
+import httpx2
from pydantic import BaseModel
from .sessions import (
@@ -394,7 +394,7 @@ async def __aenter__(self) -> AsyncRealtimeConnection:
enter = __aenter__
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
@@ -577,7 +577,7 @@ def __enter__(self) -> RealtimeConnection:
enter = __enter__
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
diff --git a/src/openai/resources/beta/realtime/sessions.py b/src/openai/resources/beta/realtime/sessions.py
index 9b85e02d17..50a38df7f8 100644
--- a/src/openai/resources/beta/realtime/sessions.py
+++ b/src/openai/resources/beta/realtime/sessions.py
@@ -5,7 +5,7 @@
from typing import List, Union, Iterable
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
@@ -75,7 +75,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> SessionCreateResponse:
"""
Create an ephemeral API token for use in client-side applications with the
@@ -259,7 +259,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> SessionCreateResponse:
"""
Create an ephemeral API token for use in client-side applications with the
diff --git a/src/openai/resources/beta/realtime/transcription_sessions.py b/src/openai/resources/beta/realtime/transcription_sessions.py
index 54fe7d5a6c..5ba79c7172 100644
--- a/src/openai/resources/beta/realtime/transcription_sessions.py
+++ b/src/openai/resources/beta/realtime/transcription_sessions.py
@@ -5,7 +5,7 @@
from typing import List
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
@@ -56,7 +56,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> TranscriptionSession:
"""
Create an ephemeral API token for use in client-side applications with the
@@ -169,7 +169,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> TranscriptionSession:
"""
Create an ephemeral API token for use in client-side applications with the
diff --git a/src/openai/resources/beta/responses/input_items.py b/src/openai/resources/beta/responses/input_items.py
index 325395dac4..219ea5cdd1 100644
--- a/src/openai/resources/beta/responses/input_items.py
+++ b/src/openai/resources/beta/responses/input_items.py
@@ -5,7 +5,7 @@
from typing import Any, List, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -56,7 +56,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[BetaResponseItem]:
"""
Returns a list of input items for a given response.
@@ -146,7 +146,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[BetaResponseItem, AsyncCursorPage[BetaResponseItem]]:
"""
Returns a list of input items for a given response.
diff --git a/src/openai/resources/beta/responses/input_tokens.py b/src/openai/resources/beta/responses/input_tokens.py
index a2af998fbb..cac50b1629 100644
--- a/src/openai/resources/beta/responses/input_tokens.py
+++ b/src/openai/resources/beta/responses/input_tokens.py
@@ -5,7 +5,7 @@
from typing import List, Union, Iterable, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -63,7 +63,7 @@ def count(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> InputTokenCountResponse:
"""
Returns input token counts of the request.
@@ -204,7 +204,7 @@ async def count(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> InputTokenCountResponse:
"""
Returns input token counts of the request.
diff --git a/src/openai/resources/beta/responses/responses.py b/src/openai/resources/beta/responses/responses.py
index 7bf83d2a4c..2b4217db8f 100644
--- a/src/openai/resources/beta/responses/responses.py
+++ b/src/openai/resources/beta/responses/responses.py
@@ -10,7 +10,7 @@
from typing import TYPE_CHECKING, Any, Dict, List, Union, Callable, Iterable, Iterator, Optional, Awaitable, cast
from typing_extensions import Literal, AsyncIterator, overload
-import httpx
+import httpx2
from pydantic import BaseModel
from .... import _legacy_response
@@ -249,7 +249,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse:
"""Creates a model response.
@@ -638,7 +638,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[BetaResponseStreamEvent]:
"""Creates a model response.
@@ -1027,7 +1027,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | Stream[BetaResponseStreamEvent]:
"""Creates a model response.
@@ -1415,7 +1415,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | Stream[BetaResponseStreamEvent]:
extra_headers = {
**strip_not_given({"openai-beta": ",".join(str(e) for e in betas) if is_given(betas) else not_given}),
@@ -1489,7 +1489,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse:
"""
Retrieves a model response with the given ID.
@@ -1539,7 +1539,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[BetaResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -1589,7 +1589,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | Stream[BetaResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -1638,7 +1638,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | Stream[BetaResponseStreamEvent]:
if not response_id:
raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}")
@@ -1679,7 +1679,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Deletes a model response with the given ID.
@@ -1722,7 +1722,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse:
"""Cancels a model response with the given ID.
@@ -1878,7 +1878,7 @@ def compact(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaCompactedResponse:
"""Compact a conversation.
@@ -2177,7 +2177,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse:
"""Creates a model response.
@@ -2566,7 +2566,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[BetaResponseStreamEvent]:
"""Creates a model response.
@@ -2955,7 +2955,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | AsyncStream[BetaResponseStreamEvent]:
"""Creates a model response.
@@ -3343,7 +3343,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | AsyncStream[BetaResponseStreamEvent]:
extra_headers = {
**strip_not_given({"openai-beta": ",".join(str(e) for e in betas) if is_given(betas) else not_given}),
@@ -3417,7 +3417,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse:
"""
Retrieves a model response with the given ID.
@@ -3467,7 +3467,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[BetaResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -3517,7 +3517,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | AsyncStream[BetaResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -3566,7 +3566,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse | AsyncStream[BetaResponseStreamEvent]:
if not response_id:
raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}")
@@ -3607,7 +3607,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Deletes a model response with the given ID.
@@ -3650,7 +3650,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaResponse:
"""Cancels a model response with the given ID.
@@ -3806,7 +3806,7 @@ async def compact(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> BetaCompactedResponse:
"""Compact a conversation.
@@ -4486,7 +4486,7 @@ async def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> Async
**self.__websocket_connection_options,
)
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
@@ -4931,7 +4931,7 @@ def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> WebSocketCo
**self.__websocket_connection_options,
)
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py
index c02e3191fd..66f57f9488 100644
--- a/src/openai/resources/beta/threads/messages.py
+++ b/src/openai/resources/beta/threads/messages.py
@@ -6,7 +6,7 @@
from typing import Union, Iterable, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -64,7 +64,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Message:
"""
Create a message.
@@ -132,7 +132,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Message:
"""
Retrieve a message.
@@ -175,7 +175,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Message:
"""
Modifies a message.
@@ -229,7 +229,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[Message]:
"""
Returns a list of messages for a given thread.
@@ -298,7 +298,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> MessageDeleted:
"""
Deletes a message.
@@ -366,7 +366,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Message:
"""
Create a message.
@@ -434,7 +434,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Message:
"""
Retrieve a message.
@@ -477,7 +477,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Message:
"""
Modifies a message.
@@ -531,7 +531,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Message, AsyncCursorPage[Message]]:
"""
Returns a list of messages for a given thread.
@@ -600,7 +600,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> MessageDeleted:
"""
Deletes a message.
diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py
index f1b00f8ede..5321b02c5a 100644
--- a/src/openai/resources/beta/threads/runs/runs.py
+++ b/src/openai/resources/beta/threads/runs/runs.py
@@ -7,7 +7,7 @@
from functools import partial
from typing_extensions import Literal, overload
-import httpx
+import httpx2
from ..... import _legacy_response
from .steps import (
@@ -115,7 +115,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Create a run.
@@ -266,7 +266,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[AssistantStreamEvent]:
"""
Create a run.
@@ -417,7 +417,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | Stream[AssistantStreamEvent]:
"""
Create a run.
@@ -568,7 +568,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | Stream[AssistantStreamEvent]:
if not thread_id:
raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}")
@@ -622,7 +622,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Retrieves a run.
@@ -665,7 +665,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Modifies a run.
@@ -718,7 +718,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[Run]:
"""
Returns a list of runs belonging to a thread.
@@ -784,7 +784,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Cancels a run that is `in_progress`.
@@ -843,7 +843,7 @@ def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Run:
"""
A helper to create a run an poll for a terminal state. More information on Run
@@ -913,7 +913,7 @@ def create_and_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler]:
"""Create a Run stream"""
...
@@ -946,7 +946,7 @@ def create_and_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandlerT]:
"""Create a Run stream"""
...
@@ -978,7 +978,7 @@ def create_and_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]:
"""Create a Run stream"""
if not thread_id:
@@ -1036,7 +1036,7 @@ def poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
poll_interval_ms: int | Omit = omit,
) -> Run:
"""
@@ -1102,7 +1102,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler]:
"""Create a Run stream"""
...
@@ -1136,7 +1136,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandlerT]:
"""Create a Run stream"""
...
@@ -1169,7 +1169,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]:
"""Create a Run stream"""
if not thread_id:
@@ -1234,7 +1234,7 @@ def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
When a run has the `status: "requires_action"` and `required_action.type` is
@@ -1273,7 +1273,7 @@ def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[AssistantStreamEvent]:
"""
When a run has the `status: "requires_action"` and `required_action.type` is
@@ -1312,7 +1312,7 @@ def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | Stream[AssistantStreamEvent]:
"""
When a run has the `status: "requires_action"` and `required_action.type` is
@@ -1352,7 +1352,7 @@ def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | Stream[AssistantStreamEvent]:
if not thread_id:
raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}")
@@ -1396,7 +1396,7 @@ def submit_tool_outputs_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Run:
"""
A helper to submit a tool output to a run and poll for a terminal run state.
@@ -1436,7 +1436,7 @@ def submit_tool_outputs_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler]:
"""
Submit the tool outputs from a previous run and stream the run to a terminal
@@ -1459,7 +1459,7 @@ def submit_tool_outputs_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandlerT]:
"""
Submit the tool outputs from a previous run and stream the run to a terminal
@@ -1481,7 +1481,7 @@ def submit_tool_outputs_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]:
"""
Submit the tool outputs from a previous run and stream the run to a terminal
@@ -1580,7 +1580,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Create a run.
@@ -1731,7 +1731,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[AssistantStreamEvent]:
"""
Create a run.
@@ -1882,7 +1882,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | AsyncStream[AssistantStreamEvent]:
"""
Create a run.
@@ -2034,7 +2034,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | AsyncStream[AssistantStreamEvent]:
if not thread_id:
raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}")
@@ -2088,7 +2088,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Retrieves a run.
@@ -2131,7 +2131,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Modifies a run.
@@ -2184,7 +2184,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Run, AsyncCursorPage[Run]]:
"""
Returns a list of runs belonging to a thread.
@@ -2250,7 +2250,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Cancels a run that is `in_progress`.
@@ -2309,7 +2309,7 @@ async def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Run:
"""
A helper to create a run an poll for a terminal state. More information on Run
@@ -2378,7 +2378,7 @@ def create_and_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]:
"""Create a Run stream"""
...
@@ -2410,7 +2410,7 @@ def create_and_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]:
"""Create a Run stream"""
...
@@ -2441,7 +2441,7 @@ def create_and_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> (
AsyncAssistantStreamManager[AsyncAssistantEventHandler]
| AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]
@@ -2500,7 +2500,7 @@ async def poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
poll_interval_ms: int | Omit = omit,
) -> Run:
"""
@@ -2565,7 +2565,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]:
"""Create a Run stream"""
...
@@ -2599,7 +2599,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]:
"""Create a Run stream"""
...
@@ -2632,7 +2632,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> (
AsyncAssistantStreamManager[AsyncAssistantEventHandler]
| AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]
@@ -2699,7 +2699,7 @@ async def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
When a run has the `status: "requires_action"` and `required_action.type` is
@@ -2738,7 +2738,7 @@ async def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[AssistantStreamEvent]:
"""
When a run has the `status: "requires_action"` and `required_action.type` is
@@ -2777,7 +2777,7 @@ async def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | AsyncStream[AssistantStreamEvent]:
"""
When a run has the `status: "requires_action"` and `required_action.type` is
@@ -2817,7 +2817,7 @@ async def submit_tool_outputs(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | AsyncStream[AssistantStreamEvent]:
if not thread_id:
raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}")
@@ -2861,7 +2861,7 @@ async def submit_tool_outputs_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Run:
"""
A helper to submit a tool output to a run and poll for a terminal run state.
@@ -2901,7 +2901,7 @@ def submit_tool_outputs_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]:
"""
Submit the tool outputs from a previous run and stream the run to a terminal
@@ -2924,7 +2924,7 @@ def submit_tool_outputs_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]:
"""
Submit the tool outputs from a previous run and stream the run to a terminal
@@ -2946,7 +2946,7 @@ def submit_tool_outputs_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> (
AsyncAssistantStreamManager[AsyncAssistantEventHandler]
| AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]
diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py
index 56631966da..784c7f49b8 100644
--- a/src/openai/resources/beta/threads/runs/steps.py
+++ b/src/openai/resources/beta/threads/runs/steps.py
@@ -6,7 +6,7 @@
from typing import List
from typing_extensions import Literal
-import httpx
+import httpx2
from ..... import _legacy_response
from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -58,7 +58,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunStep:
"""
Retrieves a run step.
@@ -121,7 +121,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[RunStep]:
"""
Returns a list of run steps belonging to a run.
@@ -223,7 +223,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunStep:
"""
Retrieves a run step.
@@ -286,7 +286,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[RunStep, AsyncCursorPage[RunStep]]:
"""
Returns a list of run steps belonging to a run.
diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py
index 3932bd8789..8c568b19b4 100644
--- a/src/openai/resources/beta/threads/threads.py
+++ b/src/openai/resources/beta/threads/threads.py
@@ -7,7 +7,7 @@
from functools import partial
from typing_extensions import Literal, overload
-import httpx
+import httpx2
from .... import _legacy_response
from .messages import (
@@ -103,7 +103,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Thread:
"""
Create a thread.
@@ -163,7 +163,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Thread:
"""
Retrieves a thread.
@@ -204,7 +204,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Thread:
"""
Modifies a thread.
@@ -262,7 +262,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ThreadDeleted:
"""
Delete a thread.
@@ -317,7 +317,7 @@ def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Create a thread and run it in one request.
@@ -451,7 +451,7 @@ def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[AssistantStreamEvent]:
"""
Create a thread and run it in one request.
@@ -585,7 +585,7 @@ def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | Stream[AssistantStreamEvent]:
"""
Create a thread and run it in one request.
@@ -720,7 +720,7 @@ def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | Stream[AssistantStreamEvent]:
extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})}
return self._post(
@@ -785,7 +785,7 @@ def create_and_run_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Run:
"""
A helper to create a thread, start a run and then poll for a terminal state.
@@ -840,7 +840,7 @@ def create_and_run_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler]:
"""Create a thread and stream the run back"""
...
@@ -870,7 +870,7 @@ def create_and_run_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandlerT]:
"""Create a thread and stream the run back"""
...
@@ -899,7 +899,7 @@ def create_and_run_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]:
"""Create a thread and stream the run back"""
extra_headers = {
@@ -990,7 +990,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Thread:
"""
Create a thread.
@@ -1050,7 +1050,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Thread:
"""
Retrieves a thread.
@@ -1091,7 +1091,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Thread:
"""
Modifies a thread.
@@ -1149,7 +1149,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ThreadDeleted:
"""
Delete a thread.
@@ -1204,7 +1204,7 @@ async def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run:
"""
Create a thread and run it in one request.
@@ -1338,7 +1338,7 @@ async def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[AssistantStreamEvent]:
"""
Create a thread and run it in one request.
@@ -1472,7 +1472,7 @@ async def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | AsyncStream[AssistantStreamEvent]:
"""
Create a thread and run it in one request.
@@ -1607,7 +1607,7 @@ async def create_and_run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Run | AsyncStream[AssistantStreamEvent]:
extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})}
return await self._post(
@@ -1672,7 +1672,7 @@ async def create_and_run_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Run:
"""
A helper to create a thread, start a run and then poll for a terminal state.
@@ -1729,7 +1729,7 @@ def create_and_run_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]:
"""Create a thread and stream the run back"""
...
@@ -1759,7 +1759,7 @@ def create_and_run_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]:
"""Create a thread and stream the run back"""
...
@@ -1788,7 +1788,7 @@ def create_and_run_stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> (
AsyncAssistantStreamManager[AsyncAssistantEventHandler]
| AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]
diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py
index f2fda25efb..a2e36b6ad2 100644
--- a/src/openai/resources/chat/completions/completions.py
+++ b/src/openai/resources/chat/completions/completions.py
@@ -7,7 +7,7 @@
from functools import partial
from typing_extensions import Literal, overload
-import httpx
+import httpx2
import pydantic
from .... import _legacy_response
@@ -132,7 +132,7 @@ def parse(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ParsedChatCompletion[ResponseFormatT]:
"""Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types
& returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class.
@@ -294,7 +294,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion:
"""
**Starting a new project?** We recommend trying
@@ -626,7 +626,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[ChatCompletionChunk]:
"""
**Starting a new project?** We recommend trying
@@ -958,7 +958,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion | Stream[ChatCompletionChunk]:
"""
**Starting a new project?** We recommend trying
@@ -1290,7 +1290,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion | Stream[ChatCompletionChunk]:
validate_response_format(response_format)
return self._post(
@@ -1360,7 +1360,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion:
"""Get a stored chat completion.
@@ -1400,7 +1400,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion:
"""Modify a stored chat completion.
@@ -1452,7 +1452,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[ChatCompletion]:
"""List stored Chat Completions.
@@ -1514,7 +1514,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletionDeleted:
"""Delete a stored chat completion.
@@ -1588,7 +1588,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletionStreamManager[ResponseFormatT]:
"""Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API
and automatic accumulation of each delta.
@@ -1743,7 +1743,7 @@ async def parse(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ParsedChatCompletion[ResponseFormatT]:
"""Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types
& returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class.
@@ -1905,7 +1905,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion:
"""
**Starting a new project?** We recommend trying
@@ -2237,7 +2237,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[ChatCompletionChunk]:
"""
**Starting a new project?** We recommend trying
@@ -2569,7 +2569,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion | AsyncStream[ChatCompletionChunk]:
"""
**Starting a new project?** We recommend trying
@@ -2901,7 +2901,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion | AsyncStream[ChatCompletionChunk]:
validate_response_format(response_format)
return await self._post(
@@ -2971,7 +2971,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion:
"""Get a stored chat completion.
@@ -3011,7 +3011,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletion:
"""Modify a stored chat completion.
@@ -3063,7 +3063,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ChatCompletion, AsyncCursorPage[ChatCompletion]]:
"""List stored Chat Completions.
@@ -3125,7 +3125,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ChatCompletionDeleted:
"""Delete a stored chat completion.
@@ -3199,7 +3199,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncChatCompletionStreamManager[ResponseFormatT]:
"""Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API
and automatic accumulation of each delta.
diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py
index e5283da4ae..a18c162dae 100644
--- a/src/openai/resources/chat/completions/messages.py
+++ b/src/openai/resources/chat/completions/messages.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -56,7 +56,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[ChatCompletionStoreMessage]:
"""Get the messages in a stored chat completion.
@@ -139,7 +139,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ChatCompletionStoreMessage, AsyncCursorPage[ChatCompletionStoreMessage]]:
"""Get the messages in a stored chat completion.
diff --git a/src/openai/resources/completions.py b/src/openai/resources/completions.py
index 09d3c63023..160732d9a0 100644
--- a/src/openai/resources/completions.py
+++ b/src/openai/resources/completions.py
@@ -5,7 +5,7 @@
from typing import Dict, Union, Iterable, Optional
from typing_extensions import Literal, overload
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import completion_create_params
@@ -75,7 +75,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Completion:
"""
Creates a completion for the provided prompt and parameters.
@@ -233,7 +233,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[Completion]:
"""
Creates a completion for the provided prompt and parameters.
@@ -391,7 +391,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Completion | Stream[Completion]:
"""
Creates a completion for the provided prompt and parameters.
@@ -549,7 +549,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Completion | Stream[Completion]:
return self._post(
"/completions",
@@ -642,7 +642,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Completion:
"""
Creates a completion for the provided prompt and parameters.
@@ -800,7 +800,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[Completion]:
"""
Creates a completion for the provided prompt and parameters.
@@ -958,7 +958,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Completion | AsyncStream[Completion]:
"""
Creates a completion for the provided prompt and parameters.
@@ -1116,7 +1116,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Completion | AsyncStream[Completion]:
return await self._post(
"/completions",
diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py
index 53da2fc4c0..f0f0c2f506 100644
--- a/src/openai/resources/containers/containers.py
+++ b/src/openai/resources/containers/containers.py
@@ -5,7 +5,7 @@
from typing import Iterable
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ...types import container_list_params, container_create_params
@@ -69,7 +69,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ContainerCreateResponse:
"""
Create Container
@@ -127,7 +127,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ContainerRetrieveResponse:
"""
Retrieve Container
@@ -167,7 +167,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[ContainerListResponse]:
"""List Containers
@@ -226,7 +226,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Delete Container
@@ -294,7 +294,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ContainerCreateResponse:
"""
Create Container
@@ -352,7 +352,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ContainerRetrieveResponse:
"""
Retrieve Container
@@ -392,7 +392,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ContainerListResponse, AsyncCursorPage[ContainerListResponse]]:
"""List Containers
@@ -451,7 +451,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Delete Container
diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py
index 235722ac89..826aab8af5 100644
--- a/src/openai/resources/containers/files/content.py
+++ b/src/openai/resources/containers/files/content.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Query, Headers, NotGiven, not_given
@@ -50,7 +50,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Retrieve Container File Content
@@ -114,7 +114,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Retrieve Container File Content
diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py
index 56026a9eab..5511c443ef 100644
--- a/src/openai/resources/containers/files/files.py
+++ b/src/openai/resources/containers/files/files.py
@@ -5,7 +5,7 @@
from typing import Mapping, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from .content import (
@@ -67,7 +67,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileCreateResponse:
"""
Create a Container File
@@ -127,7 +127,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileRetrieveResponse:
"""
Retrieve Container File
@@ -169,7 +169,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[FileListResponse]:
"""List Container files
@@ -228,7 +228,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Delete Container File
@@ -295,7 +295,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileCreateResponse:
"""
Create a Container File
@@ -355,7 +355,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileRetrieveResponse:
"""
Retrieve Container File
@@ -397,7 +397,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[FileListResponse, AsyncCursorPage[FileListResponse]]:
"""List Container files
@@ -456,7 +456,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Delete Container File
diff --git a/src/openai/resources/content_provenance_checks.py b/src/openai/resources/content_provenance_checks.py
index 4660972336..dbdc7d5b2f 100644
--- a/src/openai/resources/content_provenance_checks.py
+++ b/src/openai/resources/content_provenance_checks.py
@@ -4,7 +4,7 @@
from typing import Mapping, cast
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import content_provenance_check_create_params
@@ -49,7 +49,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ContentProvenanceCheck:
"""
Check whether an image or audio file contains known OpenAI provenance signals.
@@ -123,7 +123,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ContentProvenanceCheck:
"""
Check whether an image or audio file contains known OpenAI provenance signals.
diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py
index f69e73c4c0..bc62041c9e 100644
--- a/src/openai/resources/conversations/conversations.py
+++ b/src/openai/resources/conversations/conversations.py
@@ -4,7 +4,7 @@
from typing import Iterable, Optional
-import httpx
+import httpx2
from ... import _legacy_response
from .items import (
@@ -67,7 +67,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Create a conversation.
@@ -119,7 +119,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Get a conversation
@@ -157,7 +157,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Update a conversation
@@ -202,7 +202,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ConversationDeletedResource:
"""Delete a conversation.
@@ -269,7 +269,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Create a conversation.
@@ -321,7 +321,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Get a conversation
@@ -359,7 +359,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Update a conversation
@@ -406,7 +406,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ConversationDeletedResource:
"""Delete a conversation.
diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py
index 339c145ca3..9ae0d2a30b 100644
--- a/src/openai/resources/conversations/items.py
+++ b/src/openai/resources/conversations/items.py
@@ -5,7 +5,7 @@
from typing import Any, List, Iterable, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -58,7 +58,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ConversationItemList:
"""
Create items in a conversation with the given ID.
@@ -105,7 +105,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ConversationItem:
"""
Get a single item from a conversation with the given IDs.
@@ -158,7 +158,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[ConversationItem]:
"""
List all items for a conversation with the given ID.
@@ -235,7 +235,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Delete an item from a conversation with the given IDs.
@@ -301,7 +301,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ConversationItemList:
"""
Create items in a conversation with the given ID.
@@ -348,7 +348,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ConversationItem:
"""
Get a single item from a conversation with the given IDs.
@@ -401,7 +401,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ConversationItem, AsyncConversationCursorPage[ConversationItem]]:
"""
List all items for a conversation with the given ID.
@@ -478,7 +478,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Conversation:
"""
Delete an item from a conversation with the given IDs.
diff --git a/src/openai/resources/embeddings.py b/src/openai/resources/embeddings.py
index 146d5531f6..5b5a018de5 100644
--- a/src/openai/resources/embeddings.py
+++ b/src/openai/resources/embeddings.py
@@ -7,7 +7,7 @@
from typing import Union, Iterable, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import embedding_create_params
@@ -61,7 +61,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> CreateEmbeddingResponse:
"""
Creates an embedding vector representing the input text.
@@ -185,7 +185,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> CreateEmbeddingResponse:
"""
Creates an embedding vector representing the input text.
diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py
index c7843d7aff..9ebed4a1b6 100644
--- a/src/openai/resources/evals/evals.py
+++ b/src/openai/resources/evals/evals.py
@@ -5,7 +5,7 @@
from typing import Iterable, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ...types import eval_list_params, eval_create_params, eval_update_params
@@ -73,7 +73,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalCreateResponse:
"""
Create the structure of an evaluation that can be used to test a model's
@@ -139,7 +139,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalRetrieveResponse:
"""
Get an evaluation by ID.
@@ -178,7 +178,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalUpdateResponse:
"""
Update certain properties of an evaluation.
@@ -234,7 +234,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[EvalListResponse]:
"""
List evaluations for a project.
@@ -289,7 +289,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalDeleteResponse:
"""
Delete an evaluation.
@@ -357,7 +357,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalCreateResponse:
"""
Create the structure of an evaluation that can be used to test a model's
@@ -423,7 +423,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalRetrieveResponse:
"""
Get an evaluation by ID.
@@ -462,7 +462,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalUpdateResponse:
"""
Update certain properties of an evaluation.
@@ -518,7 +518,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[EvalListResponse, AsyncCursorPage[EvalListResponse]]:
"""
List evaluations for a project.
@@ -573,7 +573,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> EvalDeleteResponse:
"""
Delete an evaluation.
diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py
index aac2c11e55..4a26ccf26c 100644
--- a/src/openai/resources/evals/runs/output_items.py
+++ b/src/openai/resources/evals/runs/output_items.py
@@ -4,7 +4,7 @@
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -54,7 +54,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OutputItemRetrieveResponse:
"""
Get an evaluation run output item by ID.
@@ -105,7 +105,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[OutputItemListResponse]:
"""
Get a list of output items for an evaluation run.
@@ -189,7 +189,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> OutputItemRetrieveResponse:
"""
Get an evaluation run output item by ID.
@@ -240,7 +240,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[OutputItemListResponse, AsyncCursorPage[OutputItemListResponse]]:
"""
Get a list of output items for an evaluation run.
diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py
index c848df91d4..f57db15977 100644
--- a/src/openai/resources/evals/runs/runs.py
+++ b/src/openai/resources/evals/runs/runs.py
@@ -5,7 +5,7 @@
from typing import Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -73,7 +73,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunCreateResponse:
"""
Kicks off a new run for a given evaluation, specifying the data source, and what
@@ -132,7 +132,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunRetrieveResponse:
"""
Get an evaluation run by ID.
@@ -175,7 +175,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[RunListResponse]:
"""
Get a list of runs for an evaluation.
@@ -233,7 +233,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunDeleteResponse:
"""
Delete an eval run.
@@ -273,7 +273,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunCancelResponse:
"""
Cancel an ongoing evaluation run.
@@ -343,7 +343,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunCreateResponse:
"""
Kicks off a new run for a given evaluation, specifying the data source, and what
@@ -402,7 +402,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunRetrieveResponse:
"""
Get an evaluation run by ID.
@@ -445,7 +445,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[RunListResponse, AsyncCursorPage[RunListResponse]]:
"""
Get a list of runs for an evaluation.
@@ -503,7 +503,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunDeleteResponse:
"""
Delete an eval run.
@@ -543,7 +543,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> RunCancelResponse:
"""
Cancel an ongoing evaluation run.
diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py
index 74b4d1c06a..19db280256 100644
--- a/src/openai/resources/files.py
+++ b/src/openai/resources/files.py
@@ -7,7 +7,7 @@
from typing import Mapping, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import FilePurpose, file_list_params, file_create_params
@@ -68,7 +68,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileObject:
"""Upload a file that can be used across various endpoints.
@@ -160,7 +160,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileObject:
"""
Returns information about a specific file.
@@ -200,7 +200,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[FileObject]:
"""Returns a list of files.
@@ -259,7 +259,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileDeleted:
"""
Delete a file and remove it from all vector stores.
@@ -296,7 +296,7 @@ def content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Returns the contents of the specified file.
@@ -335,7 +335,7 @@ def retrieve_content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str:
"""
Returns the contents of the specified file.
@@ -422,7 +422,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileObject:
"""Upload a file that can be used across various endpoints.
@@ -514,7 +514,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileObject:
"""
Returns information about a specific file.
@@ -554,7 +554,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[FileObject, AsyncCursorPage[FileObject]]:
"""Returns a list of files.
@@ -613,7 +613,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FileDeleted:
"""
Delete a file and remove it from all vector stores.
@@ -650,7 +650,7 @@ async def content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Returns the contents of the specified file.
@@ -689,7 +689,7 @@ async def retrieve_content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> str:
"""
Returns the contents of the specified file.
diff --git a/src/openai/resources/fine_tuning/alpha/graders.py b/src/openai/resources/fine_tuning/alpha/graders.py
index dd31605843..d7fa11ec50 100644
--- a/src/openai/resources/fine_tuning/alpha/graders.py
+++ b/src/openai/resources/fine_tuning/alpha/graders.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -51,7 +51,7 @@ def run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GraderRunResponse:
"""
Run a grader.
@@ -106,7 +106,7 @@ def validate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GraderValidateResponse:
"""
Validate a grader.
@@ -169,7 +169,7 @@ async def run(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GraderRunResponse:
"""
Run a grader.
@@ -224,7 +224,7 @@ async def validate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> GraderValidateResponse:
"""
Validate a grader.
diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py
index 8337362ba8..7ac669da31 100644
--- a/src/openai/resources/fine_tuning/checkpoints/permissions.py
+++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py
@@ -5,7 +5,7 @@
import typing_extensions
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
@@ -60,7 +60,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[PermissionCreateResponse]:
"""
**NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys).
@@ -115,7 +115,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> PermissionRetrieveResponse:
"""
**NOTE:** This endpoint requires an [admin API key](../admin-api-keys).
@@ -181,7 +181,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[PermissionListResponse]:
"""
**NOTE:** This endpoint requires an [admin API key](../admin-api-keys).
@@ -245,7 +245,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> PermissionDeleteResponse:
"""
**NOTE:** This endpoint requires an [admin API key](../admin-api-keys).
@@ -317,7 +317,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[PermissionCreateResponse, AsyncPage[PermissionCreateResponse]]:
"""
**NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys).
@@ -372,7 +372,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> PermissionRetrieveResponse:
"""
**NOTE:** This endpoint requires an [admin API key](../admin-api-keys).
@@ -438,7 +438,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[PermissionListResponse, AsyncConversationCursorPage[PermissionListResponse]]:
"""
**NOTE:** This endpoint requires an [admin API key](../admin-api-keys).
@@ -502,7 +502,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> PermissionDeleteResponse:
"""
**NOTE:** This endpoint requires an [admin API key](../admin-api-keys).
diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py
index 49dd593287..2476b66014 100644
--- a/src/openai/resources/fine_tuning/jobs/checkpoints.py
+++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -54,7 +54,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[FineTuningJobCheckpoint]:
"""
List checkpoints for a fine-tuning job.
@@ -128,7 +128,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[FineTuningJobCheckpoint, AsyncCursorPage[FineTuningJobCheckpoint]]:
"""
List checkpoints for a fine-tuning job.
diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py
index ef6e54bed0..a6046cdd0f 100644
--- a/src/openai/resources/fine_tuning/jobs/jobs.py
+++ b/src/openai/resources/fine_tuning/jobs/jobs.py
@@ -5,7 +5,7 @@
from typing import Dict, Union, Iterable, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -78,7 +78,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Creates a fine-tuning job which begins the process of creating a new model from
@@ -193,7 +193,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Get info about a fine-tuning job.
@@ -234,7 +234,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[FineTuningJob]:
"""
List your organization's fine-tuning jobs
@@ -285,7 +285,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Immediately cancel a fine-tune job.
@@ -324,7 +324,7 @@ def list_events(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[FineTuningJobEvent]:
"""
Get status updates for a fine-tuning job.
@@ -373,7 +373,7 @@ def pause(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Pause a fine-tune job.
@@ -410,7 +410,7 @@ def resume(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Resume a fine-tune job.
@@ -483,7 +483,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Creates a fine-tuning job which begins the process of creating a new model from
@@ -598,7 +598,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Get info about a fine-tuning job.
@@ -639,7 +639,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[FineTuningJob, AsyncCursorPage[FineTuningJob]]:
"""
List your organization's fine-tuning jobs
@@ -690,7 +690,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Immediately cancel a fine-tune job.
@@ -729,7 +729,7 @@ def list_events(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[FineTuningJobEvent, AsyncCursorPage[FineTuningJobEvent]]:
"""
Get status updates for a fine-tuning job.
@@ -778,7 +778,7 @@ async def pause(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Pause a fine-tune job.
@@ -815,7 +815,7 @@ async def resume(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> FineTuningJob:
"""
Resume a fine-tune job.
diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py
index d4bcbcafba..e0aad166fc 100644
--- a/src/openai/resources/images.py
+++ b/src/openai/resources/images.py
@@ -5,7 +5,7 @@
from typing import Union, Mapping, Optional, cast
from typing_extensions import Literal, overload
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import image_edit_params, image_generate_params, image_create_variation_params
@@ -61,7 +61,7 @@ def create_variation(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse:
"""Creates a variation of a given image.
@@ -150,7 +150,7 @@ def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse:
"""Creates an edited or extended image given one or more source images and a
prompt.
@@ -280,7 +280,7 @@ def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[ImageEditStreamEvent]:
"""Creates an edited or extended image given one or more source images and a
prompt.
@@ -410,7 +410,7 @@ def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | Stream[ImageEditStreamEvent]:
"""Creates an edited or extended image given one or more source images and a
prompt.
@@ -540,7 +540,7 @@ def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | Stream[ImageEditStreamEvent]:
body = deepcopy_with_paths(
{
@@ -614,7 +614,7 @@ def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse:
"""
Creates an image given a prompt.
@@ -740,7 +740,7 @@ def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[ImageGenStreamEvent]:
"""
Creates an image given a prompt.
@@ -866,7 +866,7 @@ def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | Stream[ImageGenStreamEvent]:
"""
Creates an image given a prompt.
@@ -992,7 +992,7 @@ def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | Stream[ImageGenStreamEvent]:
return self._post(
"/images/generations",
@@ -1066,7 +1066,7 @@ async def create_variation(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse:
"""Creates a variation of a given image.
@@ -1155,7 +1155,7 @@ async def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse:
"""Creates an edited or extended image given one or more source images and a
prompt.
@@ -1285,7 +1285,7 @@ async def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[ImageEditStreamEvent]:
"""Creates an edited or extended image given one or more source images and a
prompt.
@@ -1415,7 +1415,7 @@ async def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]:
"""Creates an edited or extended image given one or more source images and a
prompt.
@@ -1545,7 +1545,7 @@ async def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]:
body = deepcopy_with_paths(
{
@@ -1619,7 +1619,7 @@ async def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse:
"""
Creates an image given a prompt.
@@ -1745,7 +1745,7 @@ async def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[ImageGenStreamEvent]:
"""
Creates an image given a prompt.
@@ -1871,7 +1871,7 @@ async def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]:
"""
Creates an image given a prompt.
@@ -1997,7 +1997,7 @@ async def generate(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]:
return await self._post(
"/images/generations",
diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py
index acd55efbed..41152fb91f 100644
--- a/src/openai/resources/models.py
+++ b/src/openai/resources/models.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from .. import _legacy_response
from .._types import Body, Query, Headers, NotGiven, not_given
@@ -52,7 +52,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Model:
"""
Retrieves a model instance, providing basic information about the model such as
@@ -89,7 +89,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[Model]:
"""
Lists the currently available models, and provides basic information about each
@@ -117,7 +117,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ModelDeleted:
"""Delete a fine-tuned model.
@@ -179,7 +179,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Model:
"""
Retrieves a model instance, providing basic information about the model such as
@@ -216,7 +216,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Model, AsyncPage[Model]]:
"""
Lists the currently available models, and provides basic information about each
@@ -244,7 +244,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ModelDeleted:
"""Delete a fine-tuned model.
diff --git a/src/openai/resources/moderations.py b/src/openai/resources/moderations.py
index 35eec47206..b29de575f2 100644
--- a/src/openai/resources/moderations.py
+++ b/src/openai/resources/moderations.py
@@ -4,7 +4,7 @@
from typing import Union, Iterable
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import moderation_create_params
@@ -55,7 +55,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ModerationCreateResponse:
"""Classifies if text and/or image inputs are potentially harmful.
@@ -133,7 +133,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ModerationCreateResponse:
"""Classifies if text and/or image inputs are potentially harmful.
diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py
index d622dce409..3bc6817f5d 100644
--- a/src/openai/resources/realtime/calls.py
+++ b/src/openai/resources/realtime/calls.py
@@ -5,7 +5,7 @@
from typing import List, Union, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
@@ -69,7 +69,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Create a new Realtime API call over WebRTC and receive the SDP answer needed to
@@ -155,7 +155,7 @@ def accept(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Accept an incoming SIP call and configure the realtime session that will handle
@@ -285,7 +285,7 @@ def hangup(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
End an active Realtime API call, whether it was initiated over SIP or WebRTC.
@@ -324,7 +324,7 @@ def refer(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Transfer an active SIP call to a new destination using the SIP REFER verb.
@@ -367,7 +367,7 @@ def reject(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Decline an incoming SIP call by returning a SIP status code to the caller.
@@ -431,7 +431,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Create a new Realtime API call over WebRTC and receive the SDP answer needed to
@@ -517,7 +517,7 @@ async def accept(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Accept an incoming SIP call and configure the realtime session that will handle
@@ -647,7 +647,7 @@ async def hangup(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
End an active Realtime API call, whether it was initiated over SIP or WebRTC.
@@ -686,7 +686,7 @@ async def refer(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Transfer an active SIP call to a new destination using the SIP REFER verb.
@@ -729,7 +729,7 @@ async def reject(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Decline an incoming SIP call by returning a SIP status code to the caller.
diff --git a/src/openai/resources/realtime/client_secrets.py b/src/openai/resources/realtime/client_secrets.py
index f947712f2d..77c2753cdd 100644
--- a/src/openai/resources/realtime/client_secrets.py
+++ b/src/openai/resources/realtime/client_secrets.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -47,7 +47,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ClientSecretCreateResponse:
"""
Create a Realtime client secret with an associated session configuration.
@@ -133,7 +133,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> ClientSecretCreateResponse:
"""
Create a Realtime client secret with an associated session configuration.
diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py
index 8989d9448d..8e42e16870 100644
--- a/src/openai/resources/realtime/realtime.py
+++ b/src/openai/resources/realtime/realtime.py
@@ -10,7 +10,7 @@
from typing import TYPE_CHECKING, Any, Union, Callable, Iterator, Awaitable, cast
from typing_extensions import AsyncIterator
-import httpx
+import httpx2
from pydantic import BaseModel
from .calls import (
@@ -720,7 +720,7 @@ async def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> Async
**self.__websocket_connection_options,
)
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
@@ -1188,7 +1188,7 @@ def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> WebSocketCo
**self.__websocket_connection_options,
)
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py
index 9aaf553f22..7be6d24bd7 100644
--- a/src/openai/resources/responses/input_items.py
+++ b/src/openai/resources/responses/input_items.py
@@ -5,7 +5,7 @@
from typing import Any, List, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -55,7 +55,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[ResponseItem]:
"""
Returns a list of input items for a given response.
@@ -140,7 +140,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[ResponseItem, AsyncCursorPage[ResponseItem]]:
"""
Returns a list of input items for a given response.
diff --git a/src/openai/resources/responses/input_tokens.py b/src/openai/resources/responses/input_tokens.py
index 1d313d1190..d9f0cca458 100644
--- a/src/openai/resources/responses/input_tokens.py
+++ b/src/openai/resources/responses/input_tokens.py
@@ -5,7 +5,7 @@
from typing import Union, Iterable, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
@@ -63,7 +63,7 @@ def count(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> InputTokenCountResponse:
"""
Returns input token counts of the request.
@@ -199,7 +199,7 @@ async def count(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> InputTokenCountResponse:
"""
Returns input token counts of the request.
diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py
index 43c84769b0..bbb4a7a443 100644
--- a/src/openai/resources/responses/responses.py
+++ b/src/openai/resources/responses/responses.py
@@ -25,7 +25,7 @@
from functools import partial
from typing_extensions import Literal, overload
-import httpx
+import httpx2
from pydantic import BaseModel
from ... import _legacy_response
@@ -169,7 +169,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response:
"""Creates a model response.
@@ -450,7 +450,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[ResponseStreamEvent]:
"""Creates a model response.
@@ -731,7 +731,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | Stream[ResponseStreamEvent]:
"""Creates a model response.
@@ -1011,7 +1011,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | Stream[ResponseStreamEvent]:
return self._post(
"/responses",
@@ -1077,7 +1077,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> ResponseStreamManager[TextFormatT]: ...
@overload
@@ -1120,7 +1120,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> ResponseStreamManager[TextFormatT]: ...
def stream(
@@ -1164,7 +1164,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> ResponseStreamManager[TextFormatT]:
new_response_args = {
"input": input,
@@ -1328,7 +1328,7 @@ def parse(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> ParsedResponse[TextFormatT]:
if is_given(text_format):
if not text:
@@ -1414,7 +1414,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response: ...
@overload
@@ -1430,7 +1430,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Stream[ResponseStreamEvent]: ...
@overload
@@ -1446,7 +1446,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Response | Stream[ResponseStreamEvent]: ...
@overload
@@ -1462,7 +1462,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Response | Stream[ResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -1511,7 +1511,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Stream[ResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -1560,7 +1560,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | Stream[ResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -1608,7 +1608,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | Stream[ResponseStreamEvent]:
if not response_id:
raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}")
@@ -1644,7 +1644,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Deletes a model response with the given ID.
@@ -1682,7 +1682,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response:
"""Cancels a model response with the given ID.
@@ -1833,7 +1833,7 @@ def compact(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> CompactedResponse:
"""Compact a conversation.
@@ -2022,7 +2022,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response:
"""Creates a model response.
@@ -2303,7 +2303,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[ResponseStreamEvent]:
"""Creates a model response.
@@ -2584,7 +2584,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | AsyncStream[ResponseStreamEvent]:
"""Creates a model response.
@@ -2864,7 +2864,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | AsyncStream[ResponseStreamEvent]:
return await self._post(
"/responses",
@@ -2930,7 +2930,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncResponseStreamManager[TextFormatT]: ...
@overload
@@ -2973,7 +2973,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncResponseStreamManager[TextFormatT]: ...
def stream(
@@ -3017,7 +3017,7 @@ def stream(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncResponseStreamManager[TextFormatT]:
new_response_args = {
"input": input,
@@ -3180,7 +3180,7 @@ async def parse(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> ParsedResponse[TextFormatT]:
if is_given(text_format):
if not text:
@@ -3266,7 +3266,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response: ...
@overload
@@ -3282,7 +3282,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncStream[ResponseStreamEvent]: ...
@overload
@@ -3298,7 +3298,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Response | AsyncStream[ResponseStreamEvent]: ...
@overload
@@ -3314,7 +3314,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ timeout: float | httpx2.Timeout | None | NotGiven = NOT_GIVEN,
) -> Response | AsyncStream[ResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -3363,7 +3363,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncStream[ResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -3412,7 +3412,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | AsyncStream[ResponseStreamEvent]:
"""
Retrieves a model response with the given ID.
@@ -3460,7 +3460,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response | AsyncStream[ResponseStreamEvent]:
if not response_id:
raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}")
@@ -3496,7 +3496,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> None:
"""
Deletes a model response with the given ID.
@@ -3534,7 +3534,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Response:
"""Cancels a model response with the given ID.
@@ -3685,7 +3685,7 @@ async def compact(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> CompactedResponse:
"""Compact a conversation.
@@ -4405,7 +4405,7 @@ async def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> Async
**self.__websocket_connection_options,
)
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
@@ -4850,7 +4850,7 @@ def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> WebSocketCo
**self.__websocket_connection_options,
)
- def _prepare_url(self) -> httpx.URL:
+ def _prepare_url(self) -> httpx2.URL:
if self.__client.websocket_base_url is not None:
base_url = normalize_httpx_url(self.__client.websocket_base_url)
else:
diff --git a/src/openai/resources/skills/content.py b/src/openai/resources/skills/content.py
index eedbb90b23..91ac17d39f 100644
--- a/src/openai/resources/skills/content.py
+++ b/src/openai/resources/skills/content.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from ... import _legacy_response
from ..._types import Body, Query, Headers, NotGiven, not_given
@@ -49,7 +49,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Download a skill zip bundle by its ID.
@@ -108,7 +108,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Download a skill zip bundle by its ID.
diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py
index 0ad1b42587..7c840a901c 100644
--- a/src/openai/resources/skills/skills.py
+++ b/src/openai/resources/skills/skills.py
@@ -5,7 +5,7 @@
from typing import Union, Mapping, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from ...types import skill_list_params, skill_create_params, skill_update_params
@@ -86,7 +86,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Skill:
"""
Create a new skill.
@@ -132,7 +132,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Skill:
"""
Get a skill by its ID.
@@ -170,7 +170,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Skill:
"""
Update the default version pointer for a skill.
@@ -212,7 +212,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[Skill]:
"""
List all skills for the current project.
@@ -263,7 +263,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> DeletedSkill:
"""
Delete a skill by its ID.
@@ -329,7 +329,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Skill:
"""
Create a new skill.
@@ -375,7 +375,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Skill:
"""
Get a skill by its ID.
@@ -413,7 +413,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Skill:
"""
Update the default version pointer for a skill.
@@ -457,7 +457,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Skill, AsyncCursorPage[Skill]]:
"""
List all skills for the current project.
@@ -508,7 +508,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> DeletedSkill:
"""
Delete a skill by its ID.
diff --git a/src/openai/resources/skills/versions/content.py b/src/openai/resources/skills/versions/content.py
index c72c8c4f08..241b3f6e54 100644
--- a/src/openai/resources/skills/versions/content.py
+++ b/src/openai/resources/skills/versions/content.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-import httpx
+import httpx2
from .... import _legacy_response
from ...._types import Body, Query, Headers, NotGiven, not_given
@@ -50,7 +50,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Download a skill version zip bundle.
@@ -114,7 +114,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Download a skill version zip bundle.
diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py
index 17f85a13ec..b4efd79dfa 100644
--- a/src/openai/resources/skills/versions/versions.py
+++ b/src/openai/resources/skills/versions/versions.py
@@ -5,7 +5,7 @@
from typing import Union, Mapping, cast
from typing_extensions import Literal
-import httpx
+import httpx2
from .... import _legacy_response
from .content import (
@@ -76,7 +76,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SkillVersion:
"""
Create a new immutable skill version.
@@ -133,7 +133,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SkillVersion:
"""
Get a specific skill version.
@@ -177,7 +177,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[SkillVersion]:
"""
List skill versions for a skill.
@@ -230,7 +230,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> DeletedSkillVersion:
"""
Delete a skill version.
@@ -298,7 +298,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SkillVersion:
"""
Create a new immutable skill version.
@@ -355,7 +355,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SkillVersion:
"""
Get a specific skill version.
@@ -399,7 +399,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[SkillVersion, AsyncCursorPage[SkillVersion]]:
"""
List skill versions for a skill.
@@ -452,7 +452,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> DeletedSkillVersion:
"""
Delete a skill version.
diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py
index d04b037b44..f9c88c1cc5 100644
--- a/src/openai/resources/uploads/parts.py
+++ b/src/openai/resources/uploads/parts.py
@@ -4,7 +4,7 @@
from typing import Mapping, cast
-import httpx
+import httpx2
from ... import _legacy_response
from ..._files import deepcopy_with_paths
@@ -52,7 +52,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UploadPart:
"""
Adds a
@@ -133,7 +133,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> UploadPart:
"""
Adds a
diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py
index fa6b580df9..1ab8d8b8c6 100644
--- a/src/openai/resources/uploads/uploads.py
+++ b/src/openai/resources/uploads/uploads.py
@@ -10,7 +10,7 @@
from pathlib import Path
import anyio
-import httpx
+import httpx2
from ... import _legacy_response
from .parts import (
@@ -178,7 +178,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Upload:
"""
Creates an intermediate
@@ -260,7 +260,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Upload:
"""Cancels the Upload.
@@ -302,7 +302,7 @@ def complete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Upload:
"""
Completes the
@@ -506,7 +506,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Upload:
"""
Creates an intermediate
@@ -588,7 +588,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Upload:
"""Cancels the Upload.
@@ -630,7 +630,7 @@ async def complete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Upload:
"""
Completes the
diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py
index 6e48c2d07b..9bd5040172 100644
--- a/src/openai/resources/vector_stores/file_batches.py
+++ b/src/openai/resources/vector_stores/file_batches.py
@@ -7,7 +7,7 @@
from typing_extensions import Union, Literal
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
-import httpx
+import httpx2
import sniffio
from ... import _legacy_response
@@ -61,7 +61,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""
Create a vector store file batch.
@@ -132,7 +132,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""
Retrieves a vector store file batch.
@@ -177,7 +177,7 @@ def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""Cancel a vector store file batch.
@@ -228,7 +228,7 @@ def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""Create a vector store batch and poll until all files have been processed."""
batch = self.create(
@@ -264,7 +264,7 @@ def list_files(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[VectorStoreFile]:
"""
Returns a list of vector store files in a batch.
@@ -449,7 +449,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""
Create a vector store file batch.
@@ -520,7 +520,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""
Retrieves a vector store file batch.
@@ -565,7 +565,7 @@ async def cancel(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""Cancel a vector store file batch.
@@ -616,7 +616,7 @@ async def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileBatch:
"""Create a vector store batch and poll until all files have been processed."""
batch = await self.create(
@@ -652,7 +652,7 @@ def list_files(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]:
"""
Returns a list of vector store files in a batch.
diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py
index 69534b0c99..06ae07129d 100644
--- a/src/openai/resources/vector_stores/files.py
+++ b/src/openai/resources/vector_stores/files.py
@@ -5,7 +5,7 @@
from typing import TYPE_CHECKING, Dict, Union, Optional
from typing_extensions import Literal, assert_never
-import httpx
+import httpx2
from ... import _legacy_response
from ...types import FileChunkingStrategyParam
@@ -57,7 +57,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""
Create a vector store file by attaching a
@@ -121,7 +121,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""
Retrieves a vector store file.
@@ -165,7 +165,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""
Update attributes on a vector store file.
@@ -219,7 +219,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[VectorStoreFile]:
"""
Returns a list of vector store files.
@@ -287,7 +287,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileDeleted:
"""Delete a vector store file.
@@ -337,7 +337,7 @@ def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""Attach a file to the given vector store and wait for it to be processed."""
self.create(
@@ -442,7 +442,7 @@ def content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[FileContentResponse]:
"""
Retrieve the parsed contents of a vector store file.
@@ -511,7 +511,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""
Create a vector store file by attaching a
@@ -575,7 +575,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""
Retrieves a vector store file.
@@ -619,7 +619,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""
Update attributes on a vector store file.
@@ -673,7 +673,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]:
"""
Returns a list of vector store files.
@@ -741,7 +741,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFileDeleted:
"""Delete a vector store file.
@@ -791,7 +791,7 @@ async def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreFile:
"""Attach a file to the given vector store and wait for it to be processed."""
await self.create(
@@ -898,7 +898,7 @@ def content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[FileContentResponse, AsyncPage[FileContentResponse]]:
"""
Retrieve the parsed contents of a vector store file.
diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py
index 826f808e5b..a177c368c1 100644
--- a/src/openai/resources/vector_stores/vector_stores.py
+++ b/src/openai/resources/vector_stores/vector_stores.py
@@ -5,7 +5,7 @@
from typing import Union, Optional
from typing_extensions import Literal
-import httpx
+import httpx2
from ... import _legacy_response
from .files import (
@@ -89,7 +89,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStore:
"""
Create a vector store.
@@ -157,7 +157,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStore:
"""
Retrieves a vector store.
@@ -198,7 +198,7 @@ def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStore:
"""
Modifies a vector store.
@@ -258,7 +258,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncCursorPage[VectorStore]:
"""Returns a list of vector stores.
@@ -321,7 +321,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreDeleted:
"""
Delete a vector store.
@@ -364,7 +364,7 @@ def search(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncPage[VectorStoreSearchResponse]:
"""
Search a vector store for relevant chunks based on a query and file attributes
@@ -460,7 +460,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStore:
"""
Create a vector store.
@@ -528,7 +528,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStore:
"""
Retrieves a vector store.
@@ -569,7 +569,7 @@ async def update(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStore:
"""
Modifies a vector store.
@@ -629,7 +629,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[VectorStore, AsyncCursorPage[VectorStore]]:
"""Returns a list of vector stores.
@@ -692,7 +692,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VectorStoreDeleted:
"""
Delete a vector store.
@@ -735,7 +735,7 @@ def search(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[VectorStoreSearchResponse, AsyncPage[VectorStoreSearchResponse]]:
"""
Search a vector store for relevant chunks based on a query and file attributes
diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py
index 090ab62fa9..37ceb9a660 100644
--- a/src/openai/resources/videos.py
+++ b/src/openai/resources/videos.py
@@ -5,7 +5,7 @@
from typing import TYPE_CHECKING, Mapping, cast
from typing_extensions import Literal, assert_never
-import httpx
+import httpx2
from .. import _legacy_response
from ..types import (
@@ -79,7 +79,7 @@ def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create a new video generation job from a prompt and optional reference assets.
@@ -148,7 +148,7 @@ def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""Create a video and wait for it to be processed."""
video = self.create(
@@ -216,7 +216,7 @@ def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Fetch the latest metadata for a generated video.
@@ -255,7 +255,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> SyncConversationCursorPage[Video]:
"""
List recently generated videos for the current project.
@@ -306,7 +306,7 @@ def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VideoDeleteResponse:
"""
Permanently delete a completed or failed video and its stored assets.
@@ -344,7 +344,7 @@ def create_character(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VideoCreateCharacterResponse:
"""
Create a character from an uploaded video.
@@ -398,7 +398,7 @@ def download_content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Download the generated video bytes or a derived preview asset.
@@ -442,7 +442,7 @@ def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create a new video generation job by editing a source video or existing
@@ -498,7 +498,7 @@ def extend(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create an extension of a completed video.
@@ -555,7 +555,7 @@ def get_character(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VideoGetCharacterResponse:
"""
Fetch a character.
@@ -593,7 +593,7 @@ def remix(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create a remix of a completed video using a refreshed prompt.
@@ -658,7 +658,7 @@ async def create(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create a new video generation job from a prompt and optional reference assets.
@@ -727,7 +727,7 @@ async def create_and_poll(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""Create a video and wait for it to be processed."""
video = await self.create(
@@ -795,7 +795,7 @@ async def retrieve(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Fetch the latest metadata for a generated video.
@@ -834,7 +834,7 @@ def list(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Video, AsyncConversationCursorPage[Video]]:
"""
List recently generated videos for the current project.
@@ -885,7 +885,7 @@ async def delete(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VideoDeleteResponse:
"""
Permanently delete a completed or failed video and its stored assets.
@@ -923,7 +923,7 @@ async def create_character(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VideoCreateCharacterResponse:
"""
Create a character from an uploaded video.
@@ -977,7 +977,7 @@ async def download_content(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> _legacy_response.HttpxBinaryResponseContent:
"""
Download the generated video bytes or a derived preview asset.
@@ -1023,7 +1023,7 @@ async def edit(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create a new video generation job by editing a source video or existing
@@ -1079,7 +1079,7 @@ async def extend(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create an extension of a completed video.
@@ -1136,7 +1136,7 @@ async def get_character(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> VideoGetCharacterResponse:
"""
Fetch a character.
@@ -1174,7 +1174,7 @@ async def remix(
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ timeout: float | httpx2.Timeout | None | NotGiven = not_given,
) -> Video:
"""
Create a remix of a completed video using a refreshed prompt.
diff --git a/tests/_httpx2_respx.py b/tests/_httpx2_respx.py
deleted file mode 100644
index 3b66323daf..0000000000
--- a/tests/_httpx2_respx.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from __future__ import annotations
-
-import os
-from typing import Any, NoReturn
-
-import httpx
-import pytest
-from respx import MockRouter
-
-from openai import DefaultHttpx2Client, DefaultAsyncHttpx2Client
-
-
-def httpx2_enabled() -> bool:
- return os.environ.get("OPENAI_TEST_HTTP_CLIENT") == "httpx2"
-
-
-def sync_http_client(**kwargs: Any) -> httpx.Client:
- if httpx2_enabled():
- return DefaultHttpx2Client(**kwargs)
- return httpx.Client(**kwargs)
-
-
-def async_http_client(**kwargs: Any) -> httpx.AsyncClient:
- if httpx2_enabled():
- return DefaultAsyncHttpx2Client(**kwargs)
- return httpx.AsyncClient(**kwargs)
-
-
-def enable_httpx2_respx(
- router: MockRouter, monkeypatch: pytest.MonkeyPatch, *, replace_sdk_defaults: bool = True
-) -> None:
- httpx2 = pytest.importorskip("httpx2")
-
- # RESPX deliberately only understands HTTPX objects. Keep the SDK side native and
- # translate at this single test-only boundary so existing routes, callbacks, and
- # call assertions can be exercised against HTTPX2 without copied test cases.
- def httpx_request(native_request: Any, *, content: bytes) -> httpx.Request:
- return httpx.Request(
- native_request.method,
- str(native_request.url),
- headers=list(native_request.headers.multi_items()),
- content=content,
- extensions=dict(native_request.extensions),
- )
-
- def httpx2_response(response: httpx.Response, *, native_request: Any, content: bytes) -> Any:
- return httpx2.Response(
- response.status_code,
- headers=list(response.headers.multi_items()),
- # Supplying a stream keeps streaming-response tests meaningful: the native
- # response stays open until the SDK consumes or closes it.
- stream=httpx2.ByteStream(content),
- request=native_request,
- extensions=dict(response.extensions),
- )
-
- def raise_native_request_error(exc: httpx.RequestError, native_request: Any) -> NoReturn:
- native_error = getattr(httpx2, type(exc).__name__, httpx2.RequestError)
- raise native_error(str(exc), request=native_request) from exc
-
- def handler(native_request: Any) -> Any:
- try:
- response = router.handler(httpx_request(native_request, content=native_request.read()))
- except httpx.RequestError as exc:
- raise_native_request_error(exc, native_request)
- return httpx2_response(response, native_request=native_request, content=response.read())
-
- async def async_handler(native_request: Any) -> Any:
- try:
- response = await router.async_handler(httpx_request(native_request, content=await native_request.aread()))
- except httpx.RequestError as exc:
- raise_native_request_error(exc, native_request)
- return httpx2_response(response, native_request=native_request, content=await response.aread())
-
- # Match RESPX's own patch point. This also catches clients created inside a test,
- # while leaving every non-RESPX test on its ordinary transport.
- def sync_transport(*_args: Any) -> Any:
- return httpx2.MockTransport(handler)
-
- def async_transport(*_args: Any) -> Any:
- return httpx2.MockTransport(async_handler)
-
- monkeypatch.setattr(httpx2.Client, "_transport_for_url", sync_transport)
- monkeypatch.setattr(httpx2.AsyncClient, "_transport_for_url", async_transport)
-
- if replace_sdk_defaults:
- import openai._base_client as base_client
-
- # Clients constructed inside a RESPX test should exercise the same native
- # path as the shared fixtures; the base-compatibility tests opt out.
- monkeypatch.setattr(base_client, "SyncHttpxClientWrapper", DefaultHttpx2Client)
- monkeypatch.setattr(base_client, "AsyncHttpxClientWrapper", DefaultAsyncHttpx2Client)
diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py
index 9ad6d28316..76257dc4a7 100644
--- a/tests/api_resources/audio/test_speech.py
+++ b/tests/api_resources/audio/test_speech.py
@@ -5,13 +5,13 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
from tests.utils import assert_matches_type
+from tests.respx2 import MockRouter
# pyright: reportDeprecated=false
@@ -22,9 +22,9 @@ class TestSpeech:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_create(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
speech = client.audio.speech.create(
input="string",
model="tts-1",
@@ -34,9 +34,9 @@ def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
assert speech.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_create_with_all_params(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
speech = client.audio.speech.create(
input="string",
model="tts-1",
@@ -50,9 +50,9 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou
assert speech.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_create(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.audio.speech.with_raw_response.create(
input="string",
@@ -66,9 +66,9 @@ def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> No
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, speech, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_create(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
with client.audio.speech.with_streaming_response.create(
input="string",
model="tts-1",
@@ -89,9 +89,9 @@ class TestAsyncSpeech:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_create(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
speech = await async_client.audio.speech.create(
input="string",
model="tts-1",
@@ -101,9 +101,9 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRo
assert speech.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
speech = await async_client.audio.speech.create(
input="string",
model="tts-1",
@@ -117,9 +117,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re
assert speech.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.audio.speech.with_raw_response.create(
input="string",
@@ -133,9 +133,9 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock:
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, speech, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/audio/speech").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/audio/speech").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
async with async_client.audio.speech.with_streaming_response.create(
input="string",
model="tts-1",
diff --git a/tests/api_resources/containers/files/test_content.py b/tests/api_resources/containers/files/test_content.py
index aa282e8c04..b71577f8a8 100644
--- a/tests/api_resources/containers/files/test_content.py
+++ b/tests/api_resources/containers/files/test_content.py
@@ -5,13 +5,13 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
from tests.utils import assert_matches_type
+from tests.respx2 import MockRouter
# pyright: reportDeprecated=false
@@ -22,10 +22,10 @@ class TestContent:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/containers/container_id/files/file_id/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/containers/container_id/files/file_id/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
content = client.containers.files.content.retrieve(
file_id="file_id",
@@ -35,10 +35,10 @@ def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
assert content.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/containers/container_id/files/file_id/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/containers/container_id/files/file_id/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
response = client.containers.files.content.with_raw_response.retrieve(
@@ -52,10 +52,10 @@ def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) ->
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/containers/container_id/files/file_id/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/containers/container_id/files/file_id/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
with client.containers.files.content.with_streaming_response.retrieve(
file_id="file_id",
@@ -70,7 +70,7 @@ def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRoute
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_path_params_retrieve(self, client: OpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"):
client.containers.files.content.with_raw_response.retrieve(
@@ -91,10 +91,10 @@ class TestAsyncContent:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/containers/container_id/files/file_id/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/containers/container_id/files/file_id/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
content = await async_client.containers.files.content.retrieve(
file_id="file_id",
@@ -104,10 +104,10 @@ async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: Mock
assert content.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/containers/container_id/files/file_id/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/containers/container_id/files/file_id/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
response = await async_client.containers.files.content.with_raw_response.retrieve(
@@ -121,10 +121,10 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/containers/container_id/files/file_id/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/containers/container_id/files/file_id/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
async with async_client.containers.files.content.with_streaming_response.retrieve(
file_id="file_id",
@@ -139,7 +139,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, resp
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `container_id` but received ''"):
await async_client.containers.files.content.with_raw_response.retrieve(
diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py
index 1b70d02f9c..cd5466917c 100644
--- a/tests/api_resources/realtime/test_calls.py
+++ b/tests/api_resources/realtime/test_calls.py
@@ -5,13 +5,13 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
from tests.utils import assert_matches_type
+from tests.respx2 import MockRouter
# pyright: reportDeprecated=false
@@ -22,9 +22,9 @@ class TestCalls:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_create(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
call = client.realtime.calls.create(
sdp="sdp",
)
@@ -32,9 +32,9 @@ def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
assert call.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_create_with_all_params(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
call = client.realtime.calls.create(
sdp="sdp",
session={
@@ -102,9 +102,9 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou
assert call.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_create(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.realtime.calls.with_raw_response.create(
sdp="sdp",
@@ -116,9 +116,9 @@ def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> No
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, call, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_create(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
with client.realtime.calls.with_streaming_response.create(
sdp="sdp",
) as response:
@@ -370,9 +370,9 @@ class TestAsyncCalls:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_create(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
call = await async_client.realtime.calls.create(
sdp="sdp",
)
@@ -380,9 +380,9 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRo
assert call.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
call = await async_client.realtime.calls.create(
sdp="sdp",
session={
@@ -450,9 +450,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re
assert call.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.realtime.calls.with_raw_response.create(
sdp="sdp",
@@ -464,9 +464,9 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock:
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, call, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.post("/realtime/calls").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.post("/realtime/calls").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
async with async_client.realtime.calls.with_streaming_response.create(
sdp="sdp",
) as response:
diff --git a/tests/api_resources/skills/test_content.py b/tests/api_resources/skills/test_content.py
index 91cefe204d..04d1d0c67a 100644
--- a/tests/api_resources/skills/test_content.py
+++ b/tests/api_resources/skills/test_content.py
@@ -5,13 +5,13 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
from tests.utils import assert_matches_type
+from tests.respx2 import MockRouter
# pyright: reportDeprecated=false
@@ -22,9 +22,9 @@ class TestContent:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
content = client.skills.content.retrieve(
"skill_123",
)
@@ -32,9 +32,9 @@ def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
assert content.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.skills.content.with_raw_response.retrieve(
"skill_123",
@@ -46,9 +46,9 @@ def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) ->
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
with client.skills.content.with_streaming_response.retrieve(
"skill_123",
) as response:
@@ -61,7 +61,7 @@ def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRoute
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_path_params_retrieve(self, client: OpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"):
client.skills.content.with_raw_response.retrieve(
@@ -75,9 +75,9 @@ class TestAsyncContent:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
content = await async_client.skills.content.retrieve(
"skill_123",
)
@@ -85,9 +85,9 @@ async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: Mock
assert content.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.skills.content.with_raw_response.retrieve(
"skill_123",
@@ -99,9 +99,9 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
async with async_client.skills.content.with_streaming_response.retrieve(
"skill_123",
) as response:
@@ -114,7 +114,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, resp
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"):
await async_client.skills.content.with_raw_response.retrieve(
diff --git a/tests/api_resources/skills/versions/test_content.py b/tests/api_resources/skills/versions/test_content.py
index 8f98effade..2c0b453c6b 100644
--- a/tests/api_resources/skills/versions/test_content.py
+++ b/tests/api_resources/skills/versions/test_content.py
@@ -5,13 +5,13 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
from tests.utils import assert_matches_type
+from tests.respx2 import MockRouter
# pyright: reportDeprecated=false
@@ -22,10 +22,10 @@ class TestContent:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/versions/version/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/versions/version/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
content = client.skills.versions.content.retrieve(
version="version",
@@ -35,10 +35,10 @@ def test_method_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
assert content.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/versions/version/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/versions/version/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
response = client.skills.versions.content.with_raw_response.retrieve(
@@ -52,10 +52,10 @@ def test_raw_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) ->
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/versions/version/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_retrieve(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/versions/version/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
with client.skills.versions.content.with_streaming_response.retrieve(
version="version",
@@ -70,7 +70,7 @@ def test_streaming_response_retrieve(self, client: OpenAI, respx_mock: MockRoute
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_path_params_retrieve(self, client: OpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"):
client.skills.versions.content.with_raw_response.retrieve(
@@ -91,10 +91,10 @@ class TestAsyncContent:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/versions/version/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/versions/version/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
content = await async_client.skills.versions.content.retrieve(
version="version",
@@ -104,10 +104,10 @@ async def test_method_retrieve(self, async_client: AsyncOpenAI, respx_mock: Mock
assert content.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/versions/version/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/versions/version/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
response = await async_client.skills.versions.content.with_raw_response.retrieve(
@@ -121,10 +121,10 @@ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI, respx_mock
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, content, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/skills/skill_123/versions/version/content").mock(
- return_value=httpx.Response(200, json={"foo": "bar"})
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/skills/skill_123/versions/version/content").mock(
+ return_value=httpx2.Response(200, json={"foo": "bar"})
)
async with async_client.skills.versions.content.with_streaming_response.retrieve(
version="version",
@@ -139,7 +139,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI, resp
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `skill_id` but received ''"):
await async_client.skills.versions.content.with_raw_response.retrieve(
diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py
index d8eec954f0..2b820c0265 100644
--- a/tests/api_resources/test_files.py
+++ b/tests/api_resources/test_files.py
@@ -5,14 +5,14 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
from tests.utils import assert_matches_type
from openai.types import FileObject, FileDeleted
+from tests.respx2 import MockRouter
from openai.pagination import SyncCursorPage, AsyncCursorPage
# pyright: reportDeprecated=false
@@ -181,9 +181,9 @@ def test_path_params_delete(self, client: OpenAI) -> None:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/files/string/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_content(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/files/string/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
file = client.files.content(
"string",
)
@@ -191,9 +191,9 @@ def test_method_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
assert file.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/files/string/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_content(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/files/string/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.files.with_raw_response.content(
"string",
@@ -205,9 +205,9 @@ def test_raw_response_content(self, client: OpenAI, respx_mock: MockRouter) -> N
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, file, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/files/string/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_content(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/files/string/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
with client.files.with_streaming_response.content(
"string",
) as response:
@@ -220,7 +220,7 @@ def test_streaming_response_content(self, client: OpenAI, respx_mock: MockRouter
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_path_params_content(self, client: OpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
client.files.with_raw_response.content(
@@ -434,9 +434,9 @@ async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None:
)
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/files/string/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_content(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/files/string/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
file = await async_client.files.content(
"string",
)
@@ -444,9 +444,9 @@ async def test_method_content(self, async_client: AsyncOpenAI, respx_mock: MockR
assert file.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/files/string/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_content(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/files/string/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.files.with_raw_response.content(
"string",
@@ -458,9 +458,9 @@ async def test_raw_response_content(self, async_client: AsyncOpenAI, respx_mock:
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, file, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/files/string/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_content(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/files/string/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
async with async_client.files.with_streaming_response.content(
"string",
) as response:
@@ -473,7 +473,7 @@ async def test_streaming_response_content(self, async_client: AsyncOpenAI, respx
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_path_params_content(self, async_client: AsyncOpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
await async_client.files.with_raw_response.content(
diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py
index 8e147c6572..71e87a4e4a 100644
--- a/tests/api_resources/test_videos.py
+++ b/tests/api_resources/test_videos.py
@@ -5,9 +5,8 @@
import os
from typing import Any, cast
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
import openai._legacy_response as _legacy_response
from openai import OpenAI, AsyncOpenAI
@@ -18,6 +17,7 @@
VideoGetCharacterResponse,
VideoCreateCharacterResponse,
)
+from tests.respx2 import MockRouter
from openai._utils import assert_signatures_in_sync
from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage
@@ -216,9 +216,9 @@ def test_streaming_response_create_character(self, client: OpenAI) -> None:
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_download_content(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
video = client.videos.download_content(
video_id="video_123",
)
@@ -226,9 +226,9 @@ def test_method_download_content(self, client: OpenAI, respx_mock: MockRouter) -
assert video.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_method_download_content_with_all_params(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_method_download_content_with_all_params(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
video = client.videos.download_content(
video_id="video_123",
variant="video",
@@ -237,9 +237,9 @@ def test_method_download_content_with_all_params(self, client: OpenAI, respx_moc
assert video.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_download_content(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.videos.with_raw_response.download_content(
video_id="video_123",
@@ -251,9 +251,9 @@ def test_raw_response_download_content(self, client: OpenAI, respx_mock: MockRou
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, video, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- def test_streaming_response_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_streaming_response_download_content(self, client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
with client.videos.with_streaming_response.download_content(
video_id="video_123",
) as response:
@@ -266,7 +266,7 @@ def test_streaming_response_download_content(self, client: OpenAI, respx_mock: M
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_path_params_download_content(self, client: OpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"):
client.videos.with_raw_response.download_content(
@@ -617,9 +617,9 @@ async def test_streaming_response_create_character(self, async_client: AsyncOpen
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_method_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_method_download_content(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
video = await async_client.videos.download_content(
video_id="video_123",
)
@@ -627,11 +627,11 @@ async def test_method_download_content(self, async_client: AsyncOpenAI, respx_mo
assert video.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_method_download_content_with_all_params(
- self, async_client: AsyncOpenAI, respx_mock: MockRouter
+ self, async_client: AsyncOpenAI, respx2_mock: MockRouter
) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
video = await async_client.videos.download_content(
video_id="video_123",
variant="video",
@@ -640,9 +640,9 @@ async def test_method_download_content_with_all_params(
assert video.json() == {"foo": "bar"}
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_download_content(self, async_client: AsyncOpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.videos.with_raw_response.download_content(
video_id="video_123",
@@ -654,9 +654,11 @@ async def test_raw_response_download_content(self, async_client: AsyncOpenAI, re
assert_matches_type(_legacy_response.HttpxBinaryResponseContent, video, path=["response"])
@parametrize
- @pytest.mark.respx(base_url=base_url)
- async def test_streaming_response_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/videos/video_123/content").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_streaming_response_download_content(
+ self, async_client: AsyncOpenAI, respx2_mock: MockRouter
+ ) -> None:
+ respx2_mock.get("/videos/video_123/content").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
async with async_client.videos.with_streaming_response.download_content(
video_id="video_123",
) as response:
@@ -669,7 +671,7 @@ async def test_streaming_response_download_content(self, async_client: AsyncOpen
assert cast(Any, response.is_closed) is True
@parametrize
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_path_params_download_content(self, async_client: AsyncOpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `video_id` but received ''"):
await async_client.videos.with_raw_response.download_content(
diff --git a/tests/conftest.py b/tests/conftest.py
index 8128f1515b..ff3671cb0c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -3,22 +3,21 @@
from __future__ import annotations
import os
-import sys
import logging
from typing import TYPE_CHECKING, Iterator, AsyncIterator
-import httpx
+import httpx2
import pytest
from pytest_asyncio import is_async_test
from openai import OpenAI, AsyncOpenAI, DefaultHttpx2Client, DefaultAioHttpClient, DefaultAsyncHttpx2Client
from openai._utils import is_dict
-from ._httpx2_respx import enable_httpx2_respx
-
if TYPE_CHECKING:
from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage]
+pytest_plugins = ["tests.respx2.plugin"]
+
pytest.register_assert_rewrite("tests.utils")
logging.getLogger("openai").setLevel(logging.DEBUG)
@@ -34,7 +33,7 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None:
# RESPX cannot mock requests made by the aiohttp adapter.
for item in items:
- if "respx_mock" not in item.fixturenames:
+ if "respx2_mock" not in item.fixturenames:
continue
if "async_client" not in item.fixturenames:
@@ -45,25 +44,16 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None:
async_client_param = item.callspec.params.get("async_client")
if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp":
- item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock"))
+ item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx2_mock"))
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-test_http_client = os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx")
+test_http_client = os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx2")
api_key = "My API Key"
admin_api_key = "My Admin API Key"
-@pytest.fixture(autouse=True)
-def patch_httpx2_respx(request: FixtureRequest, monkeypatch: pytest.MonkeyPatch) -> None:
- if test_http_client != "httpx2" or "respx_mock" not in request.fixturenames:
- return
-
- router = request.getfixturevalue("respx_mock")
- enable_httpx2_respx(router, monkeypatch, replace_sdk_defaults=request.path.name != "test_httpx2_base.py")
-
-
@pytest.fixture(scope="session")
def client(request: FixtureRequest) -> Iterator[OpenAI]:
strict = getattr(request, "param", True)
@@ -88,7 +78,7 @@ async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOpenAI]:
# defaults
strict = True
- http_client: None | httpx.AsyncClient = None
+ http_client: None | httpx2.AsyncClient = None
if isinstance(param, bool):
strict = param
@@ -96,11 +86,8 @@ async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOpenAI]:
strict = param.get("strict", True)
assert isinstance(strict, bool)
- http_client_type = param.get("http_client", "httpx")
+ http_client_type = param.get("http_client", "httpx2")
if http_client_type == "aiohttp":
- if sys.version_info < (3, 10):
- pytest.skip("the aiohttp client requires Python 3.10 or later")
-
http_client = DefaultAioHttpClient()
else:
raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict")
diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py
index 741f5eaa75..609c4dbe4e 100644
--- a/tests/lib/chat/test_completions.py
+++ b/tests/lib/chat/test_completions.py
@@ -5,12 +5,12 @@
from typing_extensions import Literal, TypeVar
import pytest
-from respx import MockRouter
from pydantic import Field, BaseModel
from inline_snapshot import snapshot
import openai
from openai import OpenAI, AsyncOpenAI
+from tests.respx2 import MockRouter
from openai._utils import assert_signatures_in_sync
from openai._compat import PYDANTIC_V1
@@ -28,8 +28,8 @@
# `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""`
-@pytest.mark.respx(base_url=base_url)
-def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_nothing(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
completion = make_snapshot_request(
lambda c: c.chat.completions.parse(
model="gpt-4o-2024-08-06",
@@ -45,7 +45,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion, monkeypatch) == snapshot(
@@ -93,8 +93,8 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_model(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_model(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -116,7 +116,7 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion, monkeypatch) == snapshot(
@@ -163,9 +163,9 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
+@pytest.mark.respx2(base_url=base_url)
def test_parse_pydantic_model_optional_default(
- client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
) -> None:
class Location(BaseModel):
city: str
@@ -188,7 +188,7 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion, monkeypatch) == snapshot(
@@ -235,8 +235,8 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_model_enum(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_model_enum(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Color(Enum):
"""The detected color"""
@@ -264,7 +264,7 @@ class ColorDetection(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices[0], monkeypatch) == snapshot(
@@ -288,9 +288,9 @@ class ColorDetection(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
+@pytest.mark.respx2(base_url=base_url)
def test_parse_pydantic_model_multiple_choices(
- client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
) -> None:
class Location(BaseModel):
city: str
@@ -314,7 +314,7 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices, monkeypatch) == snapshot(
@@ -370,9 +370,9 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
+@pytest.mark.respx2(base_url=base_url)
@pytest.mark.skipif(PYDANTIC_V1, reason="dataclasses only supported in v2")
-def test_parse_pydantic_dataclass(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+def test_parse_pydantic_dataclass(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
from pydantic.dataclasses import dataclass
@dataclass
@@ -395,7 +395,7 @@ class CalendarEvent:
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion, monkeypatch) == snapshot(
@@ -442,8 +442,10 @@ class CalendarEvent:
)
-@pytest.mark.respx(base_url=base_url)
-def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_pydantic_tool_model_all_types(
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+) -> None:
completion = make_snapshot_request(
lambda c: c.chat.completions.parse(
model="gpt-4o-2024-08-06",
@@ -461,7 +463,7 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices[0], monkeypatch) == snapshot(
@@ -522,8 +524,8 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_max_tokens_reached(client: OpenAI, respx_mock: MockRouter) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_max_tokens_reached(client: OpenAI, respx2_mock: MockRouter) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -547,12 +549,12 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_model_refusal(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_model_refusal(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -574,7 +576,7 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices, monkeypatch) == snapshot(
@@ -600,8 +602,8 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_tool(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_tool(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class GetWeatherArgs(BaseModel):
city: str
country: str
@@ -625,7 +627,7 @@ class GetWeatherArgs(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices, monkeypatch) == snapshot(
@@ -661,8 +663,10 @@ class GetWeatherArgs(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_multiple_pydantic_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_multiple_pydantic_tools(
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+) -> None:
class GetWeatherArgs(BaseModel):
"""Get the temperature for the given country/city combo"""
@@ -699,7 +703,7 @@ class GetStockPrice(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices, monkeypatch) == snapshot(
@@ -744,8 +748,8 @@ class GetStockPrice(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_strict_tools(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
completion = make_snapshot_request(
lambda c: c.chat.completions.parse(
model="gpt-4o-2024-08-06",
@@ -782,7 +786,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch:
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(completion.choices, monkeypatch) == snapshot(
@@ -837,8 +841,8 @@ def test_parse_non_strict_tools(client: OpenAI) -> None:
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_raw_response(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_raw_response(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -860,7 +864,7 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert response.http_request.headers.get("x-stainless-helper-method") == "chat.completions.parse"
@@ -912,10 +916,10 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
+@pytest.mark.respx2(base_url=base_url)
@pytest.mark.asyncio
async def test_async_parse_pydantic_raw_response(
- async_client: AsyncOpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+ async_client: AsyncOpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
) -> None:
class Location(BaseModel):
city: str
@@ -938,7 +942,7 @@ class Location(BaseModel):
),
path="/chat/completions",
mock_client=async_client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert response.http_request.headers.get("x-stainless-helper-method") == "chat.completions.parse"
diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py
index 598a41ee2b..0b6200a71b 100644
--- a/tests/lib/chat/test_completions_streaming.py
+++ b/tests/lib/chat/test_completions_streaming.py
@@ -5,9 +5,8 @@
from typing_extensions import Literal, TypeVar
import rich
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
from pydantic import BaseModel
from inline_snapshot import (
external,
@@ -18,6 +17,7 @@
import openai
from openai import OpenAI, AsyncOpenAI
+from tests.respx2 import MockRouter
from openai._utils import consume_sync_iterator, assert_signatures_in_sync
from openai._compat import model_copy
from openai.types.chat import ChatCompletionChunk
@@ -43,8 +43,8 @@
# `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""`
-@pytest.mark.respx(base_url=base_url)
-def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_nothing(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
listener = _make_stream_snapshot_request(
lambda c: c.chat.completions.stream(
model="gpt-4o-2024-08-06",
@@ -57,7 +57,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte
),
content_snapshot=snapshot(external("e2aad469b71d*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot(
@@ -94,8 +94,8 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_model(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_model(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -120,7 +120,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream
),
content_snapshot=snapshot(external("7e5ea4d12e7c*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
on_event=on_event,
)
@@ -191,9 +191,9 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream
)
-@pytest.mark.respx(base_url=base_url)
+@pytest.mark.respx2(base_url=base_url)
def test_parse_pydantic_model_multiple_choices(
- client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
) -> None:
class Location(BaseModel):
city: str
@@ -214,7 +214,7 @@ class Location(BaseModel):
),
content_snapshot=snapshot(external("a491adda08c3*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert [e.type for e in listener.events] == snapshot(
@@ -371,8 +371,8 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_max_tokens_reached(client: OpenAI, respx_mock: MockRouter) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_max_tokens_reached(client: OpenAI, respx2_mock: MockRouter) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -393,12 +393,12 @@ class Location(BaseModel):
),
content_snapshot=snapshot(external("4cc50a6135d2*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_model_refusal(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_model_refusal(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -417,7 +417,7 @@ class Location(BaseModel):
),
content_snapshot=snapshot(external("173417d55340*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.get_event_by_type("refusal.done"), monkeypatch) == snapshot("""\
@@ -447,8 +447,8 @@ class Location(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_content_logprobs_events(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
listener = _make_stream_snapshot_request(
lambda c: c.chat.completions.stream(
model="gpt-4o-2024-08-06",
@@ -462,7 +462,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp
),
content_snapshot=snapshot(external("83b060bae42e*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj([e for e in listener.events if e.type.startswith("logprobs")], monkeypatch) == snapshot("""\
@@ -521,8 +521,8 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp
""")
-@pytest.mark.respx(base_url=base_url)
-def test_refusal_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_refusal_logprobs_events(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class Location(BaseModel):
city: str
temperature: float
@@ -542,7 +542,7 @@ class Location(BaseModel):
),
content_snapshot=snapshot(external("569c877e6942*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj([e.type for e in listener.events if e.type.startswith("logprobs")], monkeypatch) == snapshot("""\
@@ -633,8 +633,8 @@ class Location(BaseModel):
""")
-@pytest.mark.respx(base_url=base_url)
-def test_parse_pydantic_tool(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_pydantic_tool(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
class GetWeatherArgs(BaseModel):
city: str
country: str
@@ -655,7 +655,7 @@ class GetWeatherArgs(BaseModel):
),
content_snapshot=snapshot(external("c6aa7e397b71*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot(
@@ -725,8 +725,10 @@ class GetWeatherArgs(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_multiple_pydantic_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_multiple_pydantic_tools(
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+) -> None:
class GetWeatherArgs(BaseModel):
"""Get the temperature for the given country/city combo"""
@@ -760,7 +762,7 @@ class GetStockPrice(BaseModel):
),
content_snapshot=snapshot(external("f82268f2fefd*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot(
@@ -834,8 +836,8 @@ class GetStockPrice(BaseModel):
)
-@pytest.mark.respx(base_url=base_url)
-def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_parse_strict_tools(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
listener = _make_stream_snapshot_request(
lambda c: c.chat.completions.stream(
model="gpt-4o-2024-08-06",
@@ -869,7 +871,7 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch:
),
content_snapshot=snapshot(external("a247c49c5fcd*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot(
@@ -906,8 +908,8 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch:
)
-@pytest.mark.respx(base_url=base_url)
-def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_non_pydantic_response_format(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
listener = _make_stream_snapshot_request(
lambda c: c.chat.completions.stream(
model="gpt-4o-2024-08-06",
@@ -921,7 +923,7 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo
),
content_snapshot=snapshot(external("d61558011839*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot(
@@ -952,9 +954,9 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo
)
-@pytest.mark.respx(base_url=base_url)
+@pytest.mark.respx2(base_url=base_url)
def test_allows_non_strict_tools_but_no_parsing(
- client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
+ client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
) -> None:
listener = _make_stream_snapshot_request(
lambda c: c.chat.completions.stream(
@@ -972,7 +974,7 @@ def test_allows_non_strict_tools_but_no_parsing(
),
content_snapshot=snapshot(external("2018feb66ae1*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(listener.get_event_by_type("tool_calls.function.arguments.done"), monkeypatch) == snapshot("""\
@@ -1019,8 +1021,8 @@ def test_allows_non_strict_tools_but_no_parsing(
)
-@pytest.mark.respx(base_url=base_url)
-def test_chat_completion_state_helper(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_chat_completion_state_helper(client: OpenAI, respx2_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
state = ChatCompletionStreamState()
def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]:
@@ -1042,7 +1044,7 @@ def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]:
streamer,
content_snapshot=snapshot(external("e2aad469b71d*.bin")),
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert print_obj(state.get_final_completion().choices, monkeypatch) == snapshot(
@@ -1104,7 +1106,7 @@ def _make_stream_snapshot_request(
func: Callable[[OpenAI], ChatCompletionStreamManager[ResponseFormatT]],
*,
content_snapshot: Any,
- respx_mock: MockRouter,
+ respx2_mock: MockRouter,
mock_client: OpenAI,
on_event: Callable[[ChatCompletionStream[ResponseFormatT], ChatCompletionStreamEvent[ResponseFormatT]], Any]
| None = None,
@@ -1112,22 +1114,22 @@ def _make_stream_snapshot_request(
live = os.environ.get("OPENAI_LIVE") == "1"
if live:
- def _on_response(response: httpx.Response) -> None:
+ def _on_response(response: httpx2.Response) -> None:
# update the content snapshot
assert outsource(response.read()) == content_snapshot
- respx_mock.stop()
+ respx2_mock.stop()
client = OpenAI(
- http_client=httpx.Client(
+ http_client=httpx2.Client(
event_hooks={
"response": [_on_response],
}
)
)
else:
- respx_mock.post("/chat/completions").mock(
- return_value=httpx.Response(
+ respx2_mock.post("/chat/completions").mock(
+ return_value=httpx2.Response(
200,
content=get_snapshot_value(content_snapshot),
headers={"content-type": "text/event-stream"},
@@ -1153,28 +1155,28 @@ def _make_raw_stream_snapshot_request(
func: Callable[[OpenAI], Iterator[ChatCompletionChunk]],
*,
content_snapshot: Any,
- respx_mock: MockRouter,
+ respx2_mock: MockRouter,
mock_client: OpenAI,
) -> None:
live = os.environ.get("OPENAI_LIVE") == "1"
if live:
- def _on_response(response: httpx.Response) -> None:
+ def _on_response(response: httpx2.Response) -> None:
# update the content snapshot
assert outsource(response.read()) == content_snapshot
- respx_mock.stop()
+ respx2_mock.stop()
client = OpenAI(
- http_client=httpx.Client(
+ http_client=httpx2.Client(
event_hooks={
"response": [_on_response],
}
)
)
else:
- respx_mock.post("/chat/completions").mock(
- return_value=httpx.Response(
+ respx2_mock.post("/chat/completions").mock(
+ return_value=httpx2.Response(
200,
content=get_snapshot_value(content_snapshot),
headers={"content-type": "text/event-stream"},
diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py
index 4ed6dff47d..43879942b8 100644
--- a/tests/lib/responses/test_responses.py
+++ b/tests/lib/responses/test_responses.py
@@ -3,10 +3,10 @@
from typing_extensions import TypeVar
import pytest
-from respx import MockRouter
from inline_snapshot import snapshot
from openai import OpenAI, AsyncOpenAI
+from tests.respx2 import MockRouter
from openai._types import omit
from openai._utils import assert_signatures_in_sync
from openai._models import construct_type_unchecked
@@ -25,8 +25,8 @@
# `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""`
-@pytest.mark.respx(base_url=base_url)
-def test_output_text(client: OpenAI, respx_mock: MockRouter) -> None:
+@pytest.mark.respx2(base_url=base_url)
+def test_output_text(client: OpenAI, respx2_mock: MockRouter) -> None:
response = make_snapshot_request(
lambda c: c.responses.create(
model="gpt-4o-mini",
@@ -37,7 +37,7 @@ def test_output_text(client: OpenAI, respx_mock: MockRouter) -> None:
),
path="/responses",
mock_client=client,
- respx_mock=respx_mock,
+ respx2_mock=respx2_mock,
)
assert response.output_text == snapshot(
diff --git a/tests/lib/snapshots.py b/tests/lib/snapshots.py
index 91222acda1..4789596def 100644
--- a/tests/lib/snapshots.py
+++ b/tests/lib/snapshots.py
@@ -5,11 +5,11 @@
from typing import Any, Callable, Awaitable
from typing_extensions import TypeVar
-import httpx
-from respx import MockRouter
+import httpx2
from inline_snapshot import get_snapshot_value
from openai import OpenAI, AsyncOpenAI
+from tests.respx2 import MockRouter
_T = TypeVar("_T")
@@ -18,29 +18,29 @@ def make_snapshot_request(
func: Callable[[OpenAI], _T],
*,
content_snapshot: Any,
- respx_mock: MockRouter,
+ respx2_mock: MockRouter,
mock_client: OpenAI,
path: str,
) -> _T:
live = os.environ.get("OPENAI_LIVE") == "1"
if live:
- def _on_response(response: httpx.Response) -> None:
+ def _on_response(response: httpx2.Response) -> None:
# update the content snapshot
assert json.dumps(json.loads(response.read())) == content_snapshot
- respx_mock.stop()
+ respx2_mock.stop()
client = OpenAI(
- http_client=httpx.Client(
+ http_client=httpx2.Client(
event_hooks={
"response": [_on_response],
}
)
)
else:
- respx_mock.post(path).mock(
- return_value=httpx.Response(
+ respx2_mock.post(path).mock(
+ return_value=httpx2.Response(
200,
content=get_snapshot_value(content_snapshot),
headers={"content-type": "application/json"},
@@ -61,29 +61,29 @@ async def make_async_snapshot_request(
func: Callable[[AsyncOpenAI], Awaitable[_T]],
*,
content_snapshot: Any,
- respx_mock: MockRouter,
+ respx2_mock: MockRouter,
mock_client: AsyncOpenAI,
path: str,
) -> _T:
live = os.environ.get("OPENAI_LIVE") == "1"
if live:
- async def _on_response(response: httpx.Response) -> None:
+ async def _on_response(response: httpx2.Response) -> None:
# update the content snapshot
assert json.dumps(json.loads(await response.aread())) == content_snapshot
- respx_mock.stop()
+ respx2_mock.stop()
client = AsyncOpenAI(
- http_client=httpx.AsyncClient(
+ http_client=httpx2.AsyncClient(
event_hooks={
"response": [_on_response],
}
)
)
else:
- respx_mock.post(path).mock(
- return_value=httpx.Response(
+ respx2_mock.post(path).mock(
+ return_value=httpx2.Response(
200,
content=get_snapshot_value(content_snapshot),
headers={"content-type": "application/json"},
diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py
index 3e1d783e2c..691a911144 100644
--- a/tests/lib/test_azure.py
+++ b/tests/lib/test_azure.py
@@ -4,12 +4,12 @@
from typing import Union, cast
from typing_extensions import Literal, Protocol
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
from openai import OpenAIError
from tests.utils import update_env
+from tests.respx2 import MockRouter
from openai._types import Omit
from openai._utils import SensitiveHeadersFilter, is_dict
from openai._models import FinalRequestOptions
@@ -32,7 +32,7 @@
class MockRequestCall(Protocol):
- request: httpx.Request
+ request: httpx2.Request
@pytest.mark.parametrize("client", [sync_client, async_client])
@@ -91,11 +91,11 @@ def test_enforce_credentials_false_sync() -> None:
)
-@pytest.mark.respx()
-def test_enforce_credentials_false_sync_uses_default_api_key_header(respx_mock: MockRouter) -> None:
- respx_mock.post(
+@pytest.mark.respx2()
+def test_enforce_credentials_false_sync_uses_default_api_key_header(respx2_mock: MockRouter) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
client = AzureOpenAI(
@@ -109,16 +109,16 @@ def test_enforce_credentials_false_sync_uses_default_api_key_header(respx_mock:
)
client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers.get("api-key") == "manual-api-key"
assert calls[0].request.headers.get("Authorization") is None
-@pytest.mark.respx()
-def test_enforce_credentials_false_sync_uses_request_authorization_header(respx_mock: MockRouter) -> None:
- respx_mock.post(
+@pytest.mark.respx2()
+def test_enforce_credentials_false_sync_uses_request_authorization_header(respx2_mock: MockRouter) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
client = AzureOpenAI(
@@ -135,7 +135,7 @@ def test_enforce_credentials_false_sync_uses_request_authorization_header(respx_
extra_headers={"authorization": "Bearer manual-token"},
)
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers.get("Authorization") == "Bearer manual-token"
assert calls[0].request.headers.get("api-key") is None
@@ -165,11 +165,11 @@ def test_enforce_credentials_false_async() -> None:
@pytest.mark.asyncio
-@pytest.mark.respx()
-async def test_enforce_credentials_false_async_uses_default_api_key_header(respx_mock: MockRouter) -> None:
- respx_mock.post(
+@pytest.mark.respx2()
+async def test_enforce_credentials_false_async_uses_default_api_key_header(respx2_mock: MockRouter) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
client = AsyncAzureOpenAI(
@@ -183,17 +183,17 @@ async def test_enforce_credentials_false_async_uses_default_api_key_header(respx
)
await client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers.get("api-key") == "manual-api-key"
assert calls[0].request.headers.get("Authorization") is None
@pytest.mark.asyncio
-@pytest.mark.respx()
-async def test_enforce_credentials_false_async_uses_request_authorization_header(respx_mock: MockRouter) -> None:
- respx_mock.post(
+@pytest.mark.respx2()
+async def test_enforce_credentials_false_async_uses_request_authorization_header(respx2_mock: MockRouter) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
client = AsyncAzureOpenAI(
@@ -210,7 +210,7 @@ async def test_enforce_credentials_false_async_uses_request_authorization_header
extra_headers={"authorization": "Bearer manual-token"},
)
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers.get("Authorization") == "Bearer manual-token"
assert calls[0].request.headers.get("api-key") is None
@@ -227,14 +227,14 @@ def test_enforce_credentials_true_async() -> None:
)
-@pytest.mark.respx()
-def test_client_token_provider_refresh_sync(respx_mock: MockRouter) -> None:
- respx_mock.post(
+@pytest.mark.respx2()
+def test_client_token_provider_refresh_sync(respx2_mock: MockRouter) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
).mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json={"foo": "bar"}),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json={"foo": "bar"}),
]
)
@@ -257,7 +257,7 @@ def token_provider() -> str:
)
client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 2
@@ -266,14 +266,14 @@ def token_provider() -> str:
@pytest.mark.asyncio
-@pytest.mark.respx()
-async def test_client_token_provider_refresh_async(respx_mock: MockRouter) -> None:
- respx_mock.post(
+@pytest.mark.respx2()
+async def test_client_token_provider_refresh_async(respx2_mock: MockRouter) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
).mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json={"foo": "bar"}),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json={"foo": "bar"}),
]
)
@@ -297,7 +297,7 @@ def token_provider() -> str:
await client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 2
@@ -313,11 +313,11 @@ def logger_with_filter(self) -> logging.Logger:
logger.addFilter(SensitiveHeadersFilter())
return logger
- @pytest.mark.respx()
- def test_azure_api_key_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
- respx_mock.post(
+ @pytest.mark.respx2()
+ def test_azure_api_key_redacted(self, respx2_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
client = AzureOpenAI(
api_version="2024-06-01",
@@ -332,11 +332,11 @@ def test_azure_api_key_redacted(self, respx_mock: MockRouter, caplog: pytest.Log
if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]):
assert record.args["headers"]["api-key"] == ""
- @pytest.mark.respx()
- def test_azure_bearer_token_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
- respx_mock.post(
+ @pytest.mark.respx2()
+ def test_azure_bearer_token_redacted(self, respx2_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
client = AzureOpenAI(
api_version="2024-06-01",
@@ -352,11 +352,13 @@ def test_azure_bearer_token_redacted(self, respx_mock: MockRouter, caplog: pytes
assert record.args["headers"]["Authorization"] == ""
@pytest.mark.asyncio
- @pytest.mark.respx()
- async def test_azure_api_key_redacted_async(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
- respx_mock.post(
+ @pytest.mark.respx2()
+ async def test_azure_api_key_redacted_async(
+ self, respx2_mock: MockRouter, caplog: pytest.LogCaptureFixture
+ ) -> None:
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
client = AsyncAzureOpenAI(
api_version="2024-06-01",
@@ -372,13 +374,13 @@ async def test_azure_api_key_redacted_async(self, respx_mock: MockRouter, caplog
assert record.args["headers"]["api-key"] == ""
@pytest.mark.asyncio
- @pytest.mark.respx()
+ @pytest.mark.respx2()
async def test_azure_bearer_token_redacted_async(
- self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture
+ self, respx2_mock: MockRouter, caplog: pytest.LogCaptureFixture
) -> None:
- respx_mock.post(
+ respx2_mock.post(
"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
- ).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
+ ).mock(return_value=httpx2.Response(200, json={"model": "gpt-4"}))
client = AsyncAzureOpenAI(
api_version="2024-06-01",
diff --git a/tests/lib/test_bedrock.py b/tests/lib/test_bedrock.py
index bf987b2fa9..96ebe80a10 100644
--- a/tests/lib/test_bedrock.py
+++ b/tests/lib/test_bedrock.py
@@ -4,17 +4,16 @@
from typing import Any, Union, Protocol, cast
from pathlib import Path
-import httpx
+import httpx2
import pytest
-from httpx import URL
-from respx import MockRouter
+from httpx2 import URL
import openai.lib._bedrock_auth as bedrock_auth_module
-from openai import OpenAIError, NotFoundError
+from openai import OpenAIError, NotFoundError, DefaultHttpx2Client, DefaultAsyncHttpx2Client
from tests.utils import update_env
+from tests.respx2 import MockRouter
from openai._types import Omit
from openai.lib.bedrock import BedrockOpenAI, AsyncBedrockOpenAI
-from tests._httpx2_respx import sync_http_client, async_http_client
Client = Union[BedrockOpenAI, AsyncBedrockOpenAI]
@@ -76,7 +75,7 @@
class MockRequestCall(Protocol):
- request: httpx.Request
+ request: httpx2.Request
class MockAwsCredentials:
@@ -87,11 +86,11 @@ def __init__(self, access_key: str, secret_key: str, token: str | None = None) -
def make_sync_client(**kwargs: Any) -> BedrockOpenAI:
- return BedrockOpenAI(http_client=sync_http_client(trust_env=False), **kwargs)
+ return BedrockOpenAI(http_client=DefaultHttpx2Client(trust_env=False), **kwargs)
def make_async_client(**kwargs: Any) -> AsyncBedrockOpenAI:
- return AsyncBedrockOpenAI(http_client=async_http_client(trust_env=False), **kwargs)
+ return AsyncBedrockOpenAI(http_client=DefaultAsyncHttpx2Client(trust_env=False), **kwargs)
def response_created_sse() -> str:
@@ -133,14 +132,14 @@ def test_bedrock_config_precedence(client_cls: type[Client]) -> None:
assert client.api_key == "explicit token"
-@pytest.mark.respx()
-def test_env_bearer_does_not_require_botocore(monkeypatch: pytest.MonkeyPatch, respx_mock: MockRouter) -> None:
+@pytest.mark.respx2()
+def test_env_bearer_does_not_require_botocore(monkeypatch: pytest.MonkeyPatch, respx2_mock: MockRouter) -> None:
def load_botocore() -> None:
raise AssertionError("bearer authentication must not import botocore")
monkeypatch.setattr(bedrock_auth_module, "_load_botocore", load_botocore)
- respx_mock.post("https://example.com/openai/v1/responses").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
with update_env(
AWS_BEDROCK_BASE_URL="https://example.com/openai/v1",
@@ -150,7 +149,7 @@ def load_botocore() -> None:
client.responses.create(model="gpt-4o", input="hello")
- request = cast("list[MockRequestCall]", respx_mock.calls)[0].request
+ request = cast("list[MockRequestCall]", respx2_mock.calls)[0].request
assert request.headers["Authorization"] == "Bearer env token"
@@ -165,11 +164,11 @@ def load_botocore() -> None:
with update_env(AWS_BEDROCK_BASE_URL=Omit(), AWS_BEARER_TOKEN_BEDROCK="", AWS_REGION="us-east-1"):
client = make_sync_client()
with pytest.raises(OpenAIError, match="requires optional AWS dependencies"):
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
-@pytest.mark.respx()
-def test_env_bearer_does_not_use_botocore_bearer_auth(monkeypatch: pytest.MonkeyPatch, respx_mock: MockRouter) -> None:
+@pytest.mark.respx2()
+def test_env_bearer_does_not_use_botocore_bearer_auth(monkeypatch: pytest.MonkeyPatch, respx2_mock: MockRouter) -> None:
auth_module = pytest.importorskip("botocore.auth")
calls = 0
real_add_auth = auth_module.BearerAuth.add_auth
@@ -180,15 +179,15 @@ def add_auth(auth: object, request: object) -> None:
real_add_auth(auth, request)
monkeypatch.setattr(auth_module.BearerAuth, "add_auth", add_auth)
- respx_mock.post("https://example.com/openai/v1/responses").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
with update_env(AWS_BEARER_TOKEN_BEDROCK="env token"):
client = make_sync_client(base_url="https://example.com/openai/v1")
client.responses.create(model="gpt-4o", input="hello")
- request = cast("list[MockRequestCall]", respx_mock.calls)[0].request
+ request = cast("list[MockRequestCall]", respx2_mock.calls)[0].request
assert request.headers["Authorization"] == "Bearer env token"
assert calls == 0
@@ -322,57 +321,57 @@ def test_requires_refreshable_tokens_to_use_provider_option(client_cls: type[Cli
)
-@pytest.mark.respx()
-def test_token_provider_refresh_sync(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
+@pytest.mark.respx2()
+def test_token_provider_refresh_sync(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json=RESPONSE_BODY),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json=RESPONSE_BODY),
]
)
tokens = iter(["first", "second"])
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
bedrock_token_provider=lambda: next(tokens),
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
max_retries=1,
)
client.responses.create(model="gpt-4o", input="hello")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers["Authorization"] == "Bearer first"
assert calls[1].request.headers["Authorization"] == "Bearer second"
@pytest.mark.asyncio
-@pytest.mark.respx()
-async def test_token_provider_refresh_async(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
+@pytest.mark.respx2()
+async def test_token_provider_refresh_async(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json=RESPONSE_BODY),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json=RESPONSE_BODY),
]
)
tokens = iter(["first", "second"])
client = AsyncBedrockOpenAI(
base_url="https://example.com/openai/v1",
bedrock_token_provider=lambda: next(tokens),
- http_client=async_http_client(trust_env=False),
+ http_client=DefaultAsyncHttpx2Client(trust_env=False),
max_retries=1,
)
await client.responses.create(model="gpt-4o", input="hello")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers["Authorization"] == "Bearer first"
assert calls[1].request.headers["Authorization"] == "Bearer second"
-@pytest.mark.respx()
-def test_explicit_aws_credentials_override_ambient_bearer(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+@pytest.mark.respx2()
+def test_explicit_aws_credentials_override_ambient_bearer(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
with update_env(AWS_BEARER_TOKEN_BEDROCK="ambient token"):
client = BedrockOpenAI(
@@ -381,22 +380,22 @@ def test_explicit_aws_credentials_override_ambient_bearer(respx_mock: MockRouter
aws_access_key_id="access key",
aws_secret_access_key="secret key",
aws_session_token="session token",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
client.responses.create(model="gpt-4o", input="hello")
- request = cast("list[MockRequestCall]", respx_mock.calls)[0].request
+ request = cast("list[MockRequestCall]", respx2_mock.calls)[0].request
assert request.headers["Authorization"].startswith("AWS4-HMAC-SHA256 Credential=access key/")
assert request.headers["X-Amz-Security-Token"] == "session token"
-@pytest.mark.respx()
-def test_aws_credentials_provider_refreshes_before_retries(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
+@pytest.mark.respx2()
+def test_aws_credentials_provider_refreshes_before_retries(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json=RESPONSE_BODY),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json=RESPONSE_BODY),
]
)
credentials = iter(
@@ -409,13 +408,13 @@ def test_aws_credentials_provider_refreshes_before_retries(respx_mock: MockRoute
base_url="https://example.com/openai/v1",
aws_region="us-east-1",
aws_credentials_provider=lambda: next(credentials),
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
max_retries=1,
)
client.responses.create(model="gpt-4o", input="hello")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert "Credential=first access key/" in calls[0].request.headers["Authorization"]
assert calls[0].request.headers["X-Amz-Security-Token"] == "first session token"
assert "Credential=second access key/" in calls[1].request.headers["Authorization"]
@@ -426,7 +425,7 @@ def test_preserves_token_provider_across_with_options() -> None:
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
bedrock_token_provider=lambda: "provider token",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
copied_client = client.with_options(timeout=1)
@@ -435,65 +434,65 @@ def test_preserves_token_provider_across_with_options() -> None:
def test_preserves_environment_bearer_across_with_options() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with update_env(AWS_BEARER_TOKEN_BEDROCK="first token"):
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
with update_env(AWS_BEARER_TOKEN_BEDROCK="second token"):
copied_client = client.with_options(timeout=1)
- copied_client.get("/models", cast_to=httpx.Response)
+ copied_client.get("/models", cast_to=httpx2.Response)
assert copied_client.api_key == "first token"
assert requests[0].headers["Authorization"] == "Bearer first token"
def test_environment_bearer_routing_copy_remains_mutable() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with update_env(AWS_BEARER_TOKEN_BEDROCK="first token"):
client = BedrockOpenAI(
aws_region="us-east-1",
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
copied_client = client.with_options(aws_region="us-west-2")
copied_client.api_key = "second token"
- copied_client.get("/models", cast_to=httpx.Response)
+ copied_client.get("/models", cast_to=httpx2.Response)
assert copied_client.api_key == "second token"
assert requests[0].headers["Authorization"] == "Bearer second token"
def test_legacy_api_key_mutation_updates_requests_and_copies() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
api_key="first token",
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
client.api_key = "second token"
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
copied_client = client.with_options(timeout=1)
- copied_client.get("/models", cast_to=httpx.Response)
+ copied_client.get("/models", cast_to=httpx2.Response)
client.api_key = "first token"
reverted_client = client.with_options(timeout=2)
- reverted_client.get("/models", cast_to=httpx.Response)
+ reverted_client.get("/models", cast_to=httpx2.Response)
assert copied_client.api_key == "second token"
assert reverted_client.api_key == "first token"
@@ -505,21 +504,21 @@ def handler(request: httpx.Request) -> httpx.Response:
def test_legacy_api_key_mutation_switches_aws_client_to_bearer() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
aws_region="us-east-1",
aws_access_key_id="access key",
aws_secret_access_key="secret key",
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
client.api_key = "bearer token"
- client.get("/models", cast_to=httpx.Response, options={"follow_redirects": True})
+ client.get("/models", cast_to=httpx2.Response, options={"follow_redirects": True})
assert requests[0].headers["Authorization"] == "Bearer bearer token"
@@ -528,7 +527,7 @@ def test_explicit_aws_copy_override_wins_over_mutated_api_key() -> None:
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
api_key="first token",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
client.api_key = "second token"
@@ -545,20 +544,20 @@ def test_explicit_aws_copy_override_wins_over_mutated_api_key() -> None:
def test_clearing_legacy_bearer_does_not_switch_to_aws_authentication() -> None:
network_calls = 0
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
with update_env(AWS_ACCESS_KEY_ID="access key", AWS_SECRET_ACCESS_KEY="secret key"):
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
api_key="bearer token",
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
client.api_key = None # type: ignore[assignment]
with pytest.raises(OpenAIError, match="bearer credential must not be empty"):
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert network_calls == 0
@@ -570,7 +569,7 @@ def test_legacy_state_repr_does_not_expose_credentials() -> None:
aws_access_key_id="secret access key id",
aws_secret_access_key="secret access key",
aws_session_token="secret session token",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
assert "secret" not in repr(client._bedrock_state)
@@ -578,7 +577,7 @@ def test_legacy_state_repr_does_not_expose_credentials() -> None:
bearer_client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
api_key="secret bearer token",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
assert "secret bearer token" not in repr(bearer_client._bedrock_runtime_signature)
@@ -648,7 +647,7 @@ def test_preserves_aws_credentials_across_with_options() -> None:
aws_region="us-east-1",
aws_access_key_id="access key",
aws_secret_access_key="secret key",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
copied_client = client.with_options(timeout=1)
@@ -912,13 +911,13 @@ def __init__(
organization: str | None = None,
project: str | None = None,
webhook_secret: str | None = None,
- base_url: str | httpx.URL | None = None,
- websocket_base_url: str | httpx.URL | None = None,
+ base_url: str | httpx2.URL | None = None,
+ websocket_base_url: str | httpx2.URL | None = None,
timeout: Any = None,
max_retries: int = 2,
default_headers: Any = None,
default_query: Any = None,
- http_client: httpx.Client | None = None,
+ http_client: httpx2.Client | None = None,
_enforce_credentials: bool = True,
) -> None:
super().__init__(
@@ -942,7 +941,7 @@ def __init__(
client = LegacyBedrockOpenAI(
api_key="token",
aws_region="us-east-1",
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
)
copied_client = client.with_options(timeout=1).with_options(aws_region="us-west-2")
@@ -1031,10 +1030,10 @@ def test_rejects_non_bedrock_copy_auth(copy_kwargs: dict[str, Any]) -> None:
client.with_options(**copy_kwargs)
-@pytest.mark.respx()
-def test_passes_non_responses_resources_through(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/chat/completions").mock(
- return_value=httpx.Response(
+@pytest.mark.respx2()
+def test_passes_non_responses_resources_through(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/chat/completions").mock(
+ return_value=httpx2.Response(
404,
json={"error": {"message": "AWS does not support chat completions here"}},
headers={"x-request-id": "req_chat"},
@@ -1046,15 +1045,15 @@ def test_passes_non_responses_resources_through(respx_mock: MockRouter) -> None:
client.chat.completions.create(model="gpt-4o", messages=[])
assert exc.value.request_id == "req_chat"
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.url == URL("https://example.com/openai/v1/chat/completions")
@pytest.mark.asyncio
-@pytest.mark.respx()
-async def test_passes_non_responses_resources_through_async(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/chat/completions").mock(
- return_value=httpx.Response(
+@pytest.mark.respx2()
+async def test_passes_non_responses_resources_through_async(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/chat/completions").mock(
+ return_value=httpx2.Response(
404,
json={"error": {"message": "AWS does not support chat completions here"}},
headers={"x-request-id": "req_chat"},
@@ -1066,14 +1065,14 @@ async def test_passes_non_responses_resources_through_async(respx_mock: MockRout
await client.chat.completions.create(model="gpt-4o", messages=[])
assert exc.value.request_id == "req_chat"
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.url == URL("https://example.com/openai/v1/chat/completions")
-@pytest.mark.respx()
-def test_passes_responses_features_through(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+@pytest.mark.respx2()
+def test_passes_responses_features_through(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token")
@@ -1084,14 +1083,14 @@ def test_passes_responses_features_through(respx_mock: MockRouter) -> None:
)
assert response.id == "resp_123"
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert json.loads(calls[0].request.content)["tools"] == [{"type": "web_search_preview"}]
-@pytest.mark.respx()
-def test_passes_admin_security_routes_through(respx_mock: MockRouter) -> None:
- respx_mock.get("https://example.com/openai/v1/organization/invites").mock(
- return_value=httpx.Response(
+@pytest.mark.respx2()
+def test_passes_admin_security_routes_through(respx2_mock: MockRouter) -> None:
+ respx2_mock.get("https://example.com/openai/v1/organization/invites").mock(
+ return_value=httpx2.Response(
404,
json={"error": {"message": "AWS does not support organization invites here"}},
headers={"x-request-id": "req_admin"},
@@ -1102,16 +1101,16 @@ def test_passes_admin_security_routes_through(respx_mock: MockRouter) -> None:
with pytest.raises(NotFoundError, match="AWS does not support organization invites here"):
list(client.admin.organization.invites.list())
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers["Authorization"] == "Bearer token"
-@pytest.mark.respx()
-def test_refreshes_token_provider_for_admin_security_routes(respx_mock: MockRouter) -> None:
- respx_mock.get("https://example.com/openai/v1/organization/invites").mock(
+@pytest.mark.respx2()
+def test_refreshes_token_provider_for_admin_security_routes(respx2_mock: MockRouter) -> None:
+ respx2_mock.get("https://example.com/openai/v1/organization/invites").mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(
404,
json={"error": {"message": "AWS does not support organization invites here"}},
headers={"x-request-id": "req_admin"},
@@ -1122,43 +1121,43 @@ def test_refreshes_token_provider_for_admin_security_routes(respx_mock: MockRout
client = BedrockOpenAI(
base_url="https://example.com/openai/v1",
bedrock_token_provider=lambda: next(tokens),
- http_client=sync_http_client(trust_env=False),
+ http_client=DefaultHttpx2Client(trust_env=False),
max_retries=1,
)
with pytest.raises(NotFoundError, match="AWS does not support organization invites here"):
list(client.admin.organization.invites.list())
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert calls[0].request.headers["Authorization"] == "Bearer first"
assert calls[1].request.headers["Authorization"] == "Bearer second"
-@pytest.mark.respx()
-def test_allows_responses_http_methods(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+@pytest.mark.respx2()
+def test_allows_responses_http_methods(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
- respx_mock.get("https://example.com/openai/v1/responses/resp_123?starting_after=1&stream=true").mock(
- return_value=httpx.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"})
+ respx2_mock.get("https://example.com/openai/v1/responses/resp_123?starting_after=1&stream=true").mock(
+ return_value=httpx2.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"})
)
- respx_mock.get("https://example.com/openai/v1/responses/resp_123?stream=true").mock(
- return_value=httpx.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"})
+ respx2_mock.get("https://example.com/openai/v1/responses/resp_123?stream=true").mock(
+ return_value=httpx2.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"})
)
- respx_mock.get("https://example.com/openai/v1/responses/resp_123").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+ respx2_mock.get("https://example.com/openai/v1/responses/resp_123").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
- respx_mock.post("https://example.com/openai/v1/responses/resp_123/cancel").mock(
- return_value=httpx.Response(200, json=RESPONSE_BODY)
+ respx2_mock.post("https://example.com/openai/v1/responses/resp_123/cancel").mock(
+ return_value=httpx2.Response(200, json=RESPONSE_BODY)
)
- respx_mock.post("https://example.com/openai/v1/responses/compact").mock(
- return_value=httpx.Response(200, json=COMPACTED_RESPONSE_BODY)
+ respx2_mock.post("https://example.com/openai/v1/responses/compact").mock(
+ return_value=httpx2.Response(200, json=COMPACTED_RESPONSE_BODY)
)
- respx_mock.get("https://example.com/openai/v1/responses/resp_123/input_items").mock(
- return_value=httpx.Response(200, json=INPUT_ITEMS_BODY)
+ respx2_mock.get("https://example.com/openai/v1/responses/resp_123/input_items").mock(
+ return_value=httpx2.Response(200, json=INPUT_ITEMS_BODY)
)
- respx_mock.post("https://example.com/openai/v1/responses/input_tokens").mock(
- return_value=httpx.Response(200, json=INPUT_TOKENS_BODY)
+ respx2_mock.post("https://example.com/openai/v1/responses/input_tokens").mock(
+ return_value=httpx2.Response(200, json=INPUT_TOKENS_BODY)
)
client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token")
@@ -1173,17 +1172,17 @@ def test_allows_responses_http_methods(respx_mock: MockRouter) -> None:
assert list(client.responses.input_items.list("resp_123")) == []
assert client.responses.input_tokens.count(model="gpt-4o", input="hello").input_tokens == 1
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert {call.request.headers["Authorization"] for call in calls} == {"Bearer token"}
-@pytest.mark.respx()
-def test_allows_sse_and_response_wrappers(respx_mock: MockRouter) -> None:
- respx_mock.post("https://example.com/openai/v1/responses").mock(
+@pytest.mark.respx2()
+def test_allows_sse_and_response_wrappers(respx2_mock: MockRouter) -> None:
+ respx2_mock.post("https://example.com/openai/v1/responses").mock(
side_effect=[
- httpx.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"}),
- httpx.Response(200, json=RESPONSE_BODY),
- httpx.Response(200, json=RESPONSE_BODY),
+ httpx2.Response(200, text=response_created_sse(), headers={"Content-Type": "text/event-stream"}),
+ httpx2.Response(200, json=RESPONSE_BODY),
+ httpx2.Response(200, json=RESPONSE_BODY),
]
)
client = make_sync_client(base_url="https://example.com/openai/v1", api_key="token")
diff --git a/tests/lib/test_bedrock_auth_conformance.py b/tests/lib/test_bedrock_auth_conformance.py
index 7478b08cbd..08953fa592 100644
--- a/tests/lib/test_bedrock_auth_conformance.py
+++ b/tests/lib/test_bedrock_auth_conformance.py
@@ -9,7 +9,7 @@
from pathlib import Path
from datetime import datetime
-import httpx
+import httpx2
import pytest
import jsonschema
@@ -50,7 +50,7 @@ def utcnow(cls) -> datetime:
monkeypatch.setattr(botocore_auth.datetime, "datetime", FrozenDatetime)
-def _lower_headers(headers: httpx.Headers | dict[str, str]) -> dict[str, str]:
+def _lower_headers(headers: httpx2.Headers | dict[str, str]) -> dict[str, str]:
return {name.lower(): value for name, value in headers.items()}
@@ -59,7 +59,7 @@ def _canonical_request_sha256(case: dict[str, Any], signed_headers: dict[str, st
authorization = signed_headers["authorization"]
signed_header_names = authorization.split("SignedHeaders=", 1)[1].split(",", 1)[0].split(";")
canonical_headers = "".join(f"{name}:{' '.join(signed_headers[name].split())}\n" for name in signed_header_names)
- url = httpx.URL(request["url"])
+ url = httpx2.URL(request["url"])
canonical_request = "\n".join(
(
request["method"],
@@ -96,7 +96,7 @@ def test_shared_sigv4_fixture_matches_node(monkeypatch: pytest.MonkeyPatch) -> N
url=request["url"],
headers={
"content-type": request["contentType"],
- "host": httpx.URL(request["url"]).host,
+ "host": httpx2.URL(request["url"]).host,
},
body=body,
)
@@ -123,7 +123,7 @@ def test_auth_selection_fixture(case: dict[str, Any], monkeypatch: pytest.Monkey
explicit = case["given"]["explicit"]
kwargs: dict[str, Any] = {
"aws_region": "us-east-1",
- "http_client": httpx.Client(trust_env=False),
+ "http_client": httpx2.Client(trust_env=False),
"_enforce_credentials": False,
}
if "bearer" in explicit:
@@ -217,12 +217,12 @@ def credentials_provider() -> _Credentials:
_freeze_botocore_time(monkeypatch, timestamps)
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
statuses = iter(case["given"]["response_statuses"])
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(next(statuses), request=request, json={})
+ return httpx2.Response(next(statuses), request=request, json={})
body = base64.b64decode(case["given"]["body_base64"])
with OpenAI(
@@ -232,12 +232,12 @@ def handler(request: httpx.Request) -> httpx.Response:
credential_provider=credentials_provider,
),
max_retries=case["given"].get("max_retries", 1),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
client.post(
"/responses",
content=body,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/json"}},
)
@@ -254,7 +254,7 @@ def test_body_replay_fixture(case: dict[str, Any]) -> None:
provider_calls = 0
network_calls = 0
body_reads = 0
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
def credentials_provider() -> _Credentials:
nonlocal provider_calls
@@ -267,12 +267,12 @@ def body() -> Iterator[bytes]:
for chunk in case["given"].get("chunks_base64", []):
yield base64.b64decode(chunk)
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
requests.append(request)
statuses = case["given"].get("response_statuses", [200])
- return httpx.Response(statuses[network_calls - 1], request=request, json={})
+ return httpx2.Response(statuses[network_calls - 1], request=request, json={})
body_kind = case["given"]["body_kind"]
content: bytes | Iterator[bytes]
@@ -289,13 +289,13 @@ def handler(request: httpx.Request) -> httpx.Response:
credential_provider=credentials_provider,
),
max_retries=case["given"].get("max_retries", 1),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
if case["expected"]["result"] == "bedrock_non_replayable_body":
with pytest.raises(OpenAIError, match="requires a replayable request body"):
- client.post("/responses", content=content, cast_to=httpx.Response)
+ client.post("/responses", content=content, cast_to=httpx2.Response)
else:
- client.post("/responses", content=content, cast_to=httpx.Response)
+ client.post("/responses", content=content, cast_to=httpx2.Response)
assert network_calls == case["expected"].get("network_attempts", case["expected"].get("attempts"))
if body_kind == "bytes":
@@ -321,10 +321,10 @@ async def body() -> AsyncIterator[bytes]:
body_reads += 1
yield b"body"
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
async with AsyncOpenAI(
provider=bedrock(
@@ -332,10 +332,10 @@ async def handler(request: httpx.Request) -> httpx.Response:
region="us-east-1",
credential_provider=credentials_provider,
),
- http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
with pytest.raises(OpenAIError, match="requires a replayable request body"):
- await client.post("/responses", content=body(), cast_to=httpx.Response)
+ await client.post("/responses", content=body(), cast_to=httpx2.Response)
assert (body_reads, provider_calls, network_calls) == (0, 0, 0)
@@ -349,8 +349,8 @@ def credentials_provider() -> _Credentials:
provider_threads.append(threading.get_ident())
return _Credentials("access-key", "secret-key")
- async def handler(request: httpx.Request) -> httpx.Response:
- return httpx.Response(200, request=request, json={})
+ async def handler(request: httpx2.Request) -> httpx2.Response:
+ return httpx2.Response(200, request=request, json={})
async with AsyncOpenAI(
provider=bedrock(
@@ -358,20 +358,20 @@ async def handler(request: httpx.Request) -> httpx.Response:
region="us-east-1",
credential_provider=credentials_provider,
),
- http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
- await client.post("/responses", content=b"{}", cast_to=httpx.Response)
+ await client.post("/responses", content=b"{}", cast_to=httpx2.Response)
assert provider_threads
assert all(thread_id != event_loop_thread for thread_id in provider_threads)
def test_custom_http_client_auth_cannot_replace_sigv4() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with OpenAI(
provider=bedrock(
@@ -380,25 +380,25 @@ def handler(request: httpx.Request) -> httpx.Response:
access_key_id="access-key",
secret_access_key="secret-key",
),
- http_client=httpx.Client(
- auth=httpx.BasicAuth("username", "password"),
- transport=httpx.MockTransport(handler),
+ http_client=httpx2.Client(
+ auth=httpx2.BasicAuth("username", "password"),
+ transport=httpx2.MockTransport(handler),
trust_env=False,
),
) as client:
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert requests[0].headers["Authorization"].startswith("AWS4-HMAC-SHA256 Credential=access-key/")
def test_sigv4_redirects_are_not_followed() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
if len(requests) == 1:
- return httpx.Response(307, request=request, headers={"Location": "/redirected"})
- return httpx.Response(200, request=request)
+ return httpx2.Response(307, request=request, headers={"Location": "/redirected"})
+ return httpx2.Response(200, request=request)
with OpenAI(
provider=bedrock(
@@ -407,10 +407,10 @@ def handler(request: httpx.Request) -> httpx.Response:
access_key_id="access-key",
secret_access_key="secret-key",
),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
with pytest.raises(APIStatusError) as exc:
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert exc.value.status_code == 307
assert len(requests) == 1
diff --git a/tests/lib/test_bedrock_credential_chain.py b/tests/lib/test_bedrock_credential_chain.py
index 93e476fe5b..fec363aeb1 100644
--- a/tests/lib/test_bedrock_credential_chain.py
+++ b/tests/lib/test_bedrock_credential_chain.py
@@ -10,7 +10,7 @@
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from typing_extensions import override
-import httpx
+import httpx2
import pytest
from openai import OpenAI
@@ -69,18 +69,18 @@ def _isolate_aws_environment(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) ->
return config_path, credentials_path
-def _signed_request(**provider_options: Any) -> httpx.Request:
- requests: list[httpx.Request] = []
+def _signed_request(**provider_options: Any) -> httpx2.Request:
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with OpenAI(
provider=bedrock(**provider_options),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert len(requests) == 1
return requests[0]
@@ -95,7 +95,7 @@ def _credentials_metadata(name: str, *, expiration: str = _FUTURE_EXPIRATION) ->
}
-def _assert_signed_with(request: httpx.Request, name: str, *, region: str) -> None:
+def _assert_signed_with(request: httpx2.Request, name: str, *, region: str) -> None:
assert request.url.host == f"bedrock-mantle.{region}.api.aws"
assert f"Credential={name}-access-key/" in request.headers["Authorization"]
assert request.headers["X-Amz-Security-Token"] == f"{name}-session-token"
@@ -370,18 +370,18 @@ def get_credentials(_: object) -> Any:
return credentials
monkeypatch.setattr(session_module.Session, "get_credentials", get_credentials)
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(500 if len(requests) == 1 else 200, request=request, json={})
+ return httpx2.Response(500 if len(requests) == 1 else 200, request=request, json={})
with OpenAI(
provider=bedrock(),
max_retries=1,
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
) as client:
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert refreshes == 2
assert len(requests) == 2
diff --git a/tests/lib/test_bedrock_provider.py b/tests/lib/test_bedrock_provider.py
index 236ce21359..7fd1ab971a 100644
--- a/tests/lib/test_bedrock_provider.py
+++ b/tests/lib/test_bedrock_provider.py
@@ -3,7 +3,7 @@
import builtins
from typing import Any, Iterator, cast
-import httpx
+import httpx2
import pytest
import openai.lib._bedrock_auth as bedrock_auth_module
@@ -15,47 +15,47 @@
def test_sync_provider_owns_endpoint_and_bearer_authentication() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
client = OpenAI(
provider=bedrock(region="us-east-1", api_key="bedrock token"),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
- assert client.base_url == httpx.URL("https://bedrock-mantle.us-east-1.api.aws/openai/v1/")
- assert requests[0].url == httpx.URL("https://bedrock-mantle.us-east-1.api.aws/openai/v1/models")
+ assert client.base_url == httpx2.URL("https://bedrock-mantle.us-east-1.api.aws/openai/v1/")
+ assert requests[0].url == httpx2.URL("https://bedrock-mantle.us-east-1.api.aws/openai/v1/models")
assert requests[0].headers["Authorization"] == "Bearer bedrock token"
@pytest.mark.asyncio
async def test_async_provider_owns_endpoint_and_bearer_authentication() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
client = AsyncOpenAI(
provider=bedrock(region="us-east-1", token_provider=lambda: "bedrock token"),
- http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(handler), trust_env=False),
)
- await client.get("/models", cast_to=httpx.Response)
+ await client.get("/models", cast_to=httpx2.Response)
await client.close()
assert requests[0].headers["Authorization"] == "Bearer bedrock token"
def test_provider_ignores_openai_environment_configuration() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with update_env(
OPENAI_API_KEY="openai token",
@@ -64,9 +64,9 @@ def handler(request: httpx.Request) -> httpx.Response:
):
client = OpenAI(
provider=bedrock(region="us-east-1", api_key="bedrock token"),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert client.api_key == ""
assert requests[0].url.host == "bedrock-mantle.us-east-1.api.aws"
@@ -98,16 +98,16 @@ def test_provider_survives_with_options_and_can_be_replaced() -> None:
assert copied.base_url == client.base_url
assert copied._provider is client._provider
- assert replaced.base_url == httpx.URL("https://bedrock-mantle.eu-west-1.api.aws/openai/v1/")
+ assert replaced.base_url == httpx2.URL("https://bedrock-mantle.eu-west-1.api.aws/openai/v1/")
assert replaced._provider is not client._provider
def test_switching_to_provider_drops_inherited_openai_metadata() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with update_env(
OPENAI_CUSTOM_HEADERS="X-OpenAI-Ambient: leak",
@@ -117,11 +117,11 @@ def handler(request: httpx.Request) -> httpx.Response:
client = OpenAI(
api_key="openai token",
default_headers={"X-OpenAI-Custom": "leak"},
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
provider_client = client.with_options(provider=bedrock(region="us-east-1", api_key="bedrock token"))
- provider_client.get("/models", cast_to=httpx.Response)
+ provider_client.get("/models", cast_to=httpx2.Response)
headers = requests[0].headers
assert headers["Authorization"] == "Bearer bedrock token"
@@ -133,22 +133,22 @@ def handler(request: httpx.Request) -> httpx.Response:
@pytest.mark.asyncio
async def test_async_switching_to_provider_drops_inherited_openai_metadata() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
client = AsyncOpenAI(
api_key="openai token",
organization="openai-org",
project="openai-project",
default_headers={"X-OpenAI-Custom": "leak"},
- http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(handler), trust_env=False),
)
provider_client = client.with_options(provider=bedrock(region="us-east-1", api_key="bedrock token"))
- await provider_client.get("/models", cast_to=httpx.Response)
+ await provider_client.get("/models", cast_to=httpx2.Response)
await provider_client.close()
headers = requests[0].headers
@@ -159,11 +159,11 @@ async def handler(request: httpx.Request) -> httpx.Response:
def test_provider_metadata_survives_same_provider_clone_but_not_replacement() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
first_provider = bedrock(region="us-east-1", api_key="first token")
client = OpenAI(
@@ -171,12 +171,12 @@ def handler(request: httpx.Request) -> httpx.Response:
organization="provider-org",
project="provider-project",
default_headers={"X-Provider-Custom": "preserve-me"},
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
- client.with_options(timeout=1).get("/models", cast_to=httpx.Response)
+ client.with_options(timeout=1).get("/models", cast_to=httpx2.Response)
client.with_options(provider=bedrock(region="us-east-1", api_key="second token")).get(
- "/models", cast_to=httpx.Response
+ "/models", cast_to=httpx2.Response
)
same_provider_headers, replacement_headers = (request.headers for request in requests)
@@ -193,8 +193,8 @@ class NormalizingProvider:
name = "normalizing"
def configure(self) -> _ProviderRuntime:
- def normalize(response: httpx.Response) -> httpx.Response:
- return httpx.Response(200, request=response.request, json={"normalized": True})
+ def normalize(response: httpx2.Response) -> httpx2.Response:
+ return httpx2.Response(200, request=response.request, json={"normalized": True})
return _ProviderRuntime(
name=self.name,
@@ -205,35 +205,35 @@ def normalize(response: httpx.Response) -> httpx.Response:
client = OpenAI(
provider=_create_provider(NormalizingProvider()),
max_retries=0,
- http_client=httpx.Client(
- transport=httpx.MockTransport(lambda request: httpx.Response(500, request=request, json={})),
+ http_client=httpx2.Client(
+ transport=httpx2.MockTransport(lambda request: httpx2.Response(500, request=request, json={})),
trust_env=False,
),
)
- response = client.get("/models", cast_to=httpx.Response)
+ response = client.get("/models", cast_to=httpx2.Response)
assert response.status_code == 200
assert response.json() == {"normalized": True}
def test_environment_bearer_mode_survives_clone_and_refreshes_each_attempt() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with update_env(AWS_BEARER_TOKEN_BEDROCK="first token"):
client = OpenAI(
provider=bedrock(region="us-east-1"),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
copied = client.with_options(timeout=1)
with update_env(AWS_BEARER_TOKEN_BEDROCK="second token"):
- copied.get("/models", cast_to=httpx.Response)
+ copied.get("/models", cast_to=httpx2.Response)
assert [request.headers["Authorization"] for request in requests] == ["Bearer first token", "Bearer second token"]
@@ -251,7 +251,7 @@ def test_provider_can_be_removed_with_explicit_openai_credentials() -> None:
assert copied._provider is None
assert copied.api_key == "openai token"
- assert copied.base_url == httpx.URL("https://api.openai.com/v1/")
+ assert copied.base_url == httpx2.URL("https://api.openai.com/v1/")
assert copied.organization is None
assert copied.project is None
assert "X-Provider-Custom" not in copied.default_headers
@@ -285,29 +285,29 @@ def import_module(
raise ImportError(name)
return real_import(name, globals, locals, fromlist, level)
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
monkeypatch.setattr(builtins, "__import__", import_module)
client = OpenAI(
provider=bedrock(region="us-east-1"),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
with pytest.raises(OpenAIError, match=r"pip install openai\[bedrock\]"):
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert network_calls == 0
def test_api_key_none_skips_environment_bearer_fallback() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with update_env(
AWS_BEARER_TOKEN_BEDROCK="environment bearer",
@@ -316,9 +316,9 @@ def handler(request: httpx.Request) -> httpx.Response:
):
client = OpenAI(
provider=bedrock(region="us-east-1", api_key=None),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert requests[0].headers["Authorization"].startswith("AWS4-HMAC-SHA256 Credential=access key/")
@@ -326,20 +326,20 @@ def handler(request: httpx.Request) -> httpx.Response:
def test_provider_rejects_custom_authorization_before_network() -> None:
network_calls = 0
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
client = OpenAI(
provider=bedrock(region="us-east-1", api_key="bedrock token"),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
with pytest.raises(OpenAIError, match="cannot be combined with a custom `Authorization` header"):
client.get(
"/models",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Authorization": "Bearer custom"}},
)
@@ -355,18 +355,18 @@ def token_provider() -> str:
provider_calls += 1
return "bedrock token"
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
client = OpenAI(
provider=bedrock(base_url="https://bedrock.example/openai/v1", token_provider=token_provider),
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
with pytest.raises(OpenAIError, match="origin other than the configured provider URL"):
- client.get("https://attacker.example/steal", cast_to=httpx.Response)
+ client.get("https://attacker.example/steal", cast_to=httpx2.Response)
assert (provider_calls, network_calls) == (0, 0)
@@ -381,40 +381,40 @@ async def token_provider() -> str:
provider_calls += 1
return "bedrock token"
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
nonlocal network_calls
network_calls += 1
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
client = AsyncOpenAI(
provider=bedrock(base_url="https://bedrock.example/openai/v1", token_provider=token_provider),
- http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(handler), trust_env=False),
)
with pytest.raises(OpenAIError, match="origin other than the configured provider URL"):
- await client.get("https://attacker.example/steal", cast_to=httpx.Response)
+ await client.get("https://attacker.example/steal", cast_to=httpx2.Response)
await client.close()
assert (provider_calls, network_calls) == (0, 0)
def test_bearer_provider_allows_one_shot_body_when_retries_are_disabled() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
def body() -> Iterator[bytes]:
yield b"body"
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request)
+ return httpx2.Response(200, request=request)
client = OpenAI(
provider=bedrock(base_url="https://bedrock.example/openai/v1", api_key="bedrock token"),
max_retries=0,
- http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False),
)
- client.post("/responses", content=body(), cast_to=httpx.Response)
+ client.post("/responses", content=body(), cast_to=httpx2.Response)
assert requests[0].content == b"body"
diff --git a/tests/respx2/FORK.md b/tests/respx2/FORK.md
new file mode 100644
index 0000000000..18b9cb24d8
--- /dev/null
+++ b/tests/respx2/FORK.md
@@ -0,0 +1,13 @@
+# HTTPX2-native RESPX fork
+
+This directory contains an SDK test-only fork of RESPX 0.23.1.
+
+- Upstream: https://github.com/lundberg/respx
+- Upstream tag: `0.23.1`
+- Upstream commit: `fc8b43bc74a69d07a6bdccf61522069b12bb8fad`
+- License: BSD 3-Clause; the original license is preserved in `LICENSE.md`.
+- The upstream README is preserved without modification in `README.md`.
+
+The fork replaces HTTPX and HTTPCORE imports and interception targets with HTTPX2 and HTTPCORE2, exposes the `respx2` pytest marker and `respx2_mock` fixture, and changes package imports to `tests.respx2`. This lets the SDK retain RESPX request matching, response side effects, decorators, and call history without installing legacy HTTPX in its normal test environment.
+
+The fork is limited to the SDK test suite and may be removed or upstreamed once RESPX supports HTTPX2 without requiring legacy HTTPX.
diff --git a/tests/respx2/LICENSE.md b/tests/respx2/LICENSE.md
new file mode 100644
index 0000000000..07b3b0b2b5
--- /dev/null
+++ b/tests/respx2/LICENSE.md
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2019, 5 Monkeys Agency AB
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tests/respx2/README.md b/tests/respx2/README.md
new file mode 100644
index 0000000000..392ac41a86
--- /dev/null
+++ b/tests/respx2/README.md
@@ -0,0 +1,84 @@
+
+
+
+
+ RESPX - Mock HTTPX with awesome request patterns and response side effects.
+
+
+---
+
+[](https://github.com/lundberg/respx/actions/workflows/test.yml)
+[](https://codecov.io/gh/lundberg/respx)
+[](https://pypi.org/project/respx/)
+[](https://pypi.org/project/respx/)
+[](https://pypi.org/project/respx/)
+
+## Documentation
+
+Full documentation is available at
+[lundberg.github.io/respx](https://lundberg.github.io/respx/)
+
+## QuickStart
+
+RESPX is a simple, _yet powerful_, utility for mocking out the
+[HTTPX](https://www.python-httpx.org/), _and
+[HTTP Core](https://www.encode.io/httpcore/)_, libraries.
+
+Start by [patching](https://lundberg.github.io/respx/guide/#mock-httpx) `HTTPX`, using
+`respx.mock`, then add request
+[routes](https://lundberg.github.io/respx/guide/#routing-requests) to mock
+[responses](https://lundberg.github.io/respx/guide/#mocking-responses).
+
+```python
+import httpx
+import respx
+
+from httpx import Response
+
+
+@respx.mock
+def test_example():
+ my_route = respx.get("https://example.org/").mock(return_value=Response(204))
+ response = httpx.get("https://example.org/")
+ assert my_route.called
+ assert response.status_code == 204
+```
+
+> Read the [User Guide](https://lundberg.github.io/respx/guide/) for a complete
+> walk-through.
+
+### pytest + httpx
+
+For a neater `pytest` experience, RESPX includes a `respx_mock` _fixture_ for easy
+`HTTPX` mocking, along with an optional `respx` _marker_ to fine-tune the mock
+[settings](https://lundberg.github.io/respx/api/#configuration).
+
+```python
+import httpx
+import pytest
+
+
+def test_default(respx_mock):
+ respx_mock.get("https://foo.bar/").mock(return_value=httpx.Response(204))
+ response = httpx.get("https://foo.bar/")
+ assert response.status_code == 204
+
+
+@pytest.mark.respx(base_url="https://foo.bar")
+def test_with_marker(respx_mock):
+ respx_mock.get("/baz/").mock(return_value=httpx.Response(204))
+ response = httpx.get("https://foo.bar/baz/")
+ assert response.status_code == 204
+```
+
+## Installation
+
+Install with pip:
+
+```console
+$ pip install respx
+```
+
+Requires Python 3.8+ and HTTPX 0.25+. See
+[Changelog](https://github.com/lundberg/respx/blob/master/CHANGELOG.md) for older HTTPX
+compatibility.
diff --git a/tests/respx2/__init__.py b/tests/respx2/__init__.py
new file mode 100644
index 0000000000..13694fdc82
--- /dev/null
+++ b/tests/respx2/__init__.py
@@ -0,0 +1,56 @@
+from .__version__ import __version__
+from .handlers import ASGIHandler, WSGIHandler
+from .models import MockResponse, Route
+from .router import MockRouter, Router
+from .utils import SetCookie
+
+from .api import ( # isort:skip
+ mock,
+ routes,
+ calls,
+ start,
+ stop,
+ clear,
+ reset,
+ pop,
+ route,
+ add,
+ request,
+ get,
+ post,
+ put,
+ patch,
+ delete,
+ head,
+ options,
+)
+
+
+__all__ = [
+ "__version__",
+ "MockResponse",
+ "MockRouter",
+ "ASGIHandler",
+ "WSGIHandler",
+ "Router",
+ "Route",
+ "SetCookie",
+ "mock",
+ "routes",
+ "calls",
+ "start",
+ "stop",
+ "clear",
+ "reset",
+ "pop",
+ "route",
+ "add",
+ "request",
+ "get",
+ "post",
+ "put",
+ "patch",
+ "delete",
+ "head",
+ "options",
+]
diff --git a/tests/respx2/__version__.py b/tests/respx2/__version__.py
new file mode 100644
index 0000000000..43e16f5d29
--- /dev/null
+++ b/tests/respx2/__version__.py
@@ -0,0 +1 @@
+__version__ = "0.23.1"
diff --git a/tests/respx2/api.py b/tests/respx2/api.py
new file mode 100644
index 0000000000..89e123c60b
--- /dev/null
+++ b/tests/respx2/api.py
@@ -0,0 +1,116 @@
+from typing import Any, Optional, Union, overload
+
+from .models import CallList, Route
+from .patterns import Pattern
+from .router import MockRouter
+from .types import DefaultType, URLPatternTypes
+
+mock = MockRouter(assert_all_called=False)
+
+routes = mock.routes
+calls: CallList = mock.calls
+
+
+def start() -> None:
+ global mock
+ mock.start()
+
+
+def stop(clear: bool = True, reset: bool = True) -> None:
+ global mock
+ mock.stop(clear=clear, reset=reset)
+
+
+def clear() -> None:
+ global mock
+ mock.clear()
+
+
+def reset() -> None:
+ global mock
+ mock.reset()
+
+
+@overload
+def pop(name: str) -> Route:
+ ... # pragma: nocover
+
+
+@overload
+def pop(name: str, default: DefaultType) -> Union[Route, DefaultType]:
+ ... # pragma: nocover
+
+
+def pop(name, default=...):
+ global mock
+ return mock.pop(name, default=default)
+
+
+def route(*patterns: Pattern, name: Optional[str] = None, **lookups: Any) -> Route:
+ global mock
+ return mock.route(*patterns, name=name, **lookups)
+
+
+def add(route: Route, *, name: Optional[str] = None) -> Route:
+ global mock
+ return mock.add(route, name=name)
+
+
+def request(
+ method: str,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+) -> Route:
+ global mock
+ return mock.request(method, url, name=name, **lookups)
+
+
+def get(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.get(url, name=name, **lookups)
+
+
+def post(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.post(url, name=name, **lookups)
+
+
+def put(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.put(url, name=name, **lookups)
+
+
+def patch(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.patch(url, name=name, **lookups)
+
+
+def delete(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.delete(url, name=name, **lookups)
+
+
+def head(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.head(url, name=name, **lookups)
+
+
+def options(
+ url: Optional[URLPatternTypes] = None, *, name: Optional[str] = None, **lookups: Any
+) -> Route:
+ global mock
+ return mock.options(url, name=name, **lookups)
diff --git a/tests/respx2/fixtures.py b/tests/respx2/fixtures.py
new file mode 100644
index 0000000000..1513fbf74f
--- /dev/null
+++ b/tests/respx2/fixtures.py
@@ -0,0 +1,12 @@
+try:
+ import pytest
+except ImportError: # pragma: nocover
+ pass
+else:
+ import asyncio
+
+ @pytest.fixture(scope="session")
+ def session_event_loop():
+ loop = asyncio.get_event_loop_policy().new_event_loop()
+ yield loop
+ loop.close()
diff --git a/tests/respx2/handlers.py b/tests/respx2/handlers.py
new file mode 100644
index 0000000000..b3a3cd7dda
--- /dev/null
+++ b/tests/respx2/handlers.py
@@ -0,0 +1,41 @@
+from typing import Any, Callable
+
+import httpx2 as httpx
+
+
+class TransportHandler:
+ def __init__(self, transport: httpx.BaseTransport) -> None:
+ self.transport = transport
+
+ def __call__(self, request: httpx.Request) -> httpx.Response:
+ if not isinstance(
+ request.stream,
+ httpx.SyncByteStream,
+ ): # pragma: nocover
+ raise RuntimeError("Attempted to route an async request to a sync app.")
+
+ return self.transport.handle_request(request)
+
+
+class AsyncTransportHandler:
+ def __init__(self, transport: httpx.AsyncBaseTransport) -> None:
+ self.transport = transport
+
+ async def __call__(self, request: httpx.Request) -> httpx.Response:
+ if not isinstance(
+ request.stream,
+ httpx.AsyncByteStream,
+ ): # pragma: nocover
+ raise RuntimeError("Attempted to route a sync request to an async app.")
+
+ return await self.transport.handle_async_request(request)
+
+
+class WSGIHandler(TransportHandler):
+ def __init__(self, app: Callable, **kwargs: Any) -> None:
+ super().__init__(httpx.WSGITransport(app=app, **kwargs))
+
+
+class ASGIHandler(AsyncTransportHandler):
+ def __init__(self, app: Callable, **kwargs: Any) -> None:
+ super().__init__(httpx.ASGITransport(app=app, **kwargs))
diff --git a/tests/respx2/mocks.py b/tests/respx2/mocks.py
new file mode 100644
index 0000000000..5696ee95c6
--- /dev/null
+++ b/tests/respx2/mocks.py
@@ -0,0 +1,339 @@
+import inspect
+from abc import ABC
+from types import MappingProxyType
+from typing import TYPE_CHECKING, ClassVar, Dict, List, Type
+from unittest import mock
+
+import httpcore2 as httpcore
+import httpx2 as httpx
+
+from tests.respx2.patterns import parse_url
+
+from .models import AllMockedAssertionError, PassThrough
+from .transports import TryTransport
+
+if TYPE_CHECKING:
+ from .router import Router # pragma: nocover
+
+__all__ = ["Mocker", "HTTPCoreMocker"]
+
+
+class Mocker(ABC):
+ _patches: ClassVar[List[mock._patch]]
+ name: ClassVar[str]
+ routers: ClassVar[List["Router"]]
+ targets: ClassVar[List[str]]
+ target_methods: ClassVar[List[str]]
+
+ # Automatically register all the subclasses in this dict
+ __registry: ClassVar[Dict[str, Type["Mocker"]]] = {}
+ registry = MappingProxyType(__registry)
+
+ def __init_subclass__(cls) -> None:
+ if not getattr(cls, "name", None) or ABC in cls.__bases__:
+ return
+
+ if cls.name in cls.__registry:
+ raise TypeError(
+ "Subclasses of Mocker must define a unique name. "
+ f"{cls.name!r} is already defined as {cls.__registry[cls.name]!r}"
+ )
+
+ cls.routers = []
+ cls._patches = []
+ cls.__registry[cls.name] = cls
+
+ @classmethod
+ def register(cls, router: "Router") -> None:
+ cls.routers.append(router)
+
+ @classmethod
+ def unregister(cls, router: "Router") -> bool:
+ if router in cls.routers:
+ cls.routers.remove(router)
+ return True
+ return False
+
+ @classmethod
+ def add_targets(cls, *targets: str) -> None:
+ targets = tuple(filter(lambda t: t not in cls.targets, targets))
+ if targets:
+ cls.targets.extend(targets)
+ cls.restart()
+
+ @classmethod
+ def remove_targets(cls, *targets: str) -> None:
+ targets = tuple(filter(lambda t: t in cls.targets, targets))
+ if targets:
+ for target in targets:
+ cls.targets.remove(target)
+ cls.restart()
+
+ @classmethod
+ def start(cls) -> None:
+ # Ensure we only patch once!
+ if cls._patches:
+ return
+
+ # Start patching target transports
+ for target in cls.targets:
+ for method in cls.target_methods:
+ try:
+ spec = f"{target}.{method}"
+ patch = mock.patch(spec, spec=True, new_callable=cls.mock)
+ patch.start()
+ cls._patches.append(patch)
+ except AttributeError:
+ pass
+
+ @classmethod
+ def stop(cls, force: bool = False) -> None:
+ # Ensure we don't stop patching when registered transports exists
+ if cls.routers and not force:
+ return
+
+ # Stop patching HTTPX
+ while cls._patches:
+ patch = cls._patches.pop()
+ patch.stop()
+
+ @classmethod
+ def restart(cls) -> None:
+ # Only stop and start if started
+ if cls._patches: # pragma: nocover
+ cls.stop(force=True)
+ cls.start()
+
+ @classmethod
+ def handler(cls, httpx_request):
+ httpx_response = None
+ assertion_error = None
+ for router in cls.routers:
+ try:
+ httpx_response = router.handler(httpx_request)
+ except AllMockedAssertionError as error:
+ assertion_error = error
+ continue
+ else:
+ break
+ if assertion_error and not httpx_response:
+ raise assertion_error
+ return httpx_response
+
+ @classmethod
+ async def async_handler(cls, httpx_request):
+ httpx_response = None
+ assertion_error = None
+ for router in cls.routers:
+ try:
+ httpx_response = await router.async_handler(httpx_request)
+ except AllMockedAssertionError as error:
+ assertion_error = error
+ continue
+ else:
+ break
+ if assertion_error and not httpx_response:
+ raise assertion_error
+ return httpx_response
+
+ @classmethod
+ def mock(cls, spec):
+ raise NotImplementedError() # pragma: nocover
+
+
+class HTTPXMocker(Mocker):
+ name = "httpx"
+ targets = [
+ "httpx2._client.Client",
+ "httpx2._client.AsyncClient",
+ ]
+ target_methods = ["_transport_for_url"]
+
+ @classmethod
+ def mock(cls, spec):
+ def _transport_for_url(self, *args, **kwargs):
+ handler = (
+ cls.async_handler
+ if inspect.iscoroutinefunction(self.request)
+ else cls.handler
+ )
+ mock_transport = httpx.MockTransport(handler)
+ pass_through_transport = spec(self, *args, **kwargs)
+ transport = TryTransport([mock_transport, pass_through_transport])
+ return transport
+
+ return _transport_for_url
+
+
+class AbstractRequestMocker(Mocker):
+ @classmethod
+ def mock(cls, spec):
+ if spec.__name__ not in cls.target_methods:
+ # Prevent mocking mock
+ return spec
+
+ argspec = inspect.getfullargspec(spec)
+
+ def mock(self, *args, **kwargs):
+ kwargs = cls._merge_args_and_kwargs(argspec, args, kwargs)
+ request = cls.to_httpx_request(**kwargs)
+ request, kwargs = cls.prepare_sync_request(request, **kwargs)
+ response = cls._send_sync_request(
+ request, target_spec=spec, instance=self, **kwargs
+ )
+ return response
+
+ async def amock(self, *args, **kwargs):
+ kwargs = cls._merge_args_and_kwargs(argspec, args, kwargs)
+ request = cls.to_httpx_request(**kwargs)
+ request, kwargs = await cls.prepare_async_request(request, **kwargs)
+ response = await cls._send_async_request(
+ request, target_spec=spec, instance=self, **kwargs
+ )
+ return response
+
+ return amock if inspect.iscoroutinefunction(spec) else mock
+
+ @classmethod
+ def _merge_args_and_kwargs(cls, argspec, args, kwargs):
+ arg_names = argspec.args[1:] # Omit self
+ new_kwargs = (
+ dict(zip(arg_names[-len(argspec.defaults) :], argspec.defaults))
+ if argspec.defaults
+ else dict()
+ )
+ new_kwargs.update(zip(arg_names, args))
+ new_kwargs.update(kwargs)
+ return new_kwargs
+
+ @classmethod
+ def _send_sync_request(cls, httpx_request, *, target_spec, instance, **kwargs):
+ try:
+ httpx_response = cls.handler(httpx_request)
+ except PassThrough:
+ response = target_spec(instance, **kwargs)
+ else:
+ response = cls.from_sync_httpx_response(httpx_response, instance, **kwargs)
+ return response
+
+ @classmethod
+ async def _send_async_request(
+ cls, httpx_request, *, target_spec, instance, **kwargs
+ ):
+ try:
+ httpx_response = await cls.async_handler(httpx_request)
+ except PassThrough:
+ response = await target_spec(instance, **kwargs)
+ else:
+ response = await cls.from_async_httpx_response(
+ httpx_response, instance, **kwargs
+ )
+ return response
+
+ @classmethod
+ def prepare_sync_request(cls, httpx_request, **kwargs):
+ """
+ Sync pre-read request body
+ """
+ httpx_request.read()
+ return httpx_request, kwargs
+
+ @classmethod
+ async def prepare_async_request(cls, httpx_request, **kwargs):
+ """
+ Async pre-read request body
+ """
+ await httpx_request.aread()
+ return httpx_request, kwargs
+
+ @classmethod
+ def to_httpx_request(cls, **kwargs):
+ raise NotImplementedError() # pragma: nocover
+
+ @classmethod
+ def from_sync_httpx_response(cls, httpx_response, target, **kwargs):
+ raise NotImplementedError() # pragma: nocover
+
+ @classmethod
+ async def from_async_httpx_response(cls, httpx_response, target, **kwargs):
+ raise NotImplementedError() # pragma: nocover
+
+
+class HTTPCoreMocker(AbstractRequestMocker):
+ name = "httpcore"
+ targets = [
+ "httpcore2._sync.connection.HTTPConnection",
+ "httpcore2._sync.connection_pool.ConnectionPool",
+ "httpcore2._sync.http_proxy.HTTPProxy",
+ "httpcore2._async.connection.AsyncHTTPConnection",
+ "httpcore2._async.connection_pool.AsyncConnectionPool",
+ "httpcore2._async.http_proxy.AsyncHTTPProxy",
+ ]
+ target_methods = ["handle_request", "handle_async_request"]
+
+ @classmethod
+ def prepare_sync_request(cls, httpx_request, **kwargs):
+ """
+ Sync pre-read request body, and update transport request arg.
+ """
+ httpx_request, kwargs = super().prepare_sync_request(httpx_request, **kwargs)
+ kwargs["request"].stream = httpx_request.stream
+ return httpx_request, kwargs
+
+ @classmethod
+ async def prepare_async_request(cls, httpx_request, **kwargs):
+ """
+ Async pre-read request body, and update transport request arg.
+ """
+ httpx_request, kwargs = await super().prepare_async_request(
+ httpx_request, **kwargs
+ )
+ kwargs["request"].stream = httpx_request.stream
+ return httpx_request, kwargs
+
+ @classmethod
+ def to_httpx_request(cls, **kwargs):
+ """
+ Create a `HTTPX` request from transport request arg.
+ """
+ request = kwargs["request"]
+ method = (
+ request.method.decode("ascii")
+ if isinstance(request.method, bytes)
+ else request.method
+ )
+ raw_url = (
+ request.url.scheme,
+ request.url.host,
+ request.url.port,
+ request.url.target,
+ )
+ return httpx.Request(
+ method,
+ parse_url(raw_url),
+ headers=request.headers,
+ stream=request.stream,
+ extensions=request.extensions,
+ )
+
+ @classmethod
+ def from_sync_httpx_response(cls, httpx_response, target, **kwargs):
+ """
+ Create a `httpcore` response from a `HTTPX` response.
+ """
+ return httpcore.Response(
+ status=httpx_response.status_code,
+ headers=httpx_response.headers.raw,
+ content=httpx_response.stream,
+ extensions=httpx_response.extensions,
+ )
+
+ @classmethod
+ async def from_async_httpx_response(cls, httpx_response, target, **kwargs):
+ """
+ Create a `httpcore` response from a `HTTPX` response.
+ """
+ return cls.from_sync_httpx_response(httpx_response, target, **kwargs)
+
+
+DEFAULT_MOCKER: str = HTTPCoreMocker.name
diff --git a/tests/respx2/models.py b/tests/respx2/models.py
new file mode 100644
index 0000000000..eb42b205af
--- /dev/null
+++ b/tests/respx2/models.py
@@ -0,0 +1,550 @@
+import inspect
+from typing import (
+ Any,
+ Dict,
+ Iterator,
+ List,
+ NamedTuple,
+ Optional,
+ Sequence,
+ Tuple,
+ Type,
+ Union,
+)
+from unittest import mock
+from warnings import warn
+
+import httpx2 as httpx
+
+from tests.respx2.utils import SetCookie
+
+from .patterns import M, Pattern
+from .types import (
+ CallableSideEffect,
+ Content,
+ CookieTypes,
+ HeaderTypes,
+ ResolvedResponseTypes,
+ RouteResultTypes,
+ SideEffectListTypes,
+ SideEffectTypes,
+)
+
+
+def clone_response(response: httpx.Response, request: httpx.Request) -> httpx.Response:
+ """
+ Clones a httpx Response for given request.
+ """
+ response = httpx.Response(
+ response.status_code,
+ headers=response.headers,
+ stream=response.stream,
+ request=request,
+ extensions=dict(response.extensions),
+ )
+ return response
+
+
+class Call(NamedTuple):
+ request: httpx.Request
+ optional_response: Optional[httpx.Response]
+
+ @property
+ def response(self) -> httpx.Response:
+ if self.optional_response is None:
+ raise ValueError(f"{self!r} has no response")
+ return self.optional_response
+
+ @property
+ def has_response(self) -> bool:
+ return self.optional_response is not None
+
+
+class CallList(list, mock.NonCallableMock):
+ def __init__(self, *args: Sequence[Call], name: Any = "respx") -> None:
+ super().__init__(*args)
+ mock.NonCallableMock.__init__(self, name=name)
+
+ @property
+ def called(self) -> bool: # type: ignore[override]
+ return bool(self)
+
+ @property
+ def call_count(self) -> int: # type: ignore[override]
+ return len(self)
+
+ @property
+ def last(self) -> Call:
+ return self[-1]
+
+ def record(
+ self, request: httpx.Request, response: Optional[httpx.Response]
+ ) -> Call:
+ call = Call(request=request, optional_response=response)
+ self.append(call)
+ return call
+
+
+class MockResponse(httpx.Response):
+ def __init__(
+ self,
+ status_code: Optional[int] = None,
+ *,
+ content: Optional[Content] = None,
+ content_type: Optional[str] = None,
+ http_version: Optional[str] = None,
+ cookies: Optional[Union[CookieTypes, Sequence[SetCookie]]] = None,
+ **kwargs: Any,
+ ) -> None:
+ if not isinstance(content, (str, bytes)) and (
+ callable(content) or isinstance(content, (dict, Exception))
+ ):
+ raise TypeError(
+ f"MockResponse content can only be str, bytes or byte stream"
+ f"got {content!r}. Please use json=... or side effects."
+ )
+
+ if content is not None:
+ kwargs["content"] = content
+ if http_version:
+ kwargs["extensions"] = kwargs.get("extensions", {})
+ kwargs["extensions"]["http_version"] = http_version.encode("ascii")
+ super().__init__(status_code or 200, **kwargs)
+
+ if content_type:
+ self.headers["Content-Type"] = content_type
+
+ if cookies:
+ if isinstance(cookies, dict):
+ cookies = tuple(cookies.items())
+ self.headers = httpx.Headers(
+ (
+ *self.headers.multi_items(),
+ *(
+ cookie if isinstance(cookie, SetCookie) else SetCookie(*cookie)
+ for cookie in cookies
+ ),
+ )
+ )
+
+
+class Route:
+ def __init__(
+ self,
+ *patterns: Pattern,
+ **lookups: Any,
+ ) -> None:
+ self._pattern = M(*patterns, **lookups)
+ self._return_value: Optional[httpx.Response] = None
+ self._side_effect: Optional[SideEffectTypes] = None
+ self._pass_through: bool = False
+ self._name: Optional[str] = None
+ self._snapshots: List[Tuple] = []
+ self.calls = CallList(name=self)
+ self.snapshot()
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, Route):
+ return False # pragma: nocover
+ return self.pattern == other.pattern
+
+ def __repr__(self): # pragma: nocover
+ name = f"name={self._name!r} " if self._name else ""
+ return f""
+
+ def __call__(self, side_effect: CallableSideEffect) -> CallableSideEffect:
+ self.side_effect = side_effect
+ return side_effect
+
+ def __mod__(self, response: Union[int, Dict[str, Any], httpx.Response]) -> "Route":
+ if isinstance(response, int):
+ self.return_value = httpx.Response(status_code=response)
+
+ elif isinstance(response, dict):
+ response.setdefault("status_code", 200)
+ self.return_value = httpx.Response(**response)
+
+ elif isinstance(response, httpx.Response):
+ self.return_value = response
+
+ else:
+ raise TypeError(
+ f"Route can only % with int, dict or Response, got {response!r}"
+ )
+
+ return self
+
+ @property
+ def name(self) -> Optional[str]:
+ return self._name
+
+ @name.setter
+ def name(self, name: str) -> None:
+ raise NotImplementedError("Can't set name on route.")
+
+ @property
+ def pattern(self) -> Pattern:
+ return self._pattern
+
+ @pattern.setter
+ def pattern(self, pattern: Pattern) -> None:
+ raise NotImplementedError("Can't change route pattern.")
+
+ @property
+ def return_value(self) -> Optional[httpx.Response]:
+ return self._return_value
+
+ @return_value.setter
+ def return_value(self, return_value: Optional[httpx.Response]) -> None:
+ if return_value is not None and not isinstance(return_value, httpx.Response):
+ raise TypeError(f"{return_value!r} is not an instance of httpx.Response")
+ self.pass_through(False)
+ self._return_value = return_value
+
+ @property
+ def side_effect(
+ self,
+ ) -> Optional[Union[SideEffectTypes, Sequence[SideEffectListTypes]]]:
+ return self._side_effect
+
+ @side_effect.setter
+ def side_effect(
+ self,
+ side_effect: Optional[Union[SideEffectTypes, Sequence[SideEffectListTypes]]],
+ ) -> None:
+ self.pass_through(False)
+ if not side_effect:
+ self._side_effect = None
+ elif isinstance(side_effect, (Iterator, Sequence)):
+ self._side_effect = iter(side_effect)
+ else:
+ self._side_effect = side_effect
+
+ def snapshot(self) -> None:
+ # Clone iterator-type side effect to not get pre-exhausted when rolled back
+ side_effect = self._side_effect
+ if isinstance(side_effect, Iterator):
+ side_effects = tuple(side_effect)
+ self._side_effect = iter(side_effects)
+ side_effect = iter(side_effects)
+
+ self._snapshots.append(
+ (
+ self._pattern,
+ self._name,
+ self._return_value,
+ side_effect,
+ self._pass_through,
+ CallList(self.calls, name=self),
+ ),
+ )
+
+ def rollback(self) -> None:
+ if not self._snapshots:
+ return
+
+ snapshot = self._snapshots.pop()
+ pattern, name, return_value, side_effect, pass_through, calls = snapshot
+
+ self._pattern = pattern
+ self._name = name
+ self._return_value = return_value
+ self._side_effect = side_effect
+ self.pass_through(pass_through)
+ self.calls[:] = calls
+
+ def reset(self) -> None:
+ self.calls.clear()
+
+ def mock(
+ self,
+ return_value: Optional[httpx.Response] = None,
+ *,
+ side_effect: Optional[
+ Union[SideEffectTypes, Sequence[SideEffectListTypes]]
+ ] = None,
+ ) -> "Route":
+ self.return_value = return_value
+ self.side_effect = side_effect
+ return self
+
+ def respond(
+ self,
+ status_code: int = 200,
+ *,
+ headers: Optional[HeaderTypes] = None,
+ cookies: Optional[Union[CookieTypes, Sequence[SetCookie]]] = None,
+ content: Optional[Content] = None,
+ text: Optional[str] = None,
+ html: Optional[str] = None,
+ json: Any = None,
+ stream: Optional[Union[httpx.SyncByteStream, httpx.AsyncByteStream]] = None,
+ content_type: Optional[str] = None,
+ http_version: Optional[str] = None,
+ **kwargs: Any,
+ ) -> "Route":
+ response = MockResponse(
+ status_code,
+ headers=headers,
+ cookies=cookies,
+ content=content,
+ text=text,
+ html=html,
+ json=json,
+ stream=stream,
+ content_type=content_type,
+ http_version=http_version,
+ **kwargs,
+ )
+ return self.mock(return_value=response)
+
+ def pass_through(self, value: bool = True) -> "Route":
+ self._pass_through = value
+ return self
+
+ @property
+ def is_pass_through(self) -> bool:
+ return self._pass_through
+
+ @property
+ def called(self) -> bool:
+ return self.calls.called
+
+ @property
+ def call_count(self) -> int:
+ return self.calls.call_count
+
+ def _next_side_effect(
+ self,
+ ) -> Union[CallableSideEffect, Exception, Type[Exception], httpx.Response]:
+ assert self._side_effect is not None
+ effect: Union[CallableSideEffect, Exception, Type[Exception], httpx.Response]
+ if isinstance(self._side_effect, Iterator):
+ effect = next(self._side_effect)
+ else:
+ effect = self._side_effect
+
+ return effect
+
+ def _call_side_effect(
+ self, effect: CallableSideEffect, request: httpx.Request, **kwargs: Any
+ ) -> RouteResultTypes:
+ # Add route kwarg if the side effect wants it
+ argspec = inspect.getfullargspec(effect)
+ if "route" in kwargs:
+ warn(f"Matched context contains reserved word `route`: {self.pattern!r}")
+ if "route" in argspec.args:
+ kwargs["route"] = self
+
+ try:
+ # Call side effect
+ result: RouteResultTypes = effect(request, **kwargs)
+ except Exception as error:
+ raise SideEffectError(self, origin=error) from error
+
+ # Validate result
+ if (
+ result
+ and not inspect.isawaitable(result)
+ and not isinstance(result, (httpx.Response, httpx.Request))
+ ):
+ raise TypeError(
+ f"Side effects must return; either a `httpx.Response`,"
+ f"a `httpx.Request` for pass-through, "
+ f"or `None` for a non-match. Got {result!r}"
+ )
+
+ return result
+
+ def _resolve_side_effect(
+ self, request: httpx.Request, **kwargs: Any
+ ) -> RouteResultTypes:
+ effect = self._next_side_effect()
+
+ # Handle Exception `instance` side effect
+ if isinstance(effect, Exception):
+ raise SideEffectError(self, origin=effect)
+
+ # Handle Exception `type` side effect
+ elif isinstance(effect, type):
+ assert issubclass(effect, Exception)
+ raise SideEffectError(
+ self,
+ origin=(
+ effect("Mock Error", request=request)
+ if issubclass(effect, httpx.RequestError)
+ else effect()
+ ),
+ )
+
+ # Handle `Callable` side effect
+ elif callable(effect):
+ result = self._call_side_effect(effect, request, **kwargs)
+ return result
+
+ # Resolved effect is a mocked response
+ return effect
+
+ def resolve(self, request: httpx.Request, **kwargs: Any) -> RouteResultTypes:
+ result: RouteResultTypes = None
+
+ if self._side_effect:
+ result = self._resolve_side_effect(request, **kwargs)
+ if result is None:
+ return None # Side effect resolved as a non-matching route
+
+ elif self._return_value:
+ result = self._return_value
+
+ else:
+ # Auto mock a new response
+ result = httpx.Response(200, request=request)
+
+ if isinstance(result, httpx.Response) and not result._request:
+ # Clone reused Response for immutability
+ result = clone_response(result, request)
+
+ return result
+
+ def match(self, request: httpx.Request) -> RouteResultTypes:
+ """
+ Matches and resolves request with given patterns and optional side effect.
+
+ Returns None for a non-matching route, mocked response for a match,
+ or input request for pass-through.
+ """
+ context: Dict[str, Any] = {}
+
+ if self._pattern:
+ match = self._pattern.match(request)
+ if not match:
+ return None
+ context = match.context
+
+ if self._pass_through:
+ return request
+
+ result = self.resolve(request, **context)
+ return result
+
+
+class RouteList:
+ _routes: List[Route]
+ _names: Dict[str, Route]
+
+ def __init__(self, routes: Optional["RouteList"] = None) -> None:
+ if routes is None:
+ self._routes = []
+ self._names = {}
+ else:
+ self._routes = list(routes._routes)
+ self._names = dict(routes._names)
+
+ def __repr__(self) -> str:
+ return repr(self._routes) # pragma: nocover
+
+ def __iter__(self) -> Iterator[Route]:
+ return iter(self._routes)
+
+ def __bool__(self) -> bool:
+ return bool(self._routes)
+
+ def __len__(self) -> int:
+ return len(self._routes)
+
+ def __contains__(self, name: str) -> bool:
+ return name in self._names
+
+ def __getitem__(self, key: Union[int, str]) -> Route:
+ if isinstance(key, int):
+ return self._routes[key]
+ else:
+ return self._names[key]
+
+ def __setitem__(self, i: slice, routes: "RouteList") -> None:
+ """
+ Re-set all routes to given routes.
+ """
+ if (i.start, i.stop, i.step) != (None, None, None):
+ raise TypeError("Can't slice assign routes")
+ self._routes = list(routes._routes)
+ self._names = dict(routes._names)
+
+ def clear(self) -> None:
+ self._routes.clear()
+ self._names.clear()
+
+ def add(self, route: Route, name: Optional[str] = None) -> Route:
+ # Find route with same name
+ existing_route = self._names.pop(name or "", None)
+
+ if route in self._routes:
+ if existing_route and existing_route != route:
+ # Re-use existing route with same name, and drop any with same pattern
+ index = self._routes.index(route)
+ same_pattern_route = self._routes.pop(index)
+ if same_pattern_route.name:
+ del self._names[same_pattern_route.name]
+ same_pattern_route._name = None
+ elif not existing_route:
+ # Re-use existing route with same pattern
+ index = self._routes.index(route)
+ existing_route = self._routes[index]
+ if existing_route.name:
+ del self._names[existing_route.name]
+ existing_route._name = None
+
+ if existing_route:
+ # Update existing route's pattern and mock
+ existing_route._pattern = route._pattern
+ existing_route.return_value = route.return_value
+ existing_route.side_effect = route.side_effect
+ existing_route.pass_through(route.is_pass_through)
+ route = existing_route
+ else:
+ # Add new route
+ self._routes.append(route)
+
+ if name:
+ route._name = name
+ self._names[name] = route
+
+ return route
+
+ def pop(self, name, default=...):
+ """
+ Removes a route by name and returns it.
+
+ Raises KeyError when `default` not provided and name is not found.
+ """
+ try:
+ route = self._names.pop(name)
+ self._routes.remove(route)
+ return route
+ except KeyError as ex:
+ if default is ...:
+ raise ex
+ return default
+
+
+class AllMockedAssertionError(AssertionError):
+ pass
+
+
+class SideEffectError(Exception):
+ def __init__(self, route: Route, origin: Exception) -> None:
+ self.route = route
+ self.origin = origin
+
+
+class PassThrough(Exception):
+ def __init__(self, message: str, *, request: httpx.Request, origin: Route) -> None:
+ super().__init__(message)
+ self.request = request
+ self.origin = origin
+
+
+class ResolvedRoute:
+ def __init__(self):
+ self.route: Optional[Route] = None
+ self.response: Optional[ResolvedResponseTypes] = None
diff --git a/tests/respx2/patterns.py b/tests/respx2/patterns.py
new file mode 100644
index 0000000000..7bcb43141a
--- /dev/null
+++ b/tests/respx2/patterns.py
@@ -0,0 +1,782 @@
+import io
+import json as jsonlib
+import operator
+import pathlib
+import re
+from abc import ABC
+from enum import Enum
+from functools import reduce
+from http.cookies import SimpleCookie
+from types import MappingProxyType
+from typing import (
+ Any,
+ Callable,
+ ClassVar,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Pattern as RegexPattern,
+ Sequence,
+ Set,
+ Tuple,
+ Type,
+ Union,
+)
+from unittest.mock import ANY
+
+import httpx2 as httpx
+
+from tests.respx2.utils import MultiItems, decode_data
+
+from .types import (
+ URL as RawURL,
+ CookieTypes,
+ FileTypes,
+ HeaderTypes,
+ QueryParamTypes,
+ RequestFiles,
+ URLPatternTypes,
+)
+
+
+class Lookup(Enum):
+ EQUAL = "eq"
+ REGEX = "regex"
+ STARTS_WITH = "startswith"
+ CONTAINS = "contains"
+ IN = "in"
+
+
+class Match:
+ def __init__(self, matches: bool, **context: Any) -> None:
+ self.matches = matches
+ self.context = context
+
+ def __bool__(self):
+ return bool(self.matches)
+
+ def __invert__(self):
+ self.matches = not self.matches
+ return self
+
+ def __repr__(self): # pragma: nocover
+ return f""
+
+
+class Pattern(ABC):
+ key: ClassVar[str]
+ lookups: ClassVar[Tuple[Lookup, ...]] = (Lookup.EQUAL,)
+
+ lookup: Lookup
+ base: Optional["Pattern"]
+ value: Any
+
+ # Automatically register all the subclasses in this dict
+ __registry: ClassVar[Dict[str, Type["Pattern"]]] = {}
+ registry = MappingProxyType(__registry)
+
+ def __init_subclass__(cls) -> None:
+ if not getattr(cls, "key", None) or ABC in cls.__bases__:
+ return
+
+ if cls.key in cls.__registry:
+ raise TypeError(
+ "Subclasses of Pattern must define a unique key. "
+ f"{cls.key!r} is already defined in {cls.__registry[cls.key]!r}"
+ )
+
+ cls.__registry[cls.key] = cls
+
+ def __init__(self, value: Any, lookup: Optional[Lookup] = None) -> None:
+ if lookup and lookup not in self.lookups:
+ raise NotImplementedError(
+ f"{self.key!r} pattern does not support {lookup.value!r} lookup"
+ )
+ self.lookup = lookup or self.lookups[0]
+ self.base = None
+ self.value = self.clean(value)
+
+ def __iter__(self):
+ yield self
+
+ def __bool__(self):
+ return True
+
+ def __and__(self, other: "Pattern") -> "Pattern":
+ if not bool(other):
+ return self
+ elif not bool(self):
+ return other
+ return _And((self, other))
+
+ def __or__(self, other: "Pattern") -> "Pattern":
+ if not bool(other):
+ return self
+ elif not bool(self):
+ return other
+ return _Or((self, other))
+
+ def __invert__(self):
+ if not bool(self):
+ return self
+ return _Invert(self)
+
+ def __repr__(self): # pragma: nocover
+ return f"<{self.__class__.__name__} {self.lookup.value} {repr(self.value)}>"
+
+ def __hash__(self):
+ return hash((self.__class__, self.lookup, self.value))
+
+ def __eq__(self, other: object) -> bool:
+ return hash(self) == hash(other)
+
+ def clean(self, value: Any) -> Any:
+ """
+ Clean and return pattern value.
+ """
+ return value
+
+ def parse(self, request: httpx.Request) -> Any: # pragma: nocover
+ """
+ Parse and return request value to match with pattern value.
+ """
+ raise NotImplementedError()
+
+ def strip_base(self, value: Any) -> Any: # pragma: nocover
+ return value
+
+ def match(self, request: httpx.Request) -> Match:
+ try:
+ value = self.parse(request)
+ except Exception:
+ return Match(False)
+
+ # Match and strip base
+ if self.base:
+ base_match = self.base._match(value)
+ if not base_match:
+ return base_match
+ value = self.strip_base(value)
+
+ return self._match(value)
+
+ def _match(self, value: Any) -> Match:
+ lookup_method = getattr(self, f"_{self.lookup.value}")
+ return lookup_method(value)
+
+ def _eq(self, value: Any) -> Match:
+ return Match(value == self.value)
+
+ def _regex(self, value: str) -> Match:
+ match = self.value.search(value)
+ if match is None:
+ return Match(False)
+ return Match(True, **match.groupdict())
+
+ def _startswith(self, value: str) -> Match:
+ return Match(value.startswith(self.value))
+
+ def _contains(self, value: Any) -> Match: # pragma: nocover
+ raise NotImplementedError()
+
+ def _in(self, value: Any) -> Match:
+ return Match(value in self.value)
+
+
+class Noop(Pattern):
+ def __init__(self) -> None:
+ super().__init__(None)
+
+ def __repr__(self):
+ return f"<{self.__class__.__name__}>"
+
+ def __bool__(self) -> bool:
+ # Treat this pattern as non-existent, e.g. when filtering or conditioning
+ return False
+
+ def match(self, request: httpx.Request) -> Match:
+ # If this pattern is part of a combined pattern, always be truthy, i.e. noop
+ return Match(True)
+
+
+class PathPattern(Pattern):
+ path: Optional[str]
+
+ def __init__(
+ self, value: Any, lookup: Optional[Lookup] = None, *, path: Optional[str] = None
+ ) -> None:
+ self.path = path
+ super().__init__(value, lookup)
+
+
+class _And(Pattern):
+ value: Tuple[Pattern, Pattern]
+
+ def __repr__(self): # pragma: nocover
+ a, b = self.value
+ return f"{repr(a)} AND {repr(b)}"
+
+ def __iter__(self):
+ a, b = self.value
+ yield from a
+ yield from b
+
+ def match(self, request: httpx.Request) -> Match:
+ a, b = self.value
+ a_match = a.match(request)
+ if not a_match:
+ return a_match
+ b_match = b.match(request)
+ if not b_match:
+ return b_match
+ return Match(True, **{**a_match.context, **b_match.context})
+
+
+class _Or(Pattern):
+ value: Tuple[Pattern, Pattern]
+
+ def __repr__(self): # pragma: nocover
+ a, b = self.value
+ return f"{repr(a)} OR {repr(b)}"
+
+ def __iter__(self):
+ a, b = self.value
+ yield from a
+ yield from b
+
+ def match(self, request: httpx.Request) -> Match:
+ a, b = self.value
+ match = a.match(request)
+ if not match:
+ match = b.match(request)
+ return match
+
+
+class _Invert(Pattern):
+ value: Pattern
+
+ def __repr__(self): # pragma: nocover
+ return f"NOT {repr(self.value)}"
+
+ def __iter__(self):
+ yield from self.value
+
+ def match(self, request: httpx.Request) -> Match:
+ return ~self.value.match(request)
+
+
+class Method(Pattern):
+ key = "method"
+ lookups = (Lookup.EQUAL, Lookup.IN)
+ value: Union[str, Sequence[str]]
+
+ def clean(self, value: Union[str, Sequence[str]]) -> Union[str, Sequence[str]]:
+ if isinstance(value, str):
+ value = value.upper()
+ else:
+ assert isinstance(value, Sequence)
+ value = tuple(v.upper() for v in value)
+ return value
+
+ def parse(self, request: httpx.Request) -> str:
+ return request.method
+
+
+class MultiItemsMixin:
+ lookup: Lookup
+ value: Any
+
+ def _multi_items(
+ self, value: Any, *, parse_any: bool = False, encode_any: bool = False
+ ) -> Tuple[Tuple[str, Tuple[Any, ...]], ...]:
+ return tuple(
+ (
+ key,
+ tuple(
+ self._item_value(v, parse_any=parse_any, encode_any=encode_any)
+ for v in value.get_list(key)
+ ),
+ )
+ for key in sorted(value.keys())
+ )
+
+ def _item_value(
+ self, value: Any, parse_any: bool = False, encode_any: bool = False
+ ) -> Any:
+ return (
+ ANY
+ if parse_any and value == str(ANY)
+ else str(ANY)
+ if encode_any and value is ANY
+ else value
+ )
+
+ def __hash__(self):
+ return hash(
+ (
+ self.__class__,
+ self.lookup,
+ self._multi_items(self.value, encode_any=True),
+ )
+ )
+
+ def _eq(self, value: Any) -> Match:
+ value_items = self._multi_items(self.value, parse_any=True)
+ request_items = self._multi_items(value)
+ return Match(value_items == request_items)
+
+ def _contains(self, value: Any) -> Match:
+ if len(self.value.multi_items()) > len(value.multi_items()):
+ return Match(False)
+
+ value_items = self._multi_items(self.value, parse_any=True)
+ request_items = self._multi_items(value)
+
+ for item in value_items:
+ if item not in request_items:
+ return Match(False)
+
+ return Match(True)
+
+
+class Headers(MultiItemsMixin, Pattern):
+ key = "headers"
+ lookups = (Lookup.CONTAINS, Lookup.EQUAL)
+ value: httpx.Headers
+
+ def clean(self, value: HeaderTypes) -> httpx.Headers:
+ return httpx.Headers(value)
+
+ def parse(self, request: httpx.Request) -> httpx.Headers:
+ return request.headers
+
+
+class Cookies(Pattern):
+ key = "cookies"
+ lookups = (Lookup.CONTAINS, Lookup.EQUAL)
+ value: Set[Tuple[str, str]]
+
+ def __hash__(self):
+ return hash((self.__class__, self.lookup, tuple(sorted(self.value))))
+
+ def clean(self, value: CookieTypes) -> Set[Tuple[str, str]]:
+ if isinstance(value, dict):
+ return set(value.items())
+
+ return set(value)
+
+ def parse(self, request: httpx.Request) -> Set[Tuple[str, str]]:
+ headers = request.headers
+
+ cookie_header = headers.get("cookie")
+ if not cookie_header:
+ return set()
+
+ cookies: SimpleCookie = SimpleCookie()
+ cookies.load(rawdata=cookie_header)
+
+ return {(cookie.key, cookie.value) for cookie in cookies.values()}
+
+ def _contains(self, value: Set[Tuple[str, str]]) -> Match:
+ return Match(bool(self.value & value))
+
+
+class Scheme(Pattern):
+ key = "scheme"
+ lookups = (Lookup.EQUAL, Lookup.IN)
+ value: Union[str, Sequence[str]]
+
+ def clean(self, value: Union[str, Sequence[str]]) -> Union[str, Sequence[str]]:
+ if isinstance(value, str):
+ value = value.lower()
+ else:
+ assert isinstance(value, Sequence)
+ value = tuple(v.lower() for v in value)
+ return value
+
+ def parse(self, request: httpx.Request) -> str:
+ return request.url.scheme
+
+
+class Host(Pattern):
+ key = "host"
+ lookups = (Lookup.EQUAL, Lookup.REGEX, Lookup.IN)
+ value: Union[str, RegexPattern[str], Sequence[str]]
+
+ def clean(
+ self, value: Union[str, RegexPattern[str]]
+ ) -> Union[str, RegexPattern[str]]:
+ if self.lookup is Lookup.REGEX and isinstance(value, str):
+ value = re.compile(value)
+ return value
+
+ def parse(self, request: httpx.Request) -> str:
+ return request.url.host
+
+
+class Port(Pattern):
+ key = "port"
+ lookups = (Lookup.EQUAL, Lookup.IN)
+ value: Optional[int]
+
+ def parse(self, request: httpx.Request) -> Optional[int]:
+ scheme = request.url.scheme
+ port = request.url.port
+ scheme_port = get_scheme_port(scheme)
+ return port or scheme_port
+
+
+class Path(Pattern):
+ key = "path"
+ lookups = (Lookup.EQUAL, Lookup.REGEX, Lookup.STARTS_WITH, Lookup.IN)
+ value: Union[str, Sequence[str], RegexPattern[str]]
+
+ def clean(
+ self, value: Union[str, RegexPattern[str]]
+ ) -> Union[str, RegexPattern[str]]:
+ if self.lookup in (Lookup.EQUAL, Lookup.STARTS_WITH) and isinstance(value, str):
+ # Percent encode path, i.e. revert parsed path by httpx.URL.
+ # Borrowed from HTTPX's "private" quote and percent_encode utilities.
+ path = "".join(
+ char
+ if char
+ in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~/"
+ else "".join(f"%{byte:02x}" for byte in char.encode("utf-8")).upper()
+ for char in value
+ )
+ # Ensure a leading slash. Note we don't use urljoin because its
+ # behaviour with multiple slashes in the path is incorrect - see
+ # https://github.com/lundberg/respx/issues/273
+ if not path.startswith("/"):
+ path = f"/{path}"
+ value = httpx.URL(path).path
+ elif self.lookup is Lookup.REGEX and isinstance(value, str):
+ value = re.compile(value)
+ return value
+
+ def parse(self, request: httpx.Request) -> str:
+ return request.url.path
+
+ def strip_base(self, value: str) -> str:
+ if self.base:
+ value = value[len(self.base.value) :]
+ value = "/" + value if not value.startswith("/") else value
+ return value
+
+
+class Params(MultiItemsMixin, Pattern):
+ key = "params"
+ lookups = (Lookup.CONTAINS, Lookup.EQUAL)
+ value: httpx.QueryParams
+
+ def clean(self, value: QueryParamTypes) -> httpx.QueryParams:
+ return httpx.QueryParams(value)
+
+ def parse(self, request: httpx.Request) -> httpx.QueryParams:
+ query = request.url.query
+ return httpx.QueryParams(query)
+
+
+class URL(Pattern):
+ key = "url"
+ lookups = (
+ Lookup.EQUAL,
+ Lookup.REGEX,
+ Lookup.STARTS_WITH,
+ )
+ value: Union[str, RegexPattern[str]]
+
+ def clean(self, value: URLPatternTypes) -> Union[str, RegexPattern[str]]:
+ url: Union[str, RegexPattern[str]]
+ if self.lookup is Lookup.EQUAL and isinstance(value, (str, tuple, httpx.URL)):
+ _url = parse_url(value)
+ _url = self._ensure_path(_url)
+ url = str(_url)
+ elif self.lookup is Lookup.REGEX and isinstance(value, str):
+ url = re.compile(value)
+ elif isinstance(value, (str, RegexPattern)):
+ url = value
+ else:
+ raise ValueError(f"Invalid url: {value!r}")
+ return url
+
+ def parse(self, request: httpx.Request) -> str:
+ url = request.url
+ url = self._ensure_path(url)
+ return str(url)
+
+ def _ensure_path(self, url: httpx.URL) -> httpx.URL:
+ if not url._uri_reference.path:
+ url = url.copy_with(path="/")
+ return url
+
+
+class ContentMixin:
+ def parse(self, request: httpx.Request) -> Any:
+ content = request.read()
+ return content
+
+
+class Content(ContentMixin, Pattern):
+ lookups = (Lookup.EQUAL, Lookup.CONTAINS)
+ key = "content"
+ value: bytes
+
+ def clean(self, value: Union[bytes, str]) -> bytes:
+ if isinstance(value, str):
+ return value.encode()
+ return value
+
+ def _contains(self, value: Union[bytes, str]) -> Match:
+ return Match(self.value in value)
+
+
+class JSON(ContentMixin, PathPattern):
+ lookups = (Lookup.EQUAL,)
+ key = "json"
+ value: str
+
+ def clean(self, value: Union[str, List, Dict]) -> str:
+ return self.hash(value)
+
+ def parse(self, request: httpx.Request) -> str:
+ content = super().parse(request)
+ json = jsonlib.loads(content.decode("utf-8"))
+
+ if self.path:
+ value = json
+ for bit in self.path.split("__"):
+ key = int(bit) if bit.isdigit() else bit
+ try:
+ value = value[key]
+ except KeyError as e:
+ raise KeyError(f"{self.path!r} not in {json!r}") from e
+ except IndexError as e:
+ raise IndexError(f"{self.path!r} not in {json!r}") from e
+ else:
+ value = json
+
+ return self.hash(value)
+
+ def hash(self, value: Union[str, List, Dict]) -> str:
+ return jsonlib.dumps(value, sort_keys=True)
+
+
+class Data(MultiItemsMixin, Pattern):
+ lookups = (Lookup.EQUAL, Lookup.CONTAINS)
+ key = "data"
+ value: MultiItems
+
+ def _normalize_value(self, value: Any) -> Union[str, List[str]]:
+ if value is None:
+ return ""
+ elif isinstance(value, (tuple, list)):
+ return [str(v) for v in value]
+ else:
+ return str(value)
+
+ def clean(self, value: Dict[str, Any]) -> MultiItems:
+ return MultiItems(
+ (key, self._normalize_value(value)) for key, value in value.items()
+ )
+
+ def parse(self, request: httpx.Request) -> Any:
+ data, _ = decode_data(request)
+ return data
+
+
+class Files(MultiItemsMixin, Pattern):
+ lookups = (Lookup.CONTAINS, Lookup.EQUAL)
+ key = "files"
+ value: MultiItems
+
+ def _normalize_file_value(self, value: FileTypes) -> Tuple[Tuple[Any, Any]]:
+ # Mimic httpx `FileField` to normalize `files` kwarg to shortest tuple style
+ if isinstance(value, tuple):
+ filename, fileobj = value[:2]
+ else:
+ try:
+ filename = pathlib.Path(str(getattr(value, "name"))).name # noqa: B009
+ except AttributeError:
+ filename = ANY
+ fileobj = value
+
+ # Normalize file-like objects and strings to bytes to allow equality check
+ if isinstance(fileobj, io.BytesIO):
+ fileobj = fileobj.read()
+ elif isinstance(fileobj, str):
+ fileobj = fileobj.encode()
+
+ return ((filename, fileobj),)
+
+ def _item_value(
+ self, value: Tuple[Any, Any], parse_any: bool = False, encode_any: bool = False
+ ) -> Tuple[Any, Any]:
+ filename, data = value
+ return (
+ super()._item_value(filename, parse_any=parse_any, encode_any=encode_any),
+ super()._item_value(data, parse_any=parse_any, encode_any=encode_any),
+ )
+
+ def clean(self, value: RequestFiles) -> MultiItems:
+ if isinstance(value, Mapping):
+ value = list(value.items())
+
+ files = MultiItems(
+ (name, self._normalize_file_value(file_value)) for name, file_value in value
+ )
+ return files
+
+ def parse(self, request: httpx.Request) -> Any:
+ _, files = decode_data(request)
+ return files
+
+
+def M(*patterns: Pattern, **lookups: Any) -> Pattern:
+ extras = None
+
+ for pattern__lookup, value in lookups.items():
+ # Handle url pattern
+ if pattern__lookup == "url":
+ extras = parse_url_patterns(value)
+ continue
+
+ # Parse pattern key and lookup
+ pattern_key, __, rest = pattern__lookup.partition("__")
+ path, __, lookup_name = rest.rpartition("__")
+ if pattern_key not in Pattern.registry:
+ raise KeyError(f"{pattern_key!r} is not a valid Pattern")
+
+ # Get pattern class
+ P = Pattern.registry[pattern_key]
+ pattern: Union[Pattern, PathPattern]
+
+ if issubclass(P, PathPattern):
+ # Make path supported pattern, i.e. JSON
+ try:
+ lookup = Lookup(lookup_name) if lookup_name else None
+ except ValueError:
+ lookup = None
+ path = rest
+ pattern = P(value, lookup=lookup, path=path)
+ else:
+ # Make regular pattern
+ lookup = Lookup(lookup_name) if lookup_name else None
+ pattern = P(value, lookup=lookup)
+
+ # Skip patterns with no value, exept when using equal lookup
+ if not pattern.value and pattern.lookup is not Lookup.EQUAL:
+ continue
+
+ patterns += (pattern,)
+
+ # Combine and merge patterns
+ combined_pattern = combine(patterns)
+ if extras:
+ combined_pattern = merge_patterns(combined_pattern, **extras)
+
+ return combined_pattern
+
+
+def get_scheme_port(scheme: Optional[str]) -> Optional[int]:
+ return {"http": 80, "https": 443}.get(scheme or "")
+
+
+def combine(patterns: Sequence[Pattern], op: Callable = operator.and_) -> Pattern:
+ patterns = tuple(filter(None, patterns))
+ if not patterns:
+ return Noop()
+ return reduce(op, patterns)
+
+
+def parse_url(value: Union[httpx.URL, str, RawURL]) -> httpx.URL:
+ url: Union[httpx.URL, str]
+
+ if isinstance(value, tuple):
+ # Handle "raw" httpcore urls. Borrowed from HTTPX prior to #2241
+ raw_scheme, raw_host, port, raw_path = value
+ scheme = raw_scheme.decode("ascii")
+ host = raw_host.decode("ascii")
+ if host and ":" in host and host[0] != "[":
+ # it's an IPv6 address, so it should be enclosed in "[" and "]"
+ # ref: https://tools.ietf.org/html/rfc2732#section-2
+ # ref: https://tools.ietf.org/html/rfc3986#section-3.2.2
+ host = f"[{host}]"
+ port_str = "" if port is None else f":{port}"
+ path = raw_path.decode("ascii")
+ url = f"{scheme}://{host}{port_str}{path}"
+ else:
+ url = value
+
+ return httpx.URL(url)
+
+
+def parse_url_patterns(
+ url: Optional[URLPatternTypes], exact: bool = True
+) -> Dict[str, Pattern]:
+ bases: Dict[str, Pattern] = {}
+ if not url or url == "all":
+ return bases
+
+ if isinstance(url, RegexPattern):
+ return {"url": URL(url, lookup=Lookup.REGEX)}
+
+ url = parse_url(url)
+ scheme_port = get_scheme_port(url.scheme)
+
+ if url.scheme and url.scheme != "all":
+ bases[Scheme.key] = Scheme(url.scheme)
+ if url.host:
+ # NOTE: Host regex patterns borrowed from HTTPX source to support proxy format
+ if url.host.startswith("*."):
+ domain = re.escape(url.host[2:])
+ regex = re.compile(f"^.+\\.{domain}$")
+ bases[Host.key] = Host(regex, lookup=Lookup.REGEX)
+ elif url.host.startswith("*"):
+ domain = re.escape(url.host[1:])
+ regex = re.compile(f"^(.+\\.)?{domain}$")
+ bases[Host.key] = Host(regex, lookup=Lookup.REGEX)
+ else:
+ bases[Host.key] = Host(url.host)
+ if url.port and url.port != scheme_port:
+ bases[Port.key] = Port(url.port)
+ if url._uri_reference.path: # URL.path always returns "/"
+ lookup = Lookup.EQUAL if exact else Lookup.STARTS_WITH
+ bases[Path.key] = Path(url.path, lookup=lookup)
+ if url.query:
+ lookup = Lookup.EQUAL if exact else Lookup.CONTAINS
+ bases[Params.key] = Params(url.query, lookup=lookup)
+
+ return bases
+
+
+def merge_patterns(pattern: Pattern, **bases: Pattern) -> Pattern:
+ if not bases:
+ return pattern
+
+ # Flatten pattern
+ patterns: List[Pattern] = list(filter(None, iter(pattern)))
+
+ if patterns:
+ if "host" in (_pattern.key for _pattern in patterns):
+ # Pattern is "absolute", skip merging
+ bases = {}
+ else:
+ # Traverse pattern and set related base
+ for _pattern in patterns:
+ base = bases.pop(_pattern.key, None)
+ # Skip "exact" base + don't overwrite existing base
+ if _pattern.base or base and base.lookup is Lookup.EQUAL:
+ continue
+ _pattern.base = base
+
+ if bases:
+ # Combine left over base patterns with pattern
+ base_pattern = combine(list(bases.values()))
+ if pattern and base_pattern:
+ pattern = base_pattern & pattern
+ else:
+ pattern = base_pattern
+
+ return pattern
diff --git a/tests/respx2/plugin.py b/tests/respx2/plugin.py
new file mode 100644
index 0000000000..81e2759b32
--- /dev/null
+++ b/tests/respx2/plugin.py
@@ -0,0 +1,30 @@
+from typing import cast
+
+import pytest
+
+from tests import respx2 as respx
+
+from .router import MockRouter
+
+
+def pytest_configure(config):
+ config.addinivalue_line(
+ "markers",
+ "respx2(assert_all_called=False, assert_all_mocked=False, base_url=...): "
+ "configure the respx2_mock fixture. "
+ "See https://lundberg.github.io/respx/api.html#configuration",
+ )
+
+
+@pytest.fixture
+def respx2_mock(request):
+ respx_marker = request.node.get_closest_marker("respx2")
+
+ mock_router: MockRouter = (
+ respx.mock
+ if respx_marker is None
+ else cast(MockRouter, respx.mock(**respx_marker.kwargs))
+ )
+
+ with mock_router:
+ yield mock_router
diff --git a/tests/respx2/py.typed b/tests/respx2/py.typed
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/respx2/router.py b/tests/respx2/router.py
new file mode 100644
index 0000000000..fc1d6e22e0
--- /dev/null
+++ b/tests/respx2/router.py
@@ -0,0 +1,486 @@
+import inspect
+from contextlib import contextmanager
+from functools import partial, update_wrapper, wraps
+from types import TracebackType
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ Generator,
+ List,
+ NewType,
+ Optional,
+ Tuple,
+ Type,
+ Union,
+ cast,
+ overload,
+)
+
+import httpx2 as httpx
+
+from .mocks import Mocker
+from .models import (
+ AllMockedAssertionError,
+ CallList,
+ PassThrough,
+ ResolvedRoute,
+ Route,
+ RouteList,
+ SideEffectError,
+)
+from .patterns import Pattern, merge_patterns, parse_url_patterns
+from .types import DefaultType, ResolvedResponseTypes, RouteResultTypes, URLPatternTypes
+
+Default = NewType("Default", object)
+DEFAULT = Default(...)
+
+
+class Router:
+ def __init__(
+ self,
+ *,
+ assert_all_called: bool = True,
+ assert_all_mocked: bool = True,
+ base_url: Optional[str] = None,
+ ) -> None:
+ self._assert_all_called = assert_all_called
+ self._assert_all_mocked = assert_all_mocked
+ self._bases = parse_url_patterns(base_url, exact=False)
+
+ self.routes = RouteList()
+ self.calls = CallList()
+
+ self._snapshots: List[Tuple] = []
+ self.snapshot()
+
+ def clear(self) -> None:
+ """
+ Clears all routes. May be rolled back to snapshot state.
+ """
+ self.routes.clear()
+
+ def snapshot(self) -> None:
+ """
+ Snapshots current routes and calls state.
+ """
+ # Snapshot current routes and calls
+ routes = RouteList(self.routes)
+ calls = CallList(self.calls)
+ self._snapshots.append((routes, calls))
+
+ # Snapshot each route state
+ for route in routes:
+ route.snapshot()
+
+ def rollback(self) -> None:
+ """
+ Rollbacks routes, and optionally calls, to snapshot state.
+ """
+ if not self._snapshots:
+ return
+
+ # Revert added routes and calls to last snapshot
+ routes, calls = self._snapshots.pop()
+ self.routes[:] = routes
+ self.calls[:] = calls
+
+ # Revert each route state to last snapshot
+ for route in self.routes:
+ route.rollback()
+
+ def reset(self) -> None:
+ """
+ Resets call stats.
+ """
+ self.calls.clear()
+ for route in self.routes:
+ route.reset()
+
+ def assert_all_called(self) -> None:
+ not_called_routes = [route for route in self.routes if not route.called]
+ assert not_called_routes == [], "RESPX: some routes were not called!"
+
+ def __getitem__(self, name: str) -> Route:
+ return self.routes[name]
+
+ @overload
+ def pop(self, name: str) -> Route:
+ ... # pragma: nocover
+
+ @overload
+ def pop(self, name: str, default: DefaultType) -> Union[Route, DefaultType]:
+ ... # pragma: nocover
+
+ def pop(self, name, default=...):
+ """
+ Removes a route by name and returns it.
+
+ Raises KeyError when `default` not provided and name is not found.
+ """
+ try:
+ return self.routes.pop(name)
+ except KeyError as ex:
+ if default is ...:
+ raise ex
+ return default
+
+ def route(
+ self, *patterns: Pattern, name: Optional[str] = None, **lookups: Any
+ ) -> Route:
+ route = Route(*patterns, **lookups)
+ return self.add(route, name=name)
+
+ def add(self, route: Route, *, name: Optional[str] = None) -> Route:
+ """
+ Adds a route with optionally given name,
+ replacing any existing route with same name or pattern.
+ """
+ if not isinstance(route, Route):
+ raise ValueError(
+ f"Invalid route {route!r}, please use respx.route(...).mock(...)"
+ )
+
+ route._pattern = merge_patterns(route.pattern, **self._bases)
+ route = self.routes.add(route, name=name)
+ return route
+
+ def request(
+ self,
+ method: str,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ if lookups:
+ # Validate that lookups doesn't contain method or url
+ pattern_keys = {p.split("__", 1)[0] for p in lookups.keys()}
+ if "method" in pattern_keys:
+ raise TypeError("Got multiple values for pattern 'method'")
+ elif url and "url" in pattern_keys:
+ raise TypeError("Got multiple values for pattern 'url'")
+
+ return self.route(method=method, url=url, name=name, **lookups)
+
+ def get(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="GET", url=url, name=name, **lookups)
+
+ def post(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="POST", url=url, name=name, **lookups)
+
+ def put(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="PUT", url=url, name=name, **lookups)
+
+ def patch(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="PATCH", url=url, name=name, **lookups)
+
+ def delete(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="DELETE", url=url, name=name, **lookups)
+
+ def head(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="HEAD", url=url, name=name, **lookups)
+
+ def options(
+ self,
+ url: Optional[URLPatternTypes] = None,
+ *,
+ name: Optional[str] = None,
+ **lookups: Any,
+ ) -> Route:
+ return self.request(method="OPTIONS", url=url, name=name, **lookups)
+
+ def record(
+ self,
+ request: httpx.Request,
+ *,
+ response: Optional[httpx.Response] = None,
+ route: Optional[Route] = None,
+ ) -> None:
+ call = self.calls.record(request, response)
+ if route:
+ route.calls.append(call)
+
+ @contextmanager
+ def resolver(self, request: httpx.Request) -> Generator[ResolvedRoute, None, None]:
+ resolved = ResolvedRoute()
+
+ try:
+ yield resolved
+
+ if resolved.route is None:
+ # Assert we always get a route match, if check is enabled
+ if self._assert_all_mocked:
+ raise AllMockedAssertionError(f"RESPX: {request!r} not mocked!")
+
+ # Auto mock a successful empty response
+ resolved.response = httpx.Response(200)
+
+ elif resolved.response == request:
+ # Pass-through request
+ raise PassThrough(
+ f"Request marked to pass through: {request!r}",
+ request=request,
+ origin=resolved.route,
+ )
+
+ else:
+ # Mocked response
+ assert isinstance(resolved.response, httpx.Response)
+
+ except SideEffectError as error:
+ self.record(request, response=None, route=error.route)
+ raise error.origin from error
+ except PassThrough:
+ self.record(request, response=None, route=resolved.route)
+ raise
+ else:
+ self.record(request, response=resolved.response, route=resolved.route)
+
+ def resolve(self, request: httpx.Request) -> ResolvedRoute:
+ with self.resolver(request) as resolved:
+ for route in self.routes:
+ prospect = route.match(request)
+ if prospect is not None:
+ resolved.route = route
+ resolved.response = cast(ResolvedResponseTypes, prospect)
+ break
+
+ if resolved.response and isinstance(resolved.response.stream, httpx.ByteStream):
+ resolved.response.read() # Pre-read stream
+
+ return resolved
+
+ async def aresolve(self, request: httpx.Request) -> ResolvedRoute:
+ with self.resolver(request) as resolved:
+ for route in self.routes:
+ prospect: RouteResultTypes = route.match(request)
+
+ # Await async side effect and wrap any exception
+ if inspect.isawaitable(prospect):
+ try:
+ prospect = await prospect
+ except Exception as error:
+ raise SideEffectError(route, origin=error) from error
+
+ if prospect is not None:
+ resolved.route = route
+ resolved.response = cast(ResolvedResponseTypes, prospect)
+ break
+
+ if resolved.response and isinstance(resolved.response.stream, httpx.ByteStream):
+ await resolved.response.aread() # Pre-read stream
+
+ return resolved
+
+ def handler(self, request: httpx.Request) -> httpx.Response:
+ resolved = self.resolve(request)
+ assert isinstance(resolved.response, httpx.Response)
+ return resolved.response
+
+ async def async_handler(self, request: httpx.Request) -> httpx.Response:
+ resolved = await self.aresolve(request)
+ assert isinstance(resolved.response, httpx.Response)
+ return resolved.response
+
+
+class MockRouter(Router):
+ def __init__(
+ self,
+ *,
+ assert_all_called: bool = True,
+ assert_all_mocked: bool = True,
+ base_url: Optional[str] = None,
+ using: Optional[Union[str, Default]] = DEFAULT,
+ ) -> None:
+ super().__init__(
+ assert_all_called=assert_all_called,
+ assert_all_mocked=assert_all_mocked,
+ base_url=base_url,
+ )
+ self.Mocker: Optional[Type[Mocker]] = None
+ self._using = using
+
+ @overload
+ def __call__(
+ self,
+ func: None = None,
+ *,
+ assert_all_called: Optional[bool] = None,
+ assert_all_mocked: Optional[bool] = None,
+ base_url: Optional[str] = None,
+ using: Optional[Union[str, Default]] = DEFAULT,
+ ) -> "MockRouter":
+ ... # pragma: nocover
+
+ @overload
+ def __call__(
+ self,
+ func: Callable = ...,
+ *,
+ assert_all_called: Optional[bool] = None,
+ assert_all_mocked: Optional[bool] = None,
+ base_url: Optional[str] = None,
+ using: Optional[Union[str, Default]] = DEFAULT,
+ ) -> Callable:
+ ... # pragma: nocover
+
+ def __call__(
+ self,
+ func: Optional[Callable] = None,
+ *,
+ assert_all_called: Optional[bool] = None,
+ assert_all_mocked: Optional[bool] = None,
+ base_url: Optional[str] = None,
+ using: Optional[Union[str, Default]] = DEFAULT,
+ ) -> Union["MockRouter", Callable]:
+ """
+ Decorator or Context Manager.
+
+ Use decorator/manager with parentheses for local state, or without parentheses
+ for global state, i.e. shared patterns added outside of scope.
+ """
+ if func is None:
+ # Parentheses used, branch out to new nested instance.
+ # - Only stage when using local ctx `with respx.mock(...) as respx_mock:`
+ # - First stage when using local decorator `@respx.mock(...)`
+ # FYI, global ctx `with respx.mock:` hits __enter__ directly
+ settings: Dict[str, Any] = {
+ "base_url": base_url,
+ "using": using,
+ }
+ if assert_all_called is not None:
+ settings["assert_all_called"] = assert_all_called
+ if assert_all_mocked is not None:
+ settings["assert_all_mocked"] = assert_all_mocked
+ respx_mock = self.__class__(**settings)
+ return respx_mock
+
+ # Determine if decorated function needs a `respx_mock` instance
+ is_async = inspect.iscoroutinefunction(func)
+ argspec = inspect.getfullargspec(func)
+ needs_mock_reference = "respx_mock" in argspec.args
+
+ if needs_mock_reference:
+ func = partial(func, respx_mock=self)
+
+ # Async Decorator
+ async def _async_decorator(*args, **kwargs):
+ assert func is not None
+ async with self:
+ return await func(*args, **kwargs)
+
+ # Sync Decorator
+ def _sync_decorator(*args, **kwargs):
+ assert func is not None
+ with self:
+ return func(*args, **kwargs)
+
+ if needs_mock_reference:
+ async_decorator = wraps(func)(_async_decorator)
+ sync_decorator = wraps(func)(_sync_decorator)
+ else:
+ async_decorator = update_wrapper(_async_decorator, func)
+ sync_decorator = update_wrapper(_sync_decorator, func)
+
+ # Dispatch async/sync decorator, depending on decorated function.
+ # - Only stage when using global decorator `@respx.mock`
+ # - Second stage when using local decorator `@respx.mock(...)`
+ return async_decorator if is_async else sync_decorator
+
+ def __enter__(self) -> "MockRouter":
+ self.start()
+ return self
+
+ def __exit__(
+ self,
+ exc_type: Optional[Type[BaseException]] = None,
+ exc_value: Optional[BaseException] = None,
+ traceback: Optional[TracebackType] = None,
+ ) -> None:
+ self.stop(quiet=bool(exc_type is not None))
+
+ async def __aenter__(self) -> "MockRouter":
+ return self.__enter__()
+
+ async def __aexit__(self, *args: Any) -> None:
+ self.__exit__(*args)
+
+ @property
+ def using(self) -> Optional[str]:
+ from tests.respx2.mocks import DEFAULT_MOCKER
+
+ if self._using is None:
+ using = None
+ elif self._using is DEFAULT:
+ using = DEFAULT_MOCKER
+ elif isinstance(self._using, str):
+ using = self._using
+ else:
+ raise ValueError(f"Invalid Router `using` kwarg: {self._using!r}")
+
+ return using
+
+ def start(self) -> None:
+ """
+ Register transport, snapshot router and start patching.
+ """
+ self.snapshot()
+ self.Mocker = Mocker.registry.get(self.using or "")
+ if self.Mocker:
+ self.Mocker.register(self)
+ self.Mocker.start()
+
+ def stop(self, clear: bool = True, reset: bool = True, quiet: bool = False) -> None:
+ """
+ Unregister transport and rollback router.
+ Stop patching when no registered transports left.
+ """
+ unregistered = self.Mocker.unregister(self) if self.Mocker else True
+
+ try:
+ if unregistered and not quiet and self._assert_all_called:
+ self.assert_all_called()
+ finally:
+ if clear:
+ self.rollback()
+ if reset:
+ self.reset()
+ if self.Mocker:
+ self.Mocker.stop()
diff --git a/tests/respx2/transports.py b/tests/respx2/transports.py
new file mode 100644
index 0000000000..7fb2c5d2db
--- /dev/null
+++ b/tests/respx2/transports.py
@@ -0,0 +1,93 @@
+from types import TracebackType
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ Coroutine,
+ List,
+ Optional,
+ Type,
+ Union,
+ cast,
+)
+from warnings import warn
+
+import httpx2 as httpx
+from httpx2 import AsyncBaseTransport, BaseTransport
+
+from .models import PassThrough
+
+if TYPE_CHECKING:
+ from .router import Router # pragma: nocover
+
+RequestHandler = Callable[[httpx.Request], httpx.Response]
+AsyncRequestHandler = Callable[[httpx.Request], Coroutine[None, None, httpx.Response]]
+
+
+class MockTransport(httpx.MockTransport):
+ _router: Optional["Router"]
+
+ def __init__(
+ self,
+ *,
+ handler: Optional[RequestHandler] = None,
+ async_handler: Optional[AsyncRequestHandler] = None,
+ router: Optional["Router"] = None,
+ ):
+ if router:
+ super().__init__(router.handler)
+ self._router = router
+ elif handler:
+ super().__init__(handler)
+ self._router = None
+ elif async_handler:
+ super().__init__(async_handler)
+ self._router = None
+ else:
+ raise RuntimeError(
+ "Missing a MockTransport required handler or router argument"
+ )
+ warn(
+ "MockTransport is deprecated. "
+ "Please use `httpx.MockTransport(respx_router.handler)`.",
+ category=DeprecationWarning,
+ )
+
+ def __exit__(
+ self,
+ exc_type: Optional[Type[BaseException]] = None,
+ exc_value: Optional[BaseException] = None,
+ traceback: Optional[TracebackType] = None,
+ ) -> None:
+ if not exc_type and self._router and self._router._assert_all_called:
+ self._router.assert_all_called()
+
+ async def __aexit__(self, *args: Any) -> None:
+ self.__exit__(*args)
+
+
+class TryTransport(BaseTransport, AsyncBaseTransport):
+ def __init__(
+ self, transports: List[Union[BaseTransport, AsyncBaseTransport]]
+ ) -> None:
+ self.transports = transports
+
+ def handle_request(self, request: httpx.Request) -> httpx.Response:
+ for transport in self.transports:
+ try:
+ transport = cast(BaseTransport, transport)
+ return transport.handle_request(request)
+ except PassThrough:
+ continue
+
+ raise RuntimeError() # pragma: nocover
+
+ async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
+ for transport in self.transports:
+ try:
+ transport = cast(AsyncBaseTransport, transport)
+ return await transport.handle_async_request(request)
+ except PassThrough:
+ continue
+
+ raise RuntimeError() # pragma: nocover
diff --git a/tests/respx2/types.py b/tests/respx2/types.py
new file mode 100644
index 0000000000..41956308f0
--- /dev/null
+++ b/tests/respx2/types.py
@@ -0,0 +1,71 @@
+from typing import (
+ IO,
+ Any,
+ AsyncIterable,
+ Awaitable,
+ Callable,
+ Dict,
+ Iterable,
+ Iterator,
+ List,
+ Mapping,
+ Optional,
+ Pattern,
+ Sequence,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+)
+
+import httpx2 as httpx
+
+URL = Tuple[
+ bytes, # scheme
+ bytes, # host
+ Optional[int], # port
+ bytes, # path
+]
+Headers = List[Tuple[bytes, bytes]]
+Content = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]]
+
+HeaderTypes = Union[
+ httpx.Headers,
+ Dict[str, str],
+ Dict[bytes, bytes],
+ Sequence[Tuple[str, str]],
+ Sequence[Tuple[bytes, bytes]],
+]
+CookieTypes = Union[Dict[str, str], Sequence[Tuple[str, str]]]
+
+DefaultType = TypeVar("DefaultType", bound=Any)
+
+URLPatternTypes = Union[str, Pattern[str], URL, httpx.URL]
+QueryParamTypes = Union[
+ bytes, str, List[Tuple[str, Any]], Dict[str, Any], Tuple[Tuple[str, Any], ...]
+]
+
+ResolvedResponseTypes = Optional[Union[httpx.Request, httpx.Response]]
+RouteResultTypes = Union[ResolvedResponseTypes, Awaitable[ResolvedResponseTypes]]
+CallableSideEffect = Callable[..., RouteResultTypes]
+SideEffectListTypes = Union[httpx.Response, Exception, Type[Exception]]
+SideEffectTypes = Union[
+ CallableSideEffect,
+ Exception,
+ Type[Exception],
+ Iterator[SideEffectListTypes],
+]
+
+# Borrowed from HTTPX's "private" types.
+FileContent = Union[IO[bytes], bytes, str]
+FileTypes = Union[
+ # file (or bytes)
+ FileContent,
+ # (filename, file (or bytes))
+ Tuple[Optional[str], FileContent],
+ # (filename, file (or bytes), content_type)
+ Tuple[Optional[str], FileContent, Optional[str]],
+ # (filename, file (or bytes), content_type, headers)
+ Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]],
+]
+RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]]
diff --git a/tests/respx2/utils.py b/tests/respx2/utils.py
new file mode 100644
index 0000000000..085d0c3b21
--- /dev/null
+++ b/tests/respx2/utils.py
@@ -0,0 +1,157 @@
+import email
+from collections import defaultdict
+from datetime import datetime
+from email.message import Message
+from typing import (
+ Any,
+ Dict,
+ Iterable,
+ List,
+ Literal,
+ NamedTuple,
+ Optional,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
+from urllib.parse import parse_qsl
+
+import httpx2 as httpx
+
+
+class MultiItems(defaultdict):
+ def __init__(self, values: Optional[Iterable[Tuple[str, Any]]] = None) -> None:
+ super().__init__(tuple)
+ if values is not None:
+ for key, value in values:
+ if isinstance(value, (tuple, list)):
+ self[key] += tuple(value) # Convert list to tuple and extend
+ else:
+ self[key] += (value,) # Extend with value
+
+ def get_list(self, key: str) -> List[Any]:
+ return list(self[key])
+
+ def multi_items(self) -> List[Tuple[str, str]]:
+ return [(key, value) for key, values in self.items() for value in values]
+
+ def append(self, key: str, value: Any) -> None:
+ self[key] += (value,)
+
+
+def _parse_multipart_form_data(
+ content: bytes, *, content_type: str, encoding: str
+) -> Tuple[MultiItems, MultiItems]:
+ form_data = b"\r\n".join(
+ (
+ b"MIME-Version: 1.0",
+ b"Content-Type: " + content_type.encode(encoding),
+ b"\r\n" + content,
+ )
+ )
+ data = MultiItems()
+ files = MultiItems()
+ for payload in email.message_from_bytes(form_data).get_payload():
+ payload = cast(Message, payload)
+ name = payload.get_param("name", header="Content-Disposition")
+ assert isinstance(name, str)
+ filename = payload.get_filename()
+ content_type = payload.get_content_type()
+ value = payload.get_payload(decode=True)
+ assert isinstance(value, bytes)
+ if content_type.startswith("text/") and filename is None:
+ # Text field
+ data.append(name, value.decode(payload.get_content_charset() or "utf-8"))
+ else:
+ # File field
+ files.append(name, (filename, value))
+
+ return data, files
+
+
+def _parse_urlencoded_data(content: bytes, *, encoding: str) -> MultiItems:
+ return MultiItems(
+ (key, value)
+ for key, value in parse_qsl(content.decode(encoding), keep_blank_values=True)
+ )
+
+
+def decode_data(request: httpx.Request) -> Tuple[MultiItems, MultiItems]:
+ content = request.read()
+ content_type = request.headers.get("Content-Type", "")
+
+ if content_type.startswith("multipart/form-data"):
+ data, files = _parse_multipart_form_data(
+ content,
+ content_type=content_type,
+ encoding=request.headers.encoding,
+ )
+ else:
+ data = _parse_urlencoded_data(
+ content,
+ encoding=request.headers.encoding,
+ )
+ files = MultiItems()
+
+ return data, files
+
+
+Self = TypeVar("Self", bound="SetCookie")
+
+
+class SetCookie(
+ NamedTuple(
+ "SetCookie",
+ [
+ ("header_name", Literal["Set-Cookie"]),
+ ("header_value", str),
+ ],
+ )
+):
+ def __new__(
+ cls: Type[Self],
+ name: str,
+ value: str,
+ *,
+ path: Optional[str] = None,
+ domain: Optional[str] = None,
+ expires: Optional[Union[str, datetime]] = None,
+ max_age: Optional[int] = None,
+ http_only: bool = False,
+ same_site: Optional[Literal["Strict", "Lax", "None"]] = None,
+ secure: bool = False,
+ partitioned: bool = False,
+ ) -> Self:
+ """
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#syntax
+ """
+ attrs: Dict[str, Union[str, bool]] = {name: value}
+ if path is not None:
+ attrs["Path"] = path
+ if domain is not None:
+ attrs["Domain"] = domain
+ if expires is not None:
+ if isinstance(expires, datetime): # pragma: no branch
+ expires = expires.strftime("%a, %d %b %Y %H:%M:%S GMT")
+ attrs["Expires"] = expires
+ if max_age is not None:
+ attrs["Max-Age"] = str(max_age)
+ if http_only:
+ attrs["HttpOnly"] = True
+ if same_site is not None:
+ attrs["SameSite"] = same_site
+ if same_site == "None": # pragma: no branch
+ secure = True
+ if secure:
+ attrs["Secure"] = True
+ if partitioned:
+ attrs["Partitioned"] = True
+
+ string = "; ".join(
+ _name if _value is True else f"{_name}={_value}"
+ for _name, _value in attrs.items()
+ )
+ self = super().__new__(cls, "Set-Cookie", string)
+ return self
diff --git a/tests/test_auth.py b/tests/test_auth.py
index 17e9cd814c..f9b1719cb5 100644
--- a/tests/test_auth.py
+++ b/tests/test_auth.py
@@ -2,13 +2,13 @@
from typing import cast
from pathlib import Path
-import httpx
-import respx
+import httpx2
import pytest
-from respx.models import Call
from inline_snapshot import snapshot
+from tests import respx2
from openai import OpenAI, OAuthError
+from tests.respx2.models import Call
from openai.auth._workload import (
gcp_id_token_provider,
k8s_service_account_token_provider,
@@ -16,10 +16,10 @@
)
-@respx.mock
+@respx2.mock
def test_basic_auth():
- respx.post("https://auth.openai.com/oauth/token").mock(
- return_value=httpx.Response(
+ respx2.post("https://auth.openai.com/oauth/token").mock(
+ return_value=httpx2.Response(
200,
json={
"access_token": "fake_access_token",
@@ -30,8 +30,8 @@ def test_basic_auth():
)
)
- respx.get("https://api.openai.com/v1/models").mock(
- return_value=httpx.Response(200, json={"data": [], "object": "list"})
+ respx2.get("https://api.openai.com/v1/models").mock(
+ return_value=httpx2.Response(200, json={"data": [], "object": "list"})
)
client = OpenAI(
@@ -47,15 +47,15 @@ def test_basic_auth():
client.models.list()
- assert len(respx.calls) == 2
- token_call = cast(Call, respx.calls[0])
- api_call = cast(Call, respx.calls[1])
+ assert len(respx2.calls) == 2
+ token_call = cast(Call, respx2.calls[0])
+ api_call = cast(Call, respx2.calls[1])
assert token_call.request.url == "https://auth.openai.com/oauth/token"
assert api_call.request.headers.get("Authorization") == "Bearer fake_access_token"
-@respx.mock
+@respx2.mock
def test_workload_identity_exchange_payload_and_cache() -> None:
provider_call_count = 0
@@ -64,8 +64,8 @@ def provider() -> str:
provider_call_count += 1
return "fake_subject_token"
- exchange_route = respx.post("https://auth.openai.com/oauth/token").mock(
- return_value=httpx.Response(
+ exchange_route = respx2.post("https://auth.openai.com/oauth/token").mock(
+ return_value=httpx2.Response(
200,
json={
"access_token": "fake_access_token",
@@ -75,8 +75,8 @@ def provider() -> str:
},
)
)
- api_route = respx.get("https://api.openai.com/v1/models").mock(
- return_value=httpx.Response(200, json={"data": [], "object": "list"})
+ api_route = respx2.get("https://api.openai.com/v1/models").mock(
+ return_value=httpx2.Response(200, json={"data": [], "object": "list"})
)
client = OpenAI(
@@ -97,7 +97,7 @@ def provider() -> str:
assert exchange_route.call_count == 1
assert api_route.call_count == 2
- exchange_request = cast(respx.models.Call, exchange_route.calls[0]).request
+ exchange_request = cast(respx2.models.Call, exchange_route.calls[0]).request
assert json.loads(exchange_request.content) == snapshot(
{
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
@@ -109,17 +109,17 @@ def provider() -> str:
)
assert (
- cast(respx.models.Call, api_route.calls[0]).request.headers.get("Authorization") == "Bearer fake_access_token"
+ cast(respx2.models.Call, api_route.calls[0]).request.headers.get("Authorization") == "Bearer fake_access_token"
)
assert (
- cast(respx.models.Call, api_route.calls[1]).request.headers.get("Authorization") == "Bearer fake_access_token"
+ cast(respx2.models.Call, api_route.calls[1]).request.headers.get("Authorization") == "Bearer fake_access_token"
)
-@respx.mock
+@respx2.mock
def test_workload_identity_exchange_error() -> None:
- exchange_route = respx.post("https://auth.openai.com/oauth/token").mock(
- return_value=httpx.Response(
+ exchange_route = respx2.post("https://auth.openai.com/oauth/token").mock(
+ return_value=httpx2.Response(
401,
json={
"error": "invalid_grant",
@@ -127,8 +127,8 @@ def test_workload_identity_exchange_error() -> None:
},
)
)
- api_route = respx.get("https://api.openai.com/v1/models").mock(
- return_value=httpx.Response(200, json={"data": [], "object": "list"})
+ api_route = respx2.get("https://api.openai.com/v1/models").mock(
+ return_value=httpx2.Response(200, json={"data": [], "object": "list"})
)
client = OpenAI(
@@ -162,10 +162,10 @@ def test_k8s_service_account_token_provider(tmp_path: Path) -> None:
assert provider["get_token"]() == "my-k8s-token"
-@respx.mock
+@respx2.mock
def test_azure_managed_identity_token_provider() -> None:
- respx.get("http://169.254.169.254/metadata/identity/oauth2/token").mock(
- return_value=httpx.Response(200, json={"access_token": "azure-token"})
+ respx2.get("http://169.254.169.254/metadata/identity/oauth2/token").mock(
+ return_value=httpx2.Response(200, json={"access_token": "azure-token"})
)
provider = azure_managed_identity_token_provider()
@@ -174,10 +174,10 @@ def test_azure_managed_identity_token_provider() -> None:
assert provider["get_token"]() == "azure-token"
-@respx.mock
+@respx2.mock
def test_gcp_id_token_provider() -> None:
- respx.get("http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity").mock(
- return_value=httpx.Response(200, text="gcp-token")
+ respx2.get("http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity").mock(
+ return_value=httpx2.Response(200, text="gcp-token")
)
provider = gcp_id_token_provider()
diff --git a/tests/test_client.py b/tests/test_client.py
index 33a5b1c224..092050987d 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -14,14 +14,13 @@
from unittest import mock
from typing_extensions import Literal, AsyncIterator, override
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
from pydantic import ValidationError
-from respx.models import Call as MockRequestCall
from openai import OpenAI, AsyncOpenAI, OpenAIError, APIResponseValidationError
from openai.auth import WorkloadIdentity
+from tests.respx2 import MockRouter
from openai._types import Omit
from openai._utils import asyncify
from openai._models import BaseModel, FinalRequestOptions
@@ -37,6 +36,7 @@
get_platform,
make_request_options,
)
+from tests.respx2.models import Call as MockRequestCall
from .utils import update_env
@@ -56,7 +56,7 @@
def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]:
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- url = httpx.URL(request.url)
+ url = httpx2.URL(request.url)
return dict(url.params)
@@ -64,25 +64,25 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float:
return 0.1
-def mirror_request_content(request: httpx.Request) -> httpx.Response:
- return httpx.Response(200, content=request.content)
+def mirror_request_content(request: httpx2.Request) -> httpx2.Response:
+ return httpx2.Response(200, content=request.content)
# note: we can't use the httpx.MockTransport class as it consumes the request
# body itself, which means we can't test that the body is read lazily
-class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport):
+class MockTransport(httpx2.BaseTransport, httpx2.AsyncBaseTransport):
def __init__(
self,
- handler: Callable[[httpx.Request], httpx.Response]
- | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]],
+ handler: Callable[[httpx2.Request], httpx2.Response]
+ | Callable[[httpx2.Request], Coroutine[Any, Any, httpx2.Response]],
) -> None:
self.handler = handler
@override
def handle_request(
self,
- request: httpx.Request,
- ) -> httpx.Response:
+ request: httpx2.Request,
+ ) -> httpx2.Response:
assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function"
assert inspect.isfunction(self.handler), "handler must be a function"
return self.handler(request)
@@ -90,8 +90,8 @@ def handle_request(
@override
async def handle_async_request(
self,
- request: httpx.Request,
- ) -> httpx.Response:
+ request: httpx2.Request,
+ ) -> httpx2.Response:
assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function"
return await self.handler(request)
@@ -117,7 +117,7 @@ async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter]
def _get_open_connections(client: OpenAI | AsyncOpenAI) -> int:
transport = client._client._transport
- if isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport):
+ if isinstance(transport, httpx2.HTTPTransport) or isinstance(transport, httpx2.AsyncHTTPTransport):
return len(transport._pool._requests)
assert type(transport).__module__ == "httpx2"
@@ -125,24 +125,24 @@ def _get_open_connections(client: OpenAI | AsyncOpenAI) -> int:
class TestOpenAI:
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response(self, respx_mock: MockRouter, client: OpenAI) -> None:
- respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ respx2_mock.post("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
- response = client.post("/foo", cast_to=httpx.Response)
+ response = client.post("/foo", cast_to=httpx2.Response)
assert response.status_code == 200
- assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx")
+ assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx2")
assert response.json() == {"foo": "bar"}
- @pytest.mark.respx(base_url=base_url)
- def test_raw_response_for_binary(self, respx_mock: MockRouter, client: OpenAI) -> None:
- respx_mock.post("/foo").mock(
- return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}')
+ @pytest.mark.respx2(base_url=base_url)
+ def test_raw_response_for_binary(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ respx2_mock.post("/foo").mock(
+ return_value=httpx2.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}')
)
- response = client.post("/foo", cast_to=httpx.Response)
+ response = client.post("/foo", cast_to=httpx2.Response)
assert response.status_code == 200
- assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx")
+ assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx2")
assert response.json() == {"foo": "bar"}
def test_copy(self, client: OpenAI) -> None:
@@ -168,10 +168,10 @@ def test_copy_default_options(self, client: OpenAI) -> None:
assert copied.max_retries == 7
# timeout
- assert isinstance(client.timeout, httpx.Timeout)
+ assert isinstance(client.timeout, httpx2.Timeout)
copied = client.copy(timeout=None)
assert copied.timeout is None
- assert isinstance(client.timeout, httpx.Timeout)
+ assert isinstance(client.timeout, httpx2.Timeout)
def test_copy_default_headers(self) -> None:
client = OpenAI(
@@ -335,12 +335,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic
def test_request_timeout(self, client: OpenAI) -> None:
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
assert timeout == DEFAULT_TIMEOUT
- request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
- assert timeout == httpx.Timeout(100.0)
+ request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx2.Timeout(100.0)))
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
+ assert timeout == httpx2.Timeout(100.0)
def test_client_timeout_option(self) -> None:
client = OpenAI(
@@ -348,18 +348,18 @@ def test_client_timeout_option(self) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- timeout=httpx.Timeout(0),
+ timeout=httpx2.Timeout(0),
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
- assert timeout == httpx.Timeout(0)
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
+ assert timeout == httpx2.Timeout(0)
client.close()
def test_http_client_timeout_option(self) -> None:
# custom timeout given to the httpx client should be used
- with httpx.Client(timeout=None) as http_client:
+ with httpx2.Client(timeout=None) as http_client:
client = OpenAI(
base_url=base_url,
api_key=api_key,
@@ -369,13 +369,13 @@ def test_http_client_timeout_option(self) -> None:
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
- assert timeout == httpx.Timeout(None)
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
+ assert timeout == httpx2.Timeout(None)
client.close()
# no timeout given to the httpx client should not use the httpx default
- with httpx.Client() as http_client:
+ with httpx2.Client() as http_client:
client = OpenAI(
base_url=base_url,
api_key=api_key,
@@ -385,13 +385,13 @@ def test_http_client_timeout_option(self) -> None:
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
assert timeout == DEFAULT_TIMEOUT
client.close()
# explicitly passing the default timeout currently results in it being ignored
- with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client:
+ with httpx2.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client:
client = OpenAI(
base_url=base_url,
api_key=api_key,
@@ -401,14 +401,14 @@ def test_http_client_timeout_option(self) -> None:
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
assert timeout == DEFAULT_TIMEOUT # our default
client.close()
async def test_invalid_http_client(self) -> None:
with pytest.raises(TypeError, match="Invalid `http_client` arg"):
- async with httpx.AsyncClient() as http_client:
+ async with httpx2.AsyncClient() as http_client:
OpenAI(
base_url=base_url,
api_key=api_key,
@@ -524,9 +524,9 @@ def test_validate_headers(self) -> None:
with pytest.raises(OpenAIError, match="Missing credentials"):
OpenAI(base_url=base_url, api_key=None, admin_api_key=None, _strict_response_validation=True)
- @pytest.mark.respx(base_url=base_url)
- def test_api_key_provider_preserves_admin_auth(self, respx_mock: MockRouter) -> None:
- respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_api_key_provider_preserves_admin_auth(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/organization/projects").mock(return_value=httpx2.Response(200, json={"ok": True}))
provider_called = False
@@ -538,7 +538,7 @@ def api_key_provider() -> str:
client = OpenAI(base_url=base_url, api_key=api_key_provider, admin_api_key=admin_api_key)
response = client.get(
"/organization/projects",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"security": {"admin_api_key_auth": True}},
)
@@ -558,20 +558,20 @@ def api_key_provider() -> str:
with pytest.raises(TypeError, match="Could not resolve authentication method"):
client.get(
"/organization/projects",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"security": {"admin_api_key_auth": True}},
)
assert provider_called is False
- @pytest.mark.respx(base_url=base_url)
- def test_workload_identity_preserves_admin_auth(self, respx_mock: MockRouter) -> None:
- respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True}))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_workload_identity_preserves_admin_auth(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/organization/projects").mock(return_value=httpx2.Response(200, json={"ok": True}))
client = OpenAI(base_url=base_url, workload_identity=workload_identity, admin_api_key=admin_api_key)
response = client.get(
"/organization/projects",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"security": {"admin_api_key_auth": True}},
)
@@ -599,7 +599,7 @@ def test_default_query_option(self) -> None:
default_query={"query_param": "bar"},
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- url = httpx.URL(request.url)
+ url = httpx2.URL(request.url)
assert dict(url.params) == {"query_param": "bar"}
request = client._build_request(
@@ -609,14 +609,14 @@ def test_default_query_option(self) -> None:
params={"foo": "baz", "query_param": "overridden"},
)
)
- url = httpx.URL(request.url)
+ url = httpx2.URL(request.url)
assert dict(url.params) == {"foo": "baz", "query_param": "overridden"}
client.close()
def test_hardcoded_query_params_in_url(self, client: OpenAI) -> None:
request = client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true"))
- url = httpx.URL(str(request.url))
+ url = httpx2.URL(str(request.url))
assert dict(url.params) == {"beta": "true"}
request = client._build_request(
@@ -626,7 +626,7 @@ def test_hardcoded_query_params_in_url(self, client: OpenAI) -> None:
params={"limit": "10", "page": "abc"},
)
)
- url = httpx.URL(str(request.url))
+ url = httpx2.URL(str(request.url))
assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"}
request = client._build_request(
@@ -764,16 +764,16 @@ def test_multipart_repeating_array(self, client: OpenAI) -> None:
b"",
]
- @pytest.mark.respx(base_url=base_url)
- def test_binary_content_upload(self, respx_mock: MockRouter, client: OpenAI) -> None:
- respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+ @pytest.mark.respx2(base_url=base_url)
+ def test_binary_content_upload(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ respx2_mock.post("/upload").mock(side_effect=mirror_request_content)
file_content = b"Hello, this is a test file."
response = client.post(
"/upload",
content=file_content,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/octet-stream"}},
)
@@ -786,21 +786,21 @@ def test_binary_content_upload_with_iterator(self) -> None:
counter = Counter()
iterator = _make_sync_iterator([file_content], counter=counter)
- def mock_handler(request: httpx.Request) -> httpx.Response:
+ def mock_handler(request: httpx2.Request) -> httpx2.Response:
assert counter.value == 0, "the request body should not have been read"
- return httpx.Response(200, content=request.read())
+ return httpx2.Response(200, content=request.read())
with OpenAI(
base_url=base_url,
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.Client(transport=MockTransport(handler=mock_handler)),
+ http_client=httpx2.Client(transport=MockTransport(handler=mock_handler)),
) as client:
response = client.post(
"/upload",
content=iterator,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/octet-stream"}},
)
@@ -809,9 +809,9 @@ def mock_handler(request: httpx.Request) -> httpx.Response:
assert response.content == file_content
assert counter.value == 1
- @pytest.mark.respx(base_url=base_url)
- def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: OpenAI) -> None:
- respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+ @pytest.mark.respx2(base_url=base_url)
+ def test_binary_content_upload_with_body_is_deprecated(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ respx2_mock.post("/upload").mock(side_effect=mirror_request_content)
file_content = b"Hello, this is a test file."
@@ -821,7 +821,7 @@ def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRou
response = client.post(
"/upload",
body=file_content,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/octet-stream"}},
)
@@ -829,22 +829,22 @@ def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRou
assert response.request.headers["Content-Type"] == "application/octet-stream"
assert response.content == file_content
- @pytest.mark.respx(base_url=base_url)
- def test_basic_union_response(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_basic_union_response(self, respx2_mock: MockRouter, client: OpenAI) -> None:
class Model1(BaseModel):
name: str
class Model2(BaseModel):
foo: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2]))
assert isinstance(response, Model2)
assert response.foo == "bar"
- @pytest.mark.respx(base_url=base_url)
- def test_union_response_different_types(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_union_response_different_types(self, respx2_mock: MockRouter, client: OpenAI) -> None:
"""Union of objects with the same field name using a different type"""
class Model1(BaseModel):
@@ -853,20 +853,20 @@ class Model1(BaseModel):
class Model2(BaseModel):
foo: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2]))
assert isinstance(response, Model2)
assert response.foo == "bar"
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": 1}))
response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2]))
assert isinstance(response, Model1)
assert response.foo == 1
- @pytest.mark.respx(base_url=base_url)
- def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_non_application_json_content_type_for_json_data(self, respx2_mock: MockRouter, client: OpenAI) -> None:
"""
Response that sets Content-Type to something other than application/json but returns json data
"""
@@ -874,8 +874,8 @@ def test_non_application_json_content_type_for_json_data(self, respx_mock: MockR
class Model(BaseModel):
foo: int
- respx_mock.get("/foo").mock(
- return_value=httpx.Response(
+ respx2_mock.get("/foo").mock(
+ return_value=httpx2.Response(
200,
content=json.dumps({"foo": 2}),
headers={"Content-Type": "application/text"},
@@ -920,7 +920,7 @@ def test_base_url_env(self) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.Client(),
+ http_client=httpx2.Client(),
),
],
ids=["standard", "custom http client"],
@@ -950,7 +950,7 @@ def test_base_url_trailing_slash(self, client: OpenAI) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.Client(),
+ http_client=httpx2.Client(),
),
],
ids=["standard", "custom http client"],
@@ -980,7 +980,7 @@ def test_base_url_no_trailing_slash(self, client: OpenAI) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.Client(),
+ http_client=httpx2.Client(),
),
],
ids=["standard", "custom http client"],
@@ -1019,12 +1019,12 @@ def test_client_context_manager(self) -> None:
assert not test_client.is_closed()
assert test_client.is_closed()
- @pytest.mark.respx(base_url=base_url)
- def test_client_response_validation_error(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_client_response_validation_error(self, respx2_mock: MockRouter, client: OpenAI) -> None:
class Model(BaseModel):
foo: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": {"invalid": True}}))
with pytest.raises(APIResponseValidationError) as exc:
client.get("/foo", cast_to=Model)
@@ -1041,23 +1041,23 @@ def test_client_max_retries_validation(self) -> None:
max_retries=cast(Any, None),
)
- @pytest.mark.respx(base_url=base_url)
- def test_default_stream_cls(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_default_stream_cls(self, respx2_mock: MockRouter, client: OpenAI) -> None:
class Model(BaseModel):
name: str
- respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.post("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
stream = client.post("/foo", cast_to=Model, stream=True, stream_cls=Stream[Model])
assert isinstance(stream, Stream)
stream.response.close()
- @pytest.mark.respx(base_url=base_url)
- def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_received_text_for_expected_json(self, respx2_mock: MockRouter) -> None:
class Model(BaseModel):
name: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format"))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, text="my-custom-format"))
strict_client = OpenAI(
base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True
@@ -1108,7 +1108,7 @@ class Model(BaseModel):
def test_parse_retry_after_header(
self, remaining_retries: int, retry_after: str, timeout: float, client: OpenAI
) -> None:
- headers = httpx.Headers({"retry-after": retry_after})
+ headers = httpx2.Headers({"retry-after": retry_after})
options = FinalRequestOptions(method="get", url="/foo", max_retries=3)
calculated = client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
@@ -1126,24 +1126,24 @@ def test_parse_retry_after_header(
)
@mock.patch("time.time", mock.MagicMock(return_value=1696004797))
def test_retry_after_max_delay(self, headers: dict[str, str], should_retry: bool, client: OpenAI) -> None:
- response = httpx.Response(429, headers=headers)
+ response = httpx2.Response(429, headers=headers)
assert client._should_retry(response) is should_retry
- @pytest.mark.respx(base_url=base_url)
- def test_does_not_retry_retry_after_above_max(self, respx_mock: MockRouter, client: OpenAI) -> None:
- route = respx_mock.get("/foo").mock(
- return_value=httpx.Response(429, headers={"retry-after": "121"}, json={"error": {}})
+ @pytest.mark.respx2(base_url=base_url)
+ def test_does_not_retry_retry_after_above_max(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ route = respx2_mock.get("/foo").mock(
+ return_value=httpx2.Response(429, headers={"retry-after": "121"}, json={"error": {}})
)
with pytest.raises(APIStatusError):
- client.get("/foo", cast_to=httpx.Response)
+ client.get("/foo", cast_to=httpx2.Response)
assert route.call_count == 1
- @pytest.mark.respx(base_url=base_url)
- def test_invalid_retry_after_date_does_not_mask_status_error(self, respx_mock: MockRouter, client: OpenAI) -> None:
- route = respx_mock.get("/foo").mock(
- return_value=httpx.Response(
+ @pytest.mark.respx2(base_url=base_url)
+ def test_invalid_retry_after_date_does_not_mask_status_error(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ route = respx2_mock.get("/foo").mock(
+ return_value=httpx2.Response(
400,
headers={"retry-after": "Fri, 29 Sep 100000 16:26:57 GMT"},
json={"error": {}},
@@ -1151,14 +1151,14 @@ def test_invalid_retry_after_date_does_not_mask_status_error(self, respx_mock: M
)
with pytest.raises(APIStatusError):
- client.get("/foo", cast_to=httpx.Response)
+ client.get("/foo", cast_to=httpx2.Response)
assert route.call_count == 1
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
- def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: OpenAI) -> None:
- respx_mock.post("/chat/completions").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_retrying_timeout_errors_doesnt_leak(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ respx2_mock.post("/chat/completions").mock(side_effect=httpx2.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
client.chat.completions.with_streaming_response.create(
@@ -1174,9 +1174,9 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien
assert _get_open_connections(client) == 0
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
- def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: OpenAI) -> None:
- respx_mock.post("/chat/completions").mock(return_value=httpx.Response(500))
+ @pytest.mark.respx2(base_url=base_url)
+ def test_retrying_status_errors_doesnt_leak(self, respx2_mock: MockRouter, client: OpenAI) -> None:
+ respx2_mock.post("/chat/completions").mock(return_value=httpx2.Response(500))
with pytest.raises(APIStatusError):
client.chat.completions.with_streaming_response.create(
@@ -1192,29 +1192,29 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
@pytest.mark.parametrize("failure_mode", ["status", "exception"])
def test_retries_taken(
self,
client: OpenAI,
failures_before_success: int,
failure_mode: Literal["status", "exception"],
- respx_mock: MockRouter,
+ respx2_mock: MockRouter,
) -> None:
client = client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
if failure_mode == "exception":
raise RuntimeError("oops")
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
response = client.chat.completions.with_raw_response.create(
messages=[
@@ -1231,22 +1231,22 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_omit_retry_count_header(
- self, client: OpenAI, failures_before_success: int, respx_mock: MockRouter
+ self, client: OpenAI, failures_before_success: int, respx2_mock: MockRouter
) -> None:
client = client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
response = client.chat.completions.with_raw_response.create(
messages=[
@@ -1263,22 +1263,22 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_overwrite_retry_count_header(
- self, client: OpenAI, failures_before_success: int, respx_mock: MockRouter
+ self, client: OpenAI, failures_before_success: int, respx2_mock: MockRouter
) -> None:
client = client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
response = client.chat.completions.with_raw_response.create(
messages=[
@@ -1295,22 +1295,22 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
def test_retries_taken_new_response_class(
- self, client: OpenAI, failures_before_success: int, respx_mock: MockRouter
+ self, client: OpenAI, failures_before_success: int, respx2_mock: MockRouter
) -> None:
client = client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
with client.chat.completions.with_streaming_response.create(
messages=[
@@ -1351,30 +1351,32 @@ def test_default_client_creation(self) -> None:
trust_env=True,
http1=True,
http2=False,
- limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
+ limits=httpx2.Limits(max_connections=100, max_keepalive_connections=20),
)
- @pytest.mark.respx(base_url=base_url)
- def test_follow_redirects(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_follow_redirects(self, respx2_mock: MockRouter, client: OpenAI) -> None:
# Test that the default follow_redirects=True allows following redirects
- respx_mock.post("/redirect").mock(
- return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
+ respx2_mock.post("/redirect").mock(
+ return_value=httpx2.Response(302, headers={"Location": f"{base_url}/redirected"})
)
- respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"}))
+ respx2_mock.get("/redirected").mock(return_value=httpx2.Response(200, json={"status": "ok"}))
- response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response)
+ response = client.post("/redirect", body={"key": "value"}, cast_to=httpx2.Response)
assert response.status_code == 200
assert response.json() == {"status": "ok"}
- @pytest.mark.respx(base_url=base_url)
- def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: OpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ def test_follow_redirects_disabled(self, respx2_mock: MockRouter, client: OpenAI) -> None:
# Test that follow_redirects=False prevents following redirects
- respx_mock.post("/redirect").mock(
- return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
+ respx2_mock.post("/redirect").mock(
+ return_value=httpx2.Response(302, headers={"Location": f"{base_url}/redirected"})
)
with pytest.raises(APIStatusError) as exc_info:
- client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response)
+ client.post(
+ "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx2.Response
+ )
assert exc_info.value.response.status_code == 302
assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected"
@@ -1398,12 +1400,12 @@ def test_api_key_before_after_refresh_str(self) -> None:
assert client.auth_headers.get("Authorization") == "Bearer test_api_key"
- @pytest.mark.respx()
- def test_api_key_refresh_on_retry(self, respx_mock: MockRouter) -> None:
- respx_mock.post(base_url + "/chat/completions").mock(
+ @pytest.mark.respx2()
+ def test_api_key_refresh_on_retry(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.post(base_url + "/chat/completions").mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json={"foo": "bar"}),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json={"foo": "bar"}),
]
)
@@ -1422,7 +1424,7 @@ def token_provider() -> str:
client = OpenAI(base_url=base_url, api_key=token_provider)
client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 2
assert calls[0].request.headers.get("Authorization") == "Bearer first"
@@ -1437,24 +1439,24 @@ def test_copy_auth(self) -> None:
class TestAsyncOpenAI:
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
- respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ respx2_mock.post("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
- response = await async_client.post("/foo", cast_to=httpx.Response)
+ response = await async_client.post("/foo", cast_to=httpx2.Response)
assert response.status_code == 200
- assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx")
+ assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx2")
assert response.json() == {"foo": "bar"}
- @pytest.mark.respx(base_url=base_url)
- async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
- respx_mock.post("/foo").mock(
- return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}')
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_raw_response_for_binary(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ respx2_mock.post("/foo").mock(
+ return_value=httpx2.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}')
)
- response = await async_client.post("/foo", cast_to=httpx.Response)
+ response = await async_client.post("/foo", cast_to=httpx2.Response)
assert response.status_code == 200
- assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx")
+ assert type(response).__module__ == os.environ.get("OPENAI_TEST_HTTP_CLIENT", "httpx2")
assert response.json() == {"foo": "bar"}
def test_copy(self, async_client: AsyncOpenAI) -> None:
@@ -1480,10 +1482,10 @@ def test_copy_default_options(self, async_client: AsyncOpenAI) -> None:
assert copied.max_retries == 7
# timeout
- assert isinstance(async_client.timeout, httpx.Timeout)
+ assert isinstance(async_client.timeout, httpx2.Timeout)
copied = async_client.copy(timeout=None)
assert copied.timeout is None
- assert isinstance(async_client.timeout, httpx.Timeout)
+ assert isinstance(async_client.timeout, httpx2.Timeout)
async def test_copy_default_headers(self) -> None:
client = AsyncOpenAI(
@@ -1647,14 +1649,14 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic
async def test_request_timeout(self, async_client: AsyncOpenAI) -> None:
request = async_client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
assert timeout == DEFAULT_TIMEOUT
request = async_client._build_request(
- FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))
+ FinalRequestOptions(method="get", url="/foo", timeout=httpx2.Timeout(100.0))
)
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
- assert timeout == httpx.Timeout(100.0)
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
+ assert timeout == httpx2.Timeout(100.0)
async def test_client_timeout_option(self) -> None:
client = AsyncOpenAI(
@@ -1662,18 +1664,18 @@ async def test_client_timeout_option(self) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- timeout=httpx.Timeout(0),
+ timeout=httpx2.Timeout(0),
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
- assert timeout == httpx.Timeout(0)
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
+ assert timeout == httpx2.Timeout(0)
await client.close()
async def test_http_client_timeout_option(self) -> None:
# custom timeout given to the httpx client should be used
- async with httpx.AsyncClient(timeout=None) as http_client:
+ async with httpx2.AsyncClient(timeout=None) as http_client:
client = AsyncOpenAI(
base_url=base_url,
api_key=api_key,
@@ -1683,13 +1685,13 @@ async def test_http_client_timeout_option(self) -> None:
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
- assert timeout == httpx.Timeout(None)
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
+ assert timeout == httpx2.Timeout(None)
await client.close()
# no timeout given to the httpx client should not use the httpx default
- async with httpx.AsyncClient() as http_client:
+ async with httpx2.AsyncClient() as http_client:
client = AsyncOpenAI(
base_url=base_url,
api_key=api_key,
@@ -1699,13 +1701,13 @@ async def test_http_client_timeout_option(self) -> None:
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
assert timeout == DEFAULT_TIMEOUT
await client.close()
# explicitly passing the default timeout currently results in it being ignored
- async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client:
+ async with httpx2.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client:
client = AsyncOpenAI(
base_url=base_url,
api_key=api_key,
@@ -1715,14 +1717,14 @@ async def test_http_client_timeout_option(self) -> None:
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
+ timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore
assert timeout == DEFAULT_TIMEOUT # our default
await client.close()
def test_invalid_http_client(self) -> None:
with pytest.raises(TypeError, match="Invalid `http_client` arg"):
- with httpx.Client() as http_client:
+ with httpx2.Client() as http_client:
AsyncOpenAI(
base_url=base_url,
api_key=api_key,
@@ -1837,9 +1839,9 @@ async def test_validate_headers(self) -> None:
with pytest.raises(OpenAIError, match="Missing credentials"):
AsyncOpenAI(base_url=base_url, api_key=None, admin_api_key=None, _strict_response_validation=True)
- @pytest.mark.respx(base_url=base_url)
- async def test_api_key_provider_preserves_admin_auth(self, respx_mock: MockRouter) -> None:
- respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_api_key_provider_preserves_admin_auth(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/organization/projects").mock(return_value=httpx2.Response(200, json={"ok": True}))
provider_called = False
@@ -1851,7 +1853,7 @@ async def api_key_provider() -> str:
client = AsyncOpenAI(base_url=base_url, api_key=api_key_provider, admin_api_key=admin_api_key)
response = await client.get(
"/organization/projects",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"security": {"admin_api_key_auth": True}},
)
@@ -1871,20 +1873,20 @@ async def api_key_provider() -> str:
with pytest.raises(TypeError, match="Could not resolve authentication method"):
await client.get(
"/organization/projects",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"security": {"admin_api_key_auth": True}},
)
assert provider_called is False
- @pytest.mark.respx(base_url=base_url)
- async def test_workload_identity_preserves_admin_auth(self, respx_mock: MockRouter) -> None:
- respx_mock.get("/organization/projects").mock(return_value=httpx.Response(200, json={"ok": True}))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_workload_identity_preserves_admin_auth(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/organization/projects").mock(return_value=httpx2.Response(200, json={"ok": True}))
client = AsyncOpenAI(base_url=base_url, workload_identity=workload_identity, admin_api_key=admin_api_key)
response = await client.get(
"/organization/projects",
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"security": {"admin_api_key_auth": True}},
)
@@ -1899,7 +1901,7 @@ async def test_default_query_option(self) -> None:
default_query={"query_param": "bar"},
)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- url = httpx.URL(request.url)
+ url = httpx2.URL(request.url)
assert dict(url.params) == {"query_param": "bar"}
request = client._build_request(
@@ -1909,14 +1911,14 @@ async def test_default_query_option(self) -> None:
params={"foo": "baz", "query_param": "overridden"},
)
)
- url = httpx.URL(request.url)
+ url = httpx2.URL(request.url)
assert dict(url.params) == {"foo": "baz", "query_param": "overridden"}
await client.close()
async def test_hardcoded_query_params_in_url(self, async_client: AsyncOpenAI) -> None:
request = async_client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true"))
- url = httpx.URL(str(request.url))
+ url = httpx2.URL(str(request.url))
assert dict(url.params) == {"beta": "true"}
request = async_client._build_request(
@@ -1926,7 +1928,7 @@ async def test_hardcoded_query_params_in_url(self, async_client: AsyncOpenAI) ->
params={"limit": "10", "page": "abc"},
)
)
- url = httpx.URL(str(request.url))
+ url = httpx2.URL(str(request.url))
assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"}
request = async_client._build_request(
@@ -2064,16 +2066,16 @@ def test_multipart_repeating_array(self, async_client: AsyncOpenAI) -> None:
b"",
]
- @pytest.mark.respx(base_url=base_url)
- async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
- respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_binary_content_upload(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ respx2_mock.post("/upload").mock(side_effect=mirror_request_content)
file_content = b"Hello, this is a test file."
response = await async_client.post(
"/upload",
content=file_content,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/octet-stream"}},
)
@@ -2086,21 +2088,21 @@ async def test_binary_content_upload_with_asynciterator(self) -> None:
counter = Counter()
iterator = _make_async_iterator([file_content], counter=counter)
- async def mock_handler(request: httpx.Request) -> httpx.Response:
+ async def mock_handler(request: httpx2.Request) -> httpx2.Response:
assert counter.value == 0, "the request body should not have been read"
- return httpx.Response(200, content=await request.aread())
+ return httpx2.Response(200, content=await request.aread())
async with AsyncOpenAI(
base_url=base_url,
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)),
+ http_client=httpx2.AsyncClient(transport=MockTransport(handler=mock_handler)),
) as client:
response = await client.post(
"/upload",
content=iterator,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/octet-stream"}},
)
@@ -2109,11 +2111,11 @@ async def mock_handler(request: httpx.Request) -> httpx.Response:
assert response.content == file_content
assert counter.value == 1
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_binary_content_upload_with_body_is_deprecated(
- self, respx_mock: MockRouter, async_client: AsyncOpenAI
+ self, respx2_mock: MockRouter, async_client: AsyncOpenAI
) -> None:
- respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+ respx2_mock.post("/upload").mock(side_effect=mirror_request_content)
file_content = b"Hello, this is a test file."
@@ -2123,7 +2125,7 @@ async def test_binary_content_upload_with_body_is_deprecated(
response = await async_client.post(
"/upload",
body=file_content,
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
options={"headers": {"Content-Type": "application/octet-stream"}},
)
@@ -2131,22 +2133,22 @@ async def test_binary_content_upload_with_body_is_deprecated(
assert response.request.headers["Content-Type"] == "application/octet-stream"
assert response.content == file_content
- @pytest.mark.respx(base_url=base_url)
- async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_basic_union_response(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
class Model1(BaseModel):
name: str
class Model2(BaseModel):
foo: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2]))
assert isinstance(response, Model2)
assert response.foo == "bar"
- @pytest.mark.respx(base_url=base_url)
- async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_union_response_different_types(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
"""Union of objects with the same field name using a different type"""
class Model1(BaseModel):
@@ -2155,21 +2157,21 @@ class Model1(BaseModel):
class Model2(BaseModel):
foo: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2]))
assert isinstance(response, Model2)
assert response.foo == "bar"
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": 1}))
response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2]))
assert isinstance(response, Model1)
assert response.foo == 1
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_non_application_json_content_type_for_json_data(
- self, respx_mock: MockRouter, async_client: AsyncOpenAI
+ self, respx2_mock: MockRouter, async_client: AsyncOpenAI
) -> None:
"""
Response that sets Content-Type to something other than application/json but returns json data
@@ -2178,8 +2180,8 @@ async def test_non_application_json_content_type_for_json_data(
class Model(BaseModel):
foo: int
- respx_mock.get("/foo").mock(
- return_value=httpx.Response(
+ respx2_mock.get("/foo").mock(
+ return_value=httpx2.Response(
200,
content=json.dumps({"foo": 2}),
headers={"Content-Type": "application/text"},
@@ -2224,7 +2226,7 @@ async def test_base_url_env(self) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.AsyncClient(),
+ http_client=httpx2.AsyncClient(),
),
],
ids=["standard", "custom http client"],
@@ -2254,7 +2256,7 @@ async def test_base_url_trailing_slash(self, client: AsyncOpenAI) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.AsyncClient(),
+ http_client=httpx2.AsyncClient(),
),
],
ids=["standard", "custom http client"],
@@ -2284,7 +2286,7 @@ async def test_base_url_no_trailing_slash(self, client: AsyncOpenAI) -> None:
api_key=api_key,
admin_api_key=admin_api_key,
_strict_response_validation=True,
- http_client=httpx.AsyncClient(),
+ http_client=httpx2.AsyncClient(),
),
],
ids=["standard", "custom http client"],
@@ -2324,12 +2326,12 @@ async def test_client_context_manager(self) -> None:
assert not test_client.is_closed()
assert test_client.is_closed()
- @pytest.mark.respx(base_url=base_url)
- async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_client_response_validation_error(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
class Model(BaseModel):
foo: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}}))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json={"foo": {"invalid": True}}))
with pytest.raises(APIResponseValidationError) as exc:
await async_client.get("/foo", cast_to=Model)
@@ -2346,23 +2348,23 @@ async def test_client_max_retries_validation(self) -> None:
max_retries=cast(Any, None),
)
- @pytest.mark.respx(base_url=base_url)
- async def test_default_stream_cls(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_default_stream_cls(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
class Model(BaseModel):
name: str
- respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+ respx2_mock.post("/foo").mock(return_value=httpx2.Response(200, json={"foo": "bar"}))
stream = await async_client.post("/foo", cast_to=Model, stream=True, stream_cls=AsyncStream[Model])
assert isinstance(stream, AsyncStream)
await stream.response.aclose()
- @pytest.mark.respx(base_url=base_url)
- async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_received_text_for_expected_json(self, respx2_mock: MockRouter) -> None:
class Model(BaseModel):
name: str
- respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format"))
+ respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, text="my-custom-format"))
strict_client = AsyncOpenAI(
base_url=base_url, api_key=api_key, admin_api_key=admin_api_key, _strict_response_validation=True
@@ -2413,30 +2415,30 @@ class Model(BaseModel):
async def test_parse_retry_after_header(
self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncOpenAI
) -> None:
- headers = httpx.Headers({"retry-after": retry_after})
+ headers = httpx2.Headers({"retry-after": retry_after})
options = FinalRequestOptions(method="get", url="/foo", max_retries=3)
calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_does_not_retry_retry_after_above_max(
- self, respx_mock: MockRouter, async_client: AsyncOpenAI
+ self, respx2_mock: MockRouter, async_client: AsyncOpenAI
) -> None:
- route = respx_mock.get("/foo").mock(
- return_value=httpx.Response(429, headers={"retry-after": "121"}, json={"error": {}})
+ route = respx2_mock.get("/foo").mock(
+ return_value=httpx2.Response(429, headers={"retry-after": "121"}, json={"error": {}})
)
with pytest.raises(APIStatusError):
- await async_client.get("/foo", cast_to=httpx.Response)
+ await async_client.get("/foo", cast_to=httpx2.Response)
assert route.call_count == 1
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_invalid_retry_after_date_does_not_mask_status_error(
- self, respx_mock: MockRouter, async_client: AsyncOpenAI
+ self, respx2_mock: MockRouter, async_client: AsyncOpenAI
) -> None:
- route = respx_mock.get("/foo").mock(
- return_value=httpx.Response(
+ route = respx2_mock.get("/foo").mock(
+ return_value=httpx2.Response(
400,
headers={"retry-after": "Fri, 29 Sep 100000 16:26:57 GMT"},
json={"error": {}},
@@ -2444,14 +2446,16 @@ async def test_invalid_retry_after_date_does_not_mask_status_error(
)
with pytest.raises(APIStatusError):
- await async_client.get("/foo", cast_to=httpx.Response)
+ await async_client.get("/foo", cast_to=httpx2.Response)
assert route.call_count == 1
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
- async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
- respx_mock.post("/chat/completions").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_retrying_timeout_errors_doesnt_leak(
+ self, respx2_mock: MockRouter, async_client: AsyncOpenAI
+ ) -> None:
+ respx2_mock.post("/chat/completions").mock(side_effect=httpx2.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
await async_client.chat.completions.with_streaming_response.create(
@@ -2467,9 +2471,9 @@ async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter,
assert _get_open_connections(async_client) == 0
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
- async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
- respx_mock.post("/chat/completions").mock(return_value=httpx.Response(500))
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_retrying_status_errors_doesnt_leak(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ respx2_mock.post("/chat/completions").mock(return_value=httpx2.Response(500))
with pytest.raises(APIStatusError):
await async_client.chat.completions.with_streaming_response.create(
@@ -2485,29 +2489,29 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter,
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
@pytest.mark.parametrize("failure_mode", ["status", "exception"])
async def test_retries_taken(
self,
async_client: AsyncOpenAI,
failures_before_success: int,
failure_mode: Literal["status", "exception"],
- respx_mock: MockRouter,
+ respx2_mock: MockRouter,
) -> None:
client = async_client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
if failure_mode == "exception":
raise RuntimeError("oops")
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
response = await client.chat.completions.with_raw_response.create(
messages=[
@@ -2524,22 +2528,22 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_omit_retry_count_header(
- self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter
+ self, async_client: AsyncOpenAI, failures_before_success: int, respx2_mock: MockRouter
) -> None:
client = async_client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
response = await client.chat.completions.with_raw_response.create(
messages=[
@@ -2556,22 +2560,22 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_overwrite_retry_count_header(
- self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter
+ self, async_client: AsyncOpenAI, failures_before_success: int, respx2_mock: MockRouter
) -> None:
client = async_client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
response = await client.chat.completions.with_raw_response.create(
messages=[
@@ -2588,22 +2592,22 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
- @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.respx2(base_url=base_url)
async def test_retries_taken_new_response_class(
- self, async_client: AsyncOpenAI, failures_before_success: int, respx_mock: MockRouter
+ self, async_client: AsyncOpenAI, failures_before_success: int, respx2_mock: MockRouter
) -> None:
client = async_client.with_options(max_retries=4)
nb_retries = 0
- def retry_handler(_request: httpx.Request) -> httpx.Response:
+ def retry_handler(_request: httpx2.Request) -> httpx2.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
- return httpx.Response(500)
- return httpx.Response(200)
+ return httpx2.Response(500)
+ return httpx2.Response(200)
- respx_mock.post("/chat/completions").mock(side_effect=retry_handler)
+ respx2_mock.post("/chat/completions").mock(side_effect=retry_handler)
async with client.chat.completions.with_streaming_response.create(
messages=[
@@ -2648,31 +2652,31 @@ async def test_default_client_creation(self) -> None:
trust_env=True,
http1=True,
http2=False,
- limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
+ limits=httpx2.Limits(max_connections=100, max_keepalive_connections=20),
)
- @pytest.mark.respx(base_url=base_url)
- async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_follow_redirects(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
# Test that the default follow_redirects=True allows following redirects
- respx_mock.post("/redirect").mock(
- return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
+ respx2_mock.post("/redirect").mock(
+ return_value=httpx2.Response(302, headers={"Location": f"{base_url}/redirected"})
)
- respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"}))
+ respx2_mock.get("/redirected").mock(return_value=httpx2.Response(200, json={"status": "ok"}))
- response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response)
+ response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx2.Response)
assert response.status_code == 200
assert response.json() == {"status": "ok"}
- @pytest.mark.respx(base_url=base_url)
- async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncOpenAI) -> None:
+ @pytest.mark.respx2(base_url=base_url)
+ async def test_follow_redirects_disabled(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None:
# Test that follow_redirects=False prevents following redirects
- respx_mock.post("/redirect").mock(
- return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"})
+ respx2_mock.post("/redirect").mock(
+ return_value=httpx2.Response(302, headers={"Location": f"{base_url}/redirected"})
)
with pytest.raises(APIStatusError) as exc_info:
await async_client.post(
- "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response
+ "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx2.Response
)
assert exc_info.value.response.status_code == 302
@@ -2700,12 +2704,12 @@ async def test_api_key_before_after_refresh_str(self) -> None:
assert client.auth_headers.get("Authorization") == "Bearer test_api_key"
- @pytest.mark.respx()
- async def test_bearer_token_refresh_async(self, respx_mock: MockRouter) -> None:
- respx_mock.post(base_url + "/chat/completions").mock(
+ @pytest.mark.respx2()
+ async def test_bearer_token_refresh_async(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.post(base_url + "/chat/completions").mock(
side_effect=[
- httpx.Response(500, json={"error": "server error"}),
- httpx.Response(200, json={"foo": "bar"}),
+ httpx2.Response(500, json={"error": "server error"}),
+ httpx2.Response(200, json={"foo": "bar"}),
]
)
@@ -2724,7 +2728,7 @@ async def token_provider() -> str:
client = AsyncOpenAI(base_url=base_url, api_key=token_provider)
await client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 2
assert calls[0].request.headers.get("Authorization") == "Bearer first"
@@ -2743,8 +2747,8 @@ async def token_provider_2() -> str:
class TestWorkloadIdentity401Retry:
- @pytest.mark.respx()
- def test_workload_identity_401_retry(self, respx_mock: MockRouter) -> None:
+ @pytest.mark.respx2()
+ def test_workload_identity_401_retry(self, respx2_mock: MockRouter) -> None:
provider_call_count = 0
def provider() -> str:
@@ -2752,9 +2756,9 @@ def provider() -> str:
provider_call_count += 1
return f"external-subject-token-{provider_call_count}"
- respx_mock.post("https://auth.openai.com/oauth/token").mock(
+ respx2_mock.post("https://auth.openai.com/oauth/token").mock(
side_effect=[
- httpx.Response(
+ httpx2.Response(
200,
json={
"access_token": "openai-access-token-1",
@@ -2763,7 +2767,7 @@ def provider() -> str:
"expires_in": 3600,
},
),
- httpx.Response(
+ httpx2.Response(
200,
json={
"access_token": "openai-access-token-2",
@@ -2775,10 +2779,10 @@ def provider() -> str:
]
)
- respx_mock.post(base_url + "/chat/completions").mock(
+ respx2_mock.post(base_url + "/chat/completions").mock(
side_effect=[
- httpx.Response(401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}),
- httpx.Response(
+ httpx2.Response(401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}),
+ httpx2.Response(
200,
json={
"id": "chatcmpl-123",
@@ -2806,24 +2810,24 @@ def provider() -> str:
) as client:
client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 4
- assert calls[0].request.url == httpx.URL("https://auth.openai.com/oauth/token")
- assert calls[1].request.url == httpx.URL(base_url + "/chat/completions")
+ assert calls[0].request.url == httpx2.URL("https://auth.openai.com/oauth/token")
+ assert calls[1].request.url == httpx2.URL(base_url + "/chat/completions")
assert calls[1].request.headers.get("Authorization") == "Bearer openai-access-token-1"
- assert calls[2].request.url == httpx.URL("https://auth.openai.com/oauth/token")
+ assert calls[2].request.url == httpx2.URL("https://auth.openai.com/oauth/token")
- assert calls[3].request.url == httpx.URL(base_url + "/chat/completions")
+ assert calls[3].request.url == httpx2.URL(base_url + "/chat/completions")
assert calls[3].request.headers.get("Authorization") == "Bearer openai-access-token-2"
assert provider_call_count == 2
- @pytest.mark.respx()
- def test_401_without_workload_identity_no_retry(self, respx_mock: MockRouter) -> None:
- respx_mock.post(base_url + "/chat/completions").mock(
- return_value=httpx.Response(
+ @pytest.mark.respx2()
+ def test_401_without_workload_identity_no_retry(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.post(base_url + "/chat/completions").mock(
+ return_value=httpx2.Response(
401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}
)
)
@@ -2838,11 +2842,11 @@ def test_401_without_workload_identity_no_retry(self, respx_mock: MockRouter) ->
assert exc_info.value.status_code == 401
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 1
- @pytest.mark.respx()
- def test_non_401_errors_no_retry(self, respx_mock: MockRouter) -> None:
+ @pytest.mark.respx2()
+ def test_non_401_errors_no_retry(self, respx2_mock: MockRouter) -> None:
provider_call_count = 0
def provider() -> str:
@@ -2850,8 +2854,8 @@ def provider() -> str:
provider_call_count += 1
return "external-subject-token"
- respx_mock.post("https://auth.openai.com/oauth/token").mock(
- return_value=httpx.Response(
+ respx2_mock.post("https://auth.openai.com/oauth/token").mock(
+ return_value=httpx2.Response(
200,
json={
"access_token": "openai-access-token-1",
@@ -2862,8 +2866,8 @@ def provider() -> str:
)
)
- respx_mock.post(base_url + "/chat/completions").mock(
- return_value=httpx.Response(403, json={"error": {"message": "Forbidden", "type": "invalid_request_error"}})
+ respx2_mock.post(base_url + "/chat/completions").mock(
+ return_value=httpx2.Response(403, json={"error": {"message": "Forbidden", "type": "invalid_request_error"}})
)
with OpenAI(
@@ -2884,15 +2888,15 @@ def provider() -> str:
assert exc_info.value.status_code == 403
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 2
assert provider_call_count == 1
class TestAsyncWorkloadIdentity401Retry:
- @pytest.mark.respx()
- async def test_workload_identity_401_retry(self, respx_mock: MockRouter) -> None:
+ @pytest.mark.respx2()
+ async def test_workload_identity_401_retry(self, respx2_mock: MockRouter) -> None:
provider_call_count = 0
def provider() -> str:
@@ -2900,9 +2904,9 @@ def provider() -> str:
provider_call_count += 1
return f"external-subject-token-{provider_call_count}"
- respx_mock.post("https://auth.openai.com/oauth/token").mock(
+ respx2_mock.post("https://auth.openai.com/oauth/token").mock(
side_effect=[
- httpx.Response(
+ httpx2.Response(
200,
json={
"access_token": "openai-access-token-1",
@@ -2911,7 +2915,7 @@ def provider() -> str:
"expires_in": 3600,
},
),
- httpx.Response(
+ httpx2.Response(
200,
json={
"access_token": "openai-access-token-2",
@@ -2923,10 +2927,10 @@ def provider() -> str:
]
)
- respx_mock.post(base_url + "/chat/completions").mock(
+ respx2_mock.post(base_url + "/chat/completions").mock(
side_effect=[
- httpx.Response(401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}),
- httpx.Response(
+ httpx2.Response(401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}),
+ httpx2.Response(
200,
json={
"id": "chatcmpl-123",
@@ -2954,24 +2958,24 @@ def provider() -> str:
) as client:
await client.chat.completions.create(messages=[], model="gpt-4")
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 4
- assert calls[0].request.url == httpx.URL("https://auth.openai.com/oauth/token")
- assert calls[1].request.url == httpx.URL(base_url + "/chat/completions")
+ assert calls[0].request.url == httpx2.URL("https://auth.openai.com/oauth/token")
+ assert calls[1].request.url == httpx2.URL(base_url + "/chat/completions")
assert calls[1].request.headers.get("Authorization") == "Bearer openai-access-token-1"
- assert calls[2].request.url == httpx.URL("https://auth.openai.com/oauth/token")
+ assert calls[2].request.url == httpx2.URL("https://auth.openai.com/oauth/token")
- assert calls[3].request.url == httpx.URL(base_url + "/chat/completions")
+ assert calls[3].request.url == httpx2.URL(base_url + "/chat/completions")
assert calls[3].request.headers.get("Authorization") == "Bearer openai-access-token-2"
assert provider_call_count == 2
- @pytest.mark.respx()
- async def test_401_without_workload_identity_no_retry(self, respx_mock: MockRouter) -> None:
- respx_mock.post(base_url + "/chat/completions").mock(
- return_value=httpx.Response(
+ @pytest.mark.respx2()
+ async def test_401_without_workload_identity_no_retry(self, respx2_mock: MockRouter) -> None:
+ respx2_mock.post(base_url + "/chat/completions").mock(
+ return_value=httpx2.Response(
401, json={"error": {"message": "Unauthorized", "type": "invalid_request_error"}}
)
)
@@ -2986,11 +2990,11 @@ async def test_401_without_workload_identity_no_retry(self, respx_mock: MockRout
assert exc_info.value.status_code == 401
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 1
- @pytest.mark.respx()
- async def test_non_401_errors_no_retry(self, respx_mock: MockRouter) -> None:
+ @pytest.mark.respx2()
+ async def test_non_401_errors_no_retry(self, respx2_mock: MockRouter) -> None:
provider_call_count = 0
def provider() -> str:
@@ -2998,8 +3002,8 @@ def provider() -> str:
provider_call_count += 1
return "external-subject-token"
- respx_mock.post("https://auth.openai.com/oauth/token").mock(
- return_value=httpx.Response(
+ respx2_mock.post("https://auth.openai.com/oauth/token").mock(
+ return_value=httpx2.Response(
200,
json={
"access_token": "openai-access-token-1",
@@ -3010,8 +3014,8 @@ def provider() -> str:
)
)
- respx_mock.post(base_url + "/chat/completions").mock(
- return_value=httpx.Response(403, json={"error": {"message": "Forbidden", "type": "invalid_request_error"}})
+ respx2_mock.post(base_url + "/chat/completions").mock(
+ return_value=httpx2.Response(403, json={"error": {"message": "Forbidden", "type": "invalid_request_error"}})
)
async with AsyncOpenAI(
@@ -3032,7 +3036,7 @@ def provider() -> str:
assert exc_info.value.status_code == 403
- calls = cast("list[MockRequestCall]", respx_mock.calls)
+ calls = cast("list[MockRequestCall]", respx2_mock.calls)
assert len(calls) == 2
assert provider_call_count == 1
diff --git a/tests/test_httpx2.py b/tests/test_httpx2.py
index 3afd2d68d5..764fc00f0b 100644
--- a/tests/test_httpx2.py
+++ b/tests/test_httpx2.py
@@ -4,7 +4,7 @@
from typing import Any
from typing_extensions import override
-import httpx
+import httpx2
import pytest
import openai
@@ -22,25 +22,12 @@
from openai.providers import bedrock
from openai._constants import DEFAULT_TIMEOUT
-httpx2 = pytest.importorskip("httpx2")
-
-@pytest.fixture(autouse=True)
-def forbid_httpx_execution(monkeypatch: pytest.MonkeyPatch) -> None:
- def forbidden(*_args: object, **_kwargs: object) -> None:
- raise AssertionError("the experimental path unexpectedly executed an HTTPX client")
-
- monkeypatch.setattr(httpx.Client, "build_request", forbidden)
- monkeypatch.setattr(httpx.Client, "send", forbidden)
- monkeypatch.setattr(httpx.AsyncClient, "build_request", forbidden)
- monkeypatch.setattr(httpx.AsyncClient, "send", forbidden)
-
-
-def model_list(request: httpx.Request) -> httpx.Response:
+def model_list(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(200, json={"object": "list", "data": []}, request=request)
-def sse_response(request: httpx.Request) -> httpx.Response:
+def sse_response(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(
200,
headers={"content-type": "text/event-stream"},
@@ -69,21 +56,21 @@ async def test_httpx2_helpers_supply_sdk_defaults_and_accept_native_proxy() -> N
def test_sync_helper_preserves_httpx2_family_for_parsed_raw_and_sse() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
hooks: list[str] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
return sse_response(request) if request.url.path.endswith("/responses") else model_list(request)
- def on_request(request: httpx.Request) -> None:
+ def on_request(request: httpx2.Request) -> None:
hooks.append(type(request).__module__)
with OpenAI(
api_key="test",
base_url=httpx2.URL("https://example.test/v1"),
http_client=openai.DefaultHttpx2Client(
- timeout=httpx.Timeout(30.0, read=10.0),
+ timeout=httpx2.Timeout(30.0, read=10.0),
auth=httpx2.BasicAuth("fake-test-user", "fake-test-password"),
headers=[("x-repeated", "one"), ("x-repeated", "two")],
mounts={"https://example.test": httpx2.MockTransport(handler)},
@@ -100,7 +87,7 @@ def on_request(request: httpx.Request) -> None:
"/multipart",
files={"file": ("example.txt", b"body", "text/plain")},
options={"headers": {"Content-Type": "multipart/form-data"}},
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
)
assert parsed.object == "list"
@@ -122,21 +109,21 @@ def on_request(request: httpx.Request) -> None:
async def test_async_helper_preserves_httpx2_family_for_parsed_raw_and_sse() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
hooks: list[str] = []
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
return sse_response(request) if request.url.path.endswith("/responses") else model_list(request)
- async def on_request(request: httpx.Request) -> None:
+ async def on_request(request: httpx2.Request) -> None:
hooks.append(type(request).__module__)
async with AsyncOpenAI(
api_key="test",
base_url=httpx2.URL("https://example.test/v1"),
http_client=openai.DefaultAsyncHttpx2Client(
- timeout=httpx.Timeout(30.0, read=10.0),
+ timeout=httpx2.Timeout(30.0, read=10.0),
auth=httpx2.BasicAuth("fake-test-user", "fake-test-password"),
headers=[("x-repeated", "one"), ("x-repeated", "two")],
transport=httpx2.MockTransport(handler),
@@ -153,7 +140,7 @@ async def on_request(request: httpx.Request) -> None:
"/multipart",
files={"file": ("example.txt", b"body", "text/plain")},
options={"headers": {"Content-Type": "multipart/form-data"}},
- cast_to=httpx.Response,
+ cast_to=httpx2.Response,
)
assert parsed.object == "list"
@@ -196,7 +183,7 @@ async def test_httpx2_urls_and_response_casts() -> None:
class ResponseSubclass(httpx2.Response):
pass
- def model(request: httpx.Request) -> httpx.Response:
+ def model(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(
200,
request=request,
@@ -218,7 +205,7 @@ def model(request: httpx.Request) -> httpx.Response:
with pytest.raises(ValueError, match="Subclasses of HTTP response classes"):
client.get("/models", cast_to=ResponseSubclass)
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
return model(request)
async with AsyncOpenAI(
@@ -308,14 +295,14 @@ async def test_httpx2_urls_work_for_all_websocket_builders() -> None:
async def test_httpx2_native_timeouts_set_numeric_read_timeout_header() -> None:
- sync_requests: list[httpx.Request] = []
- async_requests: list[httpx.Request] = []
+ sync_requests: list[httpx2.Request] = []
+ async_requests: list[httpx2.Request] = []
- def sync_handler(request: httpx.Request) -> httpx.Response:
+ def sync_handler(request: httpx2.Request) -> httpx2.Response:
sync_requests.append(request)
return model_list(request)
- async def async_handler(request: httpx.Request) -> httpx.Response:
+ async def async_handler(request: httpx2.Request) -> httpx2.Response:
async_requests.append(request)
return model_list(request)
@@ -344,7 +331,7 @@ async def async_handler(request: httpx.Request) -> httpx.Response:
async def test_direct_async_injection() -> None:
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
return model_list(request)
direct = httpx2.AsyncClient(transport=httpx2.MockTransport(handler), trust_env=False)
@@ -357,9 +344,9 @@ async def handler(request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failure", ["timeout", "connection", "status"])
def test_sync_retries_and_failure_families(failure: str, monkeypatch: pytest.MonkeyPatch) -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
if len(requests) > 1:
return model_list(request)
@@ -388,7 +375,7 @@ def no_sleep(**_kwargs: Any) -> None:
assert len(requests) == 2
assert all(type(request).__module__ == "httpx2" for request in requests)
- def always_fail(request: httpx.Request) -> httpx.Response:
+ def always_fail(request: httpx2.Request) -> httpx2.Response:
if failure == "timeout":
raise httpx2.ReadTimeout("timeout", request=request)
if failure == "connection":
@@ -419,9 +406,9 @@ def always_fail(request: httpx.Request) -> httpx.Response:
@pytest.mark.parametrize("failure", ["timeout", "connection", "status"])
async def test_async_retries_and_failure_families(failure: str, monkeypatch: pytest.MonkeyPatch) -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- async def handler(request: httpx.Request) -> httpx.Response:
+ async def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
if len(requests) > 1:
return model_list(request)
@@ -450,7 +437,7 @@ async def no_sleep(**_kwargs: Any) -> None:
assert len(requests) == 2
assert all(type(request).__module__ == "httpx2" for request in requests)
- async def always_fail(request: httpx.Request) -> httpx.Response:
+ async def always_fail(request: httpx2.Request) -> httpx2.Response:
if failure == "timeout":
raise httpx2.ReadTimeout("timeout", request=request)
if failure == "connection":
@@ -480,14 +467,14 @@ async def always_fail(request: httpx.Request) -> httpx.Response:
async def test_provider_auth_and_stream_consumed_families() -> None:
- sync_requests: list[httpx.Request] = []
- async_requests: list[httpx.Request] = []
+ sync_requests: list[httpx2.Request] = []
+ async_requests: list[httpx2.Request] = []
- def sync_handler(request: httpx.Request) -> httpx.Response:
+ def sync_handler(request: httpx2.Request) -> httpx2.Response:
sync_requests.append(request)
return model_list(request)
- async def async_handler(request: httpx.Request) -> httpx.Response:
+ async def async_handler(request: httpx2.Request) -> httpx2.Response:
async_requests.append(request)
return model_list(request)
@@ -509,35 +496,39 @@ async def async_handler(request: httpx.Request) -> httpx.Response:
assert async_requests[0].headers["authorization"] == "Bearer bedrock-token"
class SyncStream(httpx2.SyncByteStream):
+ @override
def __iter__(self):
yield b'{"object":"list","data":[]}'
class AsyncStream(httpx2.AsyncByteStream):
+ @override
async def __aiter__(self):
yield b'{"object":"list","data":[]}'
class FailingSyncStream(httpx2.SyncByteStream):
+ @override
def __iter__(self):
yield b"partial"
raise httpx2.ReadTimeout("stream timeout")
class FailingAsyncStream(httpx2.AsyncByteStream):
+ @override
async def __aiter__(self):
yield b"partial"
raise httpx2.ReadTimeout("stream timeout")
- def sync_stream_handler(request: httpx.Request) -> httpx.Response:
+ def sync_stream_handler(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(200, headers={"content-type": "application/json"}, stream=SyncStream(), request=request)
- async def async_stream_handler(request: httpx.Request) -> httpx.Response:
+ async def async_stream_handler(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(200, headers={"content-type": "application/json"}, stream=AsyncStream(), request=request)
- def sync_failing_stream_handler(request: httpx.Request) -> httpx.Response:
+ def sync_failing_stream_handler(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(
200, headers={"content-type": "application/json"}, stream=FailingSyncStream(), request=request
)
- async def async_failing_stream_handler(request: httpx.Request) -> httpx.Response:
+ async def async_failing_stream_handler(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(
200, headers={"content-type": "application/json"}, stream=FailingAsyncStream(), request=request
)
@@ -616,21 +607,23 @@ async def on_exception(self, exception: Exception) -> None:
self.exception = exception
class FailingSyncStream(httpx2.SyncByteStream):
+ @override
def __iter__(self):
yield b"partial"
raise httpx2.ReadTimeout("assistant stream timeout")
class FailingAsyncStream(httpx2.AsyncByteStream):
+ @override
async def __aiter__(self):
yield b"partial"
raise httpx2.ReadTimeout("assistant stream timeout")
- def sync_response(request: httpx.Request) -> httpx.Response:
+ def sync_response(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(
200, headers={"content-type": "text/event-stream"}, stream=FailingSyncStream(), request=request
)
- async def async_response(request: httpx.Request) -> httpx.Response:
+ async def async_response(request: httpx2.Request) -> httpx2.Response:
return httpx2.Response(
200, headers={"content-type": "text/event-stream"}, stream=FailingAsyncStream(), request=request
)
@@ -671,14 +664,14 @@ async def async_response(request: httpx.Request) -> httpx.Response:
async def test_sigv4_provider_preserves_httpx2_family_and_rejects_one_shot_bodies() -> None:
pytest.importorskip("botocore")
- sync_requests: list[httpx.Request] = []
- async_requests: list[httpx.Request] = []
+ sync_requests: list[httpx2.Request] = []
+ async_requests: list[httpx2.Request] = []
- def sync_handler(request: httpx.Request) -> httpx.Response:
+ def sync_handler(request: httpx2.Request) -> httpx2.Response:
sync_requests.append(request)
return model_list(request)
- async def async_handler(request: httpx.Request) -> httpx.Response:
+ async def async_handler(request: httpx2.Request) -> httpx2.Response:
async_requests.append(request)
return model_list(request)
@@ -695,9 +688,9 @@ async def async_handler(request: httpx.Request) -> httpx.Response:
http_client=openai.DefaultHttpx2Client(transport=httpx2.MockTransport(sync_handler), trust_env=False),
max_retries=0,
) as sync_client:
- sync_client.post("/responses", content=b"body", cast_to=httpx.Response)
+ sync_client.post("/responses", content=b"body", cast_to=httpx2.Response)
with pytest.raises(OpenAIError, match="requires a replayable request body"):
- sync_client.post("/responses", content=iter([b"body"]), cast_to=httpx.Response)
+ sync_client.post("/responses", content=iter([b"body"]), cast_to=httpx2.Response)
async def body():
yield b"body"
@@ -707,9 +700,9 @@ async def body():
http_client=openai.DefaultAsyncHttpx2Client(transport=httpx2.MockTransport(async_handler), trust_env=False),
max_retries=0,
) as async_client:
- await async_client.post("/responses", content=b"body", cast_to=httpx.Response)
+ await async_client.post("/responses", content=b"body", cast_to=httpx2.Response)
with pytest.raises(OpenAIError, match="requires a replayable request body"):
- await async_client.post("/responses", content=body(), cast_to=httpx.Response)
+ await async_client.post("/responses", content=body(), cast_to=httpx2.Response)
assert len(sync_requests) == 1
assert len(async_requests) == 1
diff --git a/tests/test_httpx2_base.py b/tests/test_httpx2_base.py
index eb81c69a98..0d0b28351e 100644
--- a/tests/test_httpx2_base.py
+++ b/tests/test_httpx2_base.py
@@ -9,42 +9,28 @@
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from typing_extensions import override
-import httpx
-import respx
+import httpx2
import pytest
import openai
-from openai import OpenAI, AsyncOpenAI, _httpx2 as httpx2_helpers
+from openai import OpenAI, AsyncOpenAI
+from tests.respx2 import MockRouter
-def test_base_import_does_not_load_httpx2() -> None:
- subprocess.run([sys.executable, "-c", "import sys; import openai; assert 'httpx2' not in sys.modules"], check=True)
+def test_base_import_does_not_load_legacy_httpx() -> None:
+ subprocess.run(
+ [
+ sys.executable,
+ "-c",
+ "import sys; import openai; assert 'httpx2' in sys.modules; assert 'httpx' not in sys.modules",
+ ],
+ check=True,
+ )
-def test_missing_httpx2_extra_is_actionable(monkeypatch: pytest.MonkeyPatch) -> None:
- monkeypatch.setattr(httpx2_helpers.sys, "version_info", (3, 10))
-
- def missing_httpx2(name: str) -> object:
- raise ImportError(name)
-
- monkeypatch.setattr(httpx2_helpers.importlib, "import_module", missing_httpx2)
-
- for helper in (openai.DefaultHttpx2Client, openai.DefaultAsyncHttpx2Client):
- with pytest.raises(RuntimeError, match=r"install the httpx2 extra: pip install 'openai\[httpx2\]'"):
- helper()
-
-
-def test_python39_httpx2_error_is_actionable(monkeypatch: pytest.MonkeyPatch) -> None:
- monkeypatch.setattr(httpx2_helpers.sys, "version_info", (3, 9))
-
- for helper in (openai.DefaultHttpx2Client, openai.DefaultAsyncHttpx2Client):
- with pytest.raises(RuntimeError, match=r"HTTPX2 requires Python 3\.10 or later.*openai\[httpx2\]"):
- helper()
-
-
-@pytest.mark.respx(base_url="https://example.test/v1")
-def test_default_httpx_family_and_respx_are_unchanged(respx_mock: respx.MockRouter) -> None:
- route = respx_mock.get("/models").mock(return_value=httpx.Response(200, json={"object": "list", "data": []}))
+@pytest.mark.respx2(base_url="https://example.test/v1")
+def test_default_client_and_respx_use_httpx2(respx2_mock: MockRouter) -> None:
+ route = respx2_mock.get("/models").mock(return_value=httpx2.Response(200, json={"object": "list", "data": []}))
with warnings.catch_warnings(record=True) as captured:
warnings.simplefilter("always")
@@ -53,35 +39,33 @@ def test_default_httpx_family_and_respx_are_unchanged(respx_mock: respx.MockRout
assert route.called
assert captured == []
- assert isinstance(response.http_response, httpx.Response)
- assert isinstance(response.http_request, httpx.Request)
+ assert isinstance(response.http_response, httpx2.Response)
+ assert isinstance(response.http_request, httpx2.Request)
-async def test_existing_httpx_helpers_and_injected_clients_are_unchanged() -> None:
- class SyncHttpxClient(openai.DefaultHttpxClient):
+async def test_existing_http_client_helpers_default_to_httpx2() -> None:
+ class SyncHttpClient(openai.DefaultHttpxClient):
pass
- class AsyncHttpxClient(openai.DefaultAsyncHttpxClient):
+ class AsyncHttpClient(openai.DefaultAsyncHttpxClient):
pass
- def handler(request: httpx.Request) -> httpx.Response:
- return httpx.Response(200, json={"object": "list", "data": []}, request=request)
+ def handler(request: httpx2.Request) -> httpx2.Response:
+ return httpx2.Response(200, json={"object": "list", "data": []}, request=request)
- with SyncHttpxClient(transport=httpx.MockTransport(handler), trust_env=False) as http_client:
+ with SyncHttpClient(transport=httpx2.MockTransport(handler), trust_env=False) as http_client:
with OpenAI(api_key="test", base_url="https://example.test/v1", http_client=http_client) as client:
response = client.models.with_raw_response.list()
- assert isinstance(response.http_response, httpx.Response)
+ assert isinstance(response.http_response, httpx2.Response)
- async with AsyncHttpxClient(transport=httpx.MockTransport(handler), trust_env=False) as http_client:
+ async with AsyncHttpClient(transport=httpx2.MockTransport(handler), trust_env=False) as http_client:
async with AsyncOpenAI(api_key="test", base_url="https://example.test/v1", http_client=http_client) as client:
response = await client.models.with_raw_response.list()
- assert isinstance(response.http_response, httpx.Response)
-
+ assert isinstance(response.http_response, httpx2.Response)
-async def test_existing_aiohttp_adapter_is_unchanged_when_installed() -> None:
- if importlib.util.find_spec("httpx_aiohttp") is None:
- pytest.skip("the aiohttp extra is not installed")
+@pytest.mark.skipif(importlib.util.find_spec("aiohttp") is None, reason="the aiohttp extra is not installed")
+async def test_default_aiohttp_client_uses_httpx2() -> None:
class ModelsHandler(BaseHTTPRequestHandler):
def do_GET(self) -> None:
self.send_response(200)
@@ -103,10 +87,11 @@ def log_message(self, format: str, *_args: object) -> None: # noqa: A002
http_client=openai.DefaultAioHttpClient(),
max_retries=0,
) as client:
+ assert isinstance(client._client, httpx2.AsyncClient)
response = await client.models.with_raw_response.list()
finally:
await asyncio.to_thread(server.shutdown)
thread.join()
server.server_close()
- assert isinstance(response.http_response, httpx.Response)
+ assert isinstance(response.http_response, httpx2.Response)
diff --git a/tests/test_httpx2_respx.py b/tests/test_httpx2_respx.py
index 37c42d9628..ab73b196bc 100644
--- a/tests/test_httpx2_respx.py
+++ b/tests/test_httpx2_respx.py
@@ -2,27 +2,23 @@
import os
-import httpx
+import httpx2
import pytest
-from respx import MockRouter
from openai import OpenAI, AsyncOpenAI, APITimeoutError
+from tests.respx2 import MockRouter
-httpx2 = pytest.importorskip("httpx2")
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-pytestmark = pytest.mark.skipif(
- os.environ.get("OPENAI_TEST_HTTP_CLIENT") != "httpx2", reason="requires the HTTPX2 test lane"
-)
-@pytest.mark.respx(base_url=base_url)
-def test_respx_bridge_preserves_native_sync_family_and_request_content(client: OpenAI, respx_mock: MockRouter) -> None:
- def mirror(request: httpx.Request) -> httpx.Response:
+@pytest.mark.respx2(base_url=base_url)
+def test_respx2_preserves_native_sync_family_and_request_content(client: OpenAI, respx2_mock: MockRouter) -> None:
+ def mirror(request: httpx2.Request) -> httpx2.Response:
assert request.url.path == "/upload"
assert request.headers["x-test"] == "sync"
- return httpx.Response(200, content=request.content)
+ return httpx2.Response(200, content=request.content)
- respx_mock.post("/upload").mock(side_effect=mirror)
+ respx2_mock.post("/upload").mock(side_effect=mirror)
response = client.post(
"/upload", content=b"sync body", options={"headers": {"x-test": "sync"}}, cast_to=httpx2.Response
@@ -31,19 +27,19 @@ def mirror(request: httpx.Request) -> httpx.Response:
assert isinstance(response, httpx2.Response)
assert isinstance(response.request, httpx2.Request)
assert response.content == b"sync body"
- assert len(respx_mock.calls) == 1
+ assert len(respx2_mock.calls) == 1
-@pytest.mark.respx(base_url=base_url)
-async def test_respx_bridge_preserves_native_async_family_and_request_content(
- async_client: AsyncOpenAI, respx_mock: MockRouter
+@pytest.mark.respx2(base_url=base_url)
+async def test_respx2_preserves_native_async_family_and_request_content(
+ async_client: AsyncOpenAI, respx2_mock: MockRouter
) -> None:
- async def mirror(request: httpx.Request) -> httpx.Response:
+ async def mirror(request: httpx2.Request) -> httpx2.Response:
assert request.url.path == "/upload"
assert request.headers["x-test"] == "async"
- return httpx.Response(200, content=await request.aread())
+ return httpx2.Response(200, content=await request.aread())
- respx_mock.post("/upload").mock(side_effect=mirror)
+ respx2_mock.post("/upload").mock(side_effect=mirror)
response = await async_client.post(
"/upload", content=b"async body", options={"headers": {"x-test": "async"}}, cast_to=httpx2.Response
@@ -52,12 +48,12 @@ async def mirror(request: httpx.Request) -> httpx.Response:
assert isinstance(response, httpx2.Response)
assert isinstance(response.request, httpx2.Request)
assert response.content == b"async body"
- assert len(respx_mock.calls) == 1
+ assert len(respx2_mock.calls) == 1
-@pytest.mark.respx(base_url=base_url)
-def test_respx_bridge_maps_timeout_to_native_family(client: OpenAI, respx_mock: MockRouter) -> None:
- respx_mock.get("/models").mock(side_effect=httpx.ReadTimeout("mock timeout"))
+@pytest.mark.respx2(base_url=base_url)
+def test_respx2_maps_timeout_to_native_family(client: OpenAI, respx2_mock: MockRouter) -> None:
+ respx2_mock.get("/models").mock(side_effect=httpx2.ReadTimeout("mock timeout"))
with pytest.raises(APITimeoutError) as exc_info:
client.with_options(max_retries=0).models.list()
diff --git a/tests/test_httpx2_workload.py b/tests/test_httpx2_workload.py
index 14bb997248..fdc787c18c 100644
--- a/tests/test_httpx2_workload.py
+++ b/tests/test_httpx2_workload.py
@@ -1,12 +1,10 @@
from __future__ import annotations
import json
-from typing import Any, NoReturn, cast
+from typing import Any
-import httpx
-import respx
+import httpx2
import pytest
-from respx.models import Call
import openai._base_client as base_client
import openai.auth._workload as workload
@@ -21,8 +19,6 @@
)
from openai.auth import WorkloadIdentity
-httpx2 = pytest.importorskip("httpx2")
-
def workload_identity(get_token: Any = lambda: "subject-token") -> WorkloadIdentity:
return {
@@ -36,10 +32,6 @@ def exchange_payload(access_token: str) -> dict[str, object]:
return {"access_token": access_token, "expires_in": 3600}
-def forbidden_httpx_send(*_args: Any, **_kwargs: Any) -> NoReturn:
- pytest.fail("HTTPX unexpectedly sent a request")
-
-
def test_sync_httpx2_workload_exchange_is_native_and_cached(monkeypatch: pytest.MonkeyPatch) -> None:
exchange_requests: list[Any] = []
api_requests: list[Any] = []
@@ -63,7 +55,6 @@ def api_handler(request: Any) -> Any:
return httpx2.Response(200, request=request, json={"object": "list", "data": []})
monkeypatch.setattr(workload, "DefaultHttpx2Client", exchange_client)
- monkeypatch.setattr(httpx.Client, "send", forbidden_httpx_send)
with OpenAI(
workload_identity=workload_identity(get_token),
@@ -111,8 +102,6 @@ async def api_handler(request: Any) -> Any:
return httpx2.Response(status_code, request=request, json={"object": "list", "data": []})
monkeypatch.setattr(workload, "DefaultHttpx2Client", exchange_client)
- monkeypatch.setattr(httpx.Client, "send", forbidden_httpx_send)
- monkeypatch.setattr(httpx.AsyncClient, "send", forbidden_httpx_send)
async with AsyncOpenAI(
workload_identity=workload_identity(),
@@ -150,7 +139,6 @@ def default_client(**kwargs: Any) -> Any:
monkeypatch.setattr(base_client, "SyncHttpxClientWrapper", default_client)
monkeypatch.setattr(workload, "DefaultHttpx2Client", exchange_client)
- monkeypatch.setattr(httpx.Client, "send", forbidden_httpx_send)
with OpenAI(
workload_identity=workload_identity(),
@@ -188,8 +176,6 @@ def default_client(**kwargs: Any) -> Any:
monkeypatch.setattr(base_client, "AsyncHttpxClientWrapper", default_client)
monkeypatch.setattr(workload, "DefaultHttpx2Client", exchange_client)
- monkeypatch.setattr(httpx.Client, "send", forbidden_httpx_send)
- monkeypatch.setattr(httpx.AsyncClient, "send", forbidden_httpx_send)
async with AsyncOpenAI(
workload_identity=workload_identity(),
@@ -273,33 +259,3 @@ def api_handler(request: Any) -> Any:
client.models.list()
assert type(exc_info.value.__cause__).__module__ == "httpx2"
-
-
-def test_httpx_workload_exchange_stays_httpx_when_httpx2_is_installed(monkeypatch: pytest.MonkeyPatch) -> None:
- api_requests: list[httpx.Request] = []
-
- def forbidden_httpx2(**_kwargs: Any) -> Any:
- pytest.fail("HTTPX2 unexpectedly created a workload exchange client")
-
- def api_handler(request: httpx.Request) -> httpx.Response:
- api_requests.append(request)
- return httpx.Response(200, request=request, json={"object": "list", "data": []})
-
- monkeypatch.setattr(workload, "DefaultHttpx2Client", forbidden_httpx2)
-
- with respx.mock(assert_all_mocked=False) as router:
- exchange = router.post("https://auth.openai.com/oauth/token").mock(
- return_value=httpx.Response(200, json=exchange_payload("access-token"))
- )
- with OpenAI(
- workload_identity=workload_identity(),
- base_url="https://api.example.test/v1",
- http_client=httpx.Client(transport=httpx.MockTransport(api_handler), trust_env=False),
- max_retries=0,
- ) as client:
- assert client.models.list().object == "list"
-
- assert exchange.call_count == 1
- assert len(api_requests) == 1
- assert isinstance(cast(Call, exchange.calls[0]).request, httpx.Request)
- assert isinstance(api_requests[0], httpx.Request)
diff --git a/tests/test_httpx_compat.py b/tests/test_httpx_compat.py
new file mode 100644
index 0000000000..cb00e9b00f
--- /dev/null
+++ b/tests/test_httpx_compat.py
@@ -0,0 +1,88 @@
+from __future__ import annotations
+
+import os
+import asyncio
+import importlib
+import threading
+from typing import Any, cast
+from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
+from typing_extensions import override
+
+import pytest
+
+from openai import OpenAI, AsyncOpenAI
+
+pytestmark = pytest.mark.skipif(
+ os.environ.get("OPENAI_TEST_LEGACY_HTTPX") != "1", reason="requires the dedicated legacy HTTPX compatibility lane"
+)
+
+
+def test_external_legacy_httpx_client_is_supported() -> None:
+ httpx = cast(Any, importlib.import_module("httpx"))
+
+ def handler(request: Any) -> Any:
+ return httpx.Response(200, request=request, json={"object": "list", "data": []})
+
+ with OpenAI(
+ api_key="test",
+ base_url="https://example.test/v1",
+ http_client=httpx.Client(transport=httpx.MockTransport(handler), trust_env=False),
+ max_retries=0,
+ ) as client:
+ assert isinstance(client._client, httpx.Client)
+ response = client.models.list()
+
+ assert response.data is not None
+
+
+async def test_external_legacy_async_httpx_client_is_supported() -> None:
+ httpx = cast(Any, importlib.import_module("httpx"))
+
+ async def handler(request: Any) -> Any:
+ return httpx.Response(200, request=request, json={"object": "list", "data": []})
+
+ async with AsyncOpenAI(
+ api_key="test",
+ base_url="https://example.test/v1",
+ http_client=httpx.AsyncClient(transport=httpx.MockTransport(handler), trust_env=False),
+ max_retries=0,
+ ) as client:
+ assert isinstance(client._client, httpx.AsyncClient)
+ response = await client.models.list()
+
+ assert response.data is not None
+
+
+async def test_external_legacy_aiohttp_client_is_supported() -> None:
+ httpx = cast(Any, importlib.import_module("httpx"))
+ HttpxAiohttpClient = cast(Any, importlib.import_module("httpx_aiohttp")).HttpxAiohttpClient
+
+ class ModelsHandler(BaseHTTPRequestHandler):
+ def do_GET(self) -> None:
+ self.send_response(200)
+ self.send_header("Content-Type", "application/json")
+ self.end_headers()
+ self.wfile.write(b'{"object":"list","data":[]}')
+
+ @override
+ def log_message(self, format: str, *_args: object) -> None: # noqa: A002
+ return None
+
+ server = ThreadingHTTPServer(("127.0.0.1", 0), ModelsHandler)
+ thread = threading.Thread(target=server.serve_forever)
+ thread.start()
+ try:
+ async with AsyncOpenAI(
+ api_key="test",
+ base_url=f"http://127.0.0.1:{server.server_port}/v1",
+ http_client=HttpxAiohttpClient(),
+ max_retries=0,
+ ) as client:
+ assert isinstance(client._client, httpx.AsyncClient)
+ response = await client.models.list()
+ finally:
+ await asyncio.to_thread(server.shutdown)
+ thread.join()
+ server.server_close()
+
+ assert response.data is not None
diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py
index 9da1a80659..236c6c259b 100644
--- a/tests/test_legacy_response.py
+++ b/tests/test_legacy_response.py
@@ -2,7 +2,7 @@
from typing import Any, Union, cast
from typing_extensions import Annotated
-import httpx
+import httpx2
import pytest
import pydantic
@@ -19,7 +19,7 @@ class PydanticModel(pydantic.BaseModel): ...
def test_response_parse_mismatched_basemodel(client: OpenAI) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(200, content=b"foo"),
+ raw=httpx2.Response(200, content=b"foo"),
client=client,
stream=False,
stream_cls=None,
@@ -47,7 +47,7 @@ def test_response_parse_mismatched_basemodel(client: OpenAI) -> None:
)
def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(200, content=content),
+ raw=httpx2.Response(200, content=content),
client=client,
stream=False,
stream_cls=None,
@@ -61,7 +61,7 @@ def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> No
def test_response_parse_custom_stream(client: OpenAI) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(200, content=b"foo"),
+ raw=httpx2.Response(200, content=b"foo"),
client=client,
stream=True,
stream_cls=None,
@@ -80,7 +80,7 @@ class CustomModel(BaseModel):
def test_response_parse_custom_model(client: OpenAI) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
+ raw=httpx2.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
client=client,
stream=False,
stream_cls=None,
@@ -95,7 +95,7 @@ def test_response_parse_custom_model(client: OpenAI) -> None:
def test_response_basemodel_request_id(client: OpenAI) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(
+ raw=httpx2.Response(
200,
headers={"x-request-id": "my-req-id"},
content=json.dumps({"foo": "hello!", "bar": 2}),
@@ -118,7 +118,7 @@ def test_response_basemodel_request_id(client: OpenAI) -> None:
def test_response_parse_annotated_type(client: OpenAI) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
+ raw=httpx2.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
client=client,
stream=False,
stream_cls=None,
@@ -140,7 +140,7 @@ class OtherModel(pydantic.BaseModel):
@pytest.mark.parametrize("client", [False], indirect=True) # loose validation
def test_response_parse_expect_model_union_non_json_content(client: OpenAI) -> None:
response = LegacyAPIResponse(
- raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
+ raw=httpx2.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
client=client,
stream=False,
stream_cls=None,
diff --git a/tests/test_module_client.py b/tests/test_module_client.py
index cb509d3d19..ff099d5056 100644
--- a/tests/test_module_client.py
+++ b/tests/test_module_client.py
@@ -4,9 +4,9 @@
import os as _os
-import httpx
+import httpx2
import pytest
-from httpx import URL
+from httpx2 import URL
import openai
from openai import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES
@@ -94,7 +94,7 @@ def test_http_client_option() -> None:
original_http_client = openai.completions._client._client
assert original_http_client is not None
- new_client = httpx.Client()
+ new_client = httpx2.Client()
openai.http_client = new_client
assert openai.completions._client._client is new_client
@@ -254,15 +254,15 @@ def test_bedrock_module_api_key_overrides_cached_env_token_after_load() -> None:
def test_bedrock_module_api_key_switches_cached_aws_client_to_bearer() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with fresh_env():
openai.api_type = "amazon-bedrock"
- openai.http_client = httpx.Client(transport=httpx.MockTransport(handler), trust_env=False)
+ openai.http_client = httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False)
_os.environ["AWS_ACCESS_KEY_ID"] = "access key"
_os.environ["AWS_SECRET_ACCESS_KEY"] = "secret key"
_os.environ["AWS_REGION"] = "us-west-2"
@@ -272,7 +272,7 @@ def handler(request: httpx.Request) -> httpx.Response:
assert client._uses_aws_auth()
openai.api_key = "new Bedrock token"
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert requests[0].headers["Authorization"] == "Bearer new Bedrock token"
@@ -290,7 +290,7 @@ def test_bedrock_api_type_uses_token_provider_without_mutating_module_api_key()
def test_bedrock_module_api_key_overrides_cached_token_provider() -> None:
- requests: list[httpx.Request] = []
+ requests: list[httpx2.Request] = []
provider_calls = 0
def token_provider() -> str:
@@ -298,21 +298,21 @@ def token_provider() -> str:
provider_calls += 1
raise AssertionError("the replaced token provider must not be called")
- def handler(request: httpx.Request) -> httpx.Response:
+ def handler(request: httpx2.Request) -> httpx2.Response:
requests.append(request)
- return httpx.Response(200, request=request, json={})
+ return httpx2.Response(200, request=request, json={})
with fresh_env():
openai.api_type = "amazon-bedrock"
openai.bedrock_token_provider = token_provider
- openai.http_client = httpx.Client(transport=httpx.MockTransport(handler), trust_env=False)
+ openai.http_client = httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False)
_os.environ["AWS_REGION"] = "us-west-2"
client = openai.responses._client
assert isinstance(client, BedrockOpenAI)
openai.api_key = "new Bedrock token"
- client.get("/models", cast_to=httpx.Response)
+ client.get("/models", cast_to=httpx2.Response)
assert provider_calls == 0
assert requests[0].headers["Authorization"] == "Bearer new Bedrock token"
diff --git a/tests/test_response.py b/tests/test_response.py
index 43f24c150d..fba775e873 100644
--- a/tests/test_response.py
+++ b/tests/test_response.py
@@ -2,7 +2,7 @@
from typing import Any, List, Union, cast
from typing_extensions import Annotated
-import httpx
+import httpx2
import pytest
import pydantic
@@ -27,7 +27,7 @@ class ConcreteBaseAPIResponse(APIResponse[bytes]): ...
class ConcreteAPIResponse(APIResponse[List[str]]): ...
-class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): ...
+class ConcreteAsyncAPIResponse(APIResponse[httpx2.Response]): ...
def test_extract_response_type_direct_classes() -> None:
@@ -47,7 +47,7 @@ def test_extract_response_type_direct_class_missing_type_arg() -> None:
def test_extract_response_type_concrete_subclasses() -> None:
assert extract_response_type(ConcreteBaseAPIResponse) == bytes
assert extract_response_type(ConcreteAPIResponse) == List[str]
- assert extract_response_type(ConcreteAsyncAPIResponse) == httpx.Response
+ assert extract_response_type(ConcreteAsyncAPIResponse) == httpx2.Response
def test_extract_response_type_binary_response() -> None:
@@ -60,7 +60,7 @@ class PydanticModel(pydantic.BaseModel): ...
def test_response_parse_mismatched_basemodel(client: OpenAI) -> None:
response = APIResponse(
- raw=httpx.Response(200, content=b"foo"),
+ raw=httpx2.Response(200, content=b"foo"),
client=client,
stream=False,
stream_cls=None,
@@ -78,7 +78,7 @@ def test_response_parse_mismatched_basemodel(client: OpenAI) -> None:
@pytest.mark.asyncio
async def test_async_response_parse_mismatched_basemodel(async_client: AsyncOpenAI) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(200, content=b"foo"),
+ raw=httpx2.Response(200, content=b"foo"),
client=async_client,
stream=False,
stream_cls=None,
@@ -95,7 +95,7 @@ async def test_async_response_parse_mismatched_basemodel(async_client: AsyncOpen
def test_response_parse_custom_stream(client: OpenAI) -> None:
response = APIResponse(
- raw=httpx.Response(200, content=b"foo"),
+ raw=httpx2.Response(200, content=b"foo"),
client=client,
stream=True,
stream_cls=None,
@@ -110,7 +110,7 @@ def test_response_parse_custom_stream(client: OpenAI) -> None:
@pytest.mark.asyncio
async def test_async_response_parse_custom_stream(async_client: AsyncOpenAI) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(200, content=b"foo"),
+ raw=httpx2.Response(200, content=b"foo"),
client=async_client,
stream=True,
stream_cls=None,
@@ -129,7 +129,7 @@ class CustomModel(BaseModel):
def test_response_parse_custom_model(client: OpenAI) -> None:
response = APIResponse(
- raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
+ raw=httpx2.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
client=client,
stream=False,
stream_cls=None,
@@ -145,7 +145,7 @@ def test_response_parse_custom_model(client: OpenAI) -> None:
@pytest.mark.asyncio
async def test_async_response_parse_custom_model(async_client: AsyncOpenAI) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
+ raw=httpx2.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
client=async_client,
stream=False,
stream_cls=None,
@@ -160,7 +160,7 @@ async def test_async_response_parse_custom_model(async_client: AsyncOpenAI) -> N
def test_response_basemodel_request_id(client: OpenAI) -> None:
response = APIResponse(
- raw=httpx.Response(
+ raw=httpx2.Response(
200,
headers={"x-request-id": "my-req-id"},
content=json.dumps({"foo": "hello!", "bar": 2}),
@@ -184,7 +184,7 @@ def test_response_basemodel_request_id(client: OpenAI) -> None:
@pytest.mark.asyncio
async def test_async_response_basemodel_request_id(client: OpenAI) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(
+ raw=httpx2.Response(
200,
headers={"x-request-id": "my-req-id"},
content=json.dumps({"foo": "hello!", "bar": 2}),
@@ -205,7 +205,7 @@ async def test_async_response_basemodel_request_id(client: OpenAI) -> None:
def test_response_parse_annotated_type(client: OpenAI) -> None:
response = APIResponse(
- raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
+ raw=httpx2.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
client=client,
stream=False,
stream_cls=None,
@@ -222,7 +222,7 @@ def test_response_parse_annotated_type(client: OpenAI) -> None:
async def test_async_response_parse_annotated_type(async_client: AsyncOpenAI) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
+ raw=httpx2.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})),
client=async_client,
stream=False,
stream_cls=None,
@@ -250,7 +250,7 @@ async def test_async_response_parse_annotated_type(async_client: AsyncOpenAI) ->
)
def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> None:
response = APIResponse(
- raw=httpx.Response(200, content=content),
+ raw=httpx2.Response(200, content=content),
client=client,
stream=False,
stream_cls=None,
@@ -275,7 +275,7 @@ def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> No
)
async def test_async_response_parse_bool(client: AsyncOpenAI, content: str, expected: bool) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(200, content=content),
+ raw=httpx2.Response(200, content=content),
client=client,
stream=False,
stream_cls=None,
@@ -294,7 +294,7 @@ class OtherModel(BaseModel):
@pytest.mark.parametrize("client", [False], indirect=True) # loose validation
def test_response_parse_expect_model_union_non_json_content(client: OpenAI) -> None:
response = APIResponse(
- raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
+ raw=httpx2.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
client=client,
stream=False,
stream_cls=None,
@@ -311,7 +311,7 @@ def test_response_parse_expect_model_union_non_json_content(client: OpenAI) -> N
@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation
async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncOpenAI) -> None:
response = AsyncAPIResponse(
- raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
+ raw=httpx2.Response(200, content=b"foo", headers={"Content-Type": "application/text"}),
client=async_client,
stream=False,
stream_cls=None,
diff --git a/tests/test_streaming.py b/tests/test_streaming.py
index 04f8e51abd..ae6c0590f7 100644
--- a/tests/test_streaming.py
+++ b/tests/test_streaming.py
@@ -2,7 +2,7 @@
from typing import Iterator, AsyncIterator
-import httpx
+import httpx2
import pytest
from openai import OpenAI, AsyncOpenAI
@@ -241,8 +241,8 @@ def make_event_iterator(
async_client: AsyncOpenAI,
) -> Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]:
if sync:
- return Stream(cast_to=object, client=client, response=httpx.Response(200, content=content))._iter_events()
+ return Stream(cast_to=object, client=client, response=httpx2.Response(200, content=content))._iter_events()
return AsyncStream(
- cast_to=object, client=async_client, response=httpx.Response(200, content=to_aiter(content))
+ cast_to=object, client=async_client, response=httpx2.Response(200, content=to_aiter(content))
)._iter_events()
diff --git a/tests/test_utils/test_logging.py b/tests/test_utils/test_logging.py
index cc018012e2..b7c53f5cae 100644
--- a/tests/test_utils/test_logging.py
+++ b/tests/test_utils/test_logging.py
@@ -4,6 +4,7 @@
import pytest
from openai._utils import SensitiveHeadersFilter
+from openai._utils._logs import setup_logging
@pytest.fixture
@@ -98,3 +99,17 @@ def test_standard_debug_msg(logger_with_filter: logging.Logger, caplog: pytest.L
with caplog.at_level(logging.DEBUG):
logger_with_filter.debug("Sending HTTP Request: %s %s", "POST", "chat/completions")
assert caplog.messages[0] == "Sending HTTP Request: POST chat/completions"
+
+
+@pytest.mark.parametrize(("setting", "level"), [("debug", logging.DEBUG), ("info", logging.INFO)])
+def test_httpx2_logger_follows_sdk_log_level(setting: str, level: int, monkeypatch: pytest.MonkeyPatch) -> None:
+ sdk_logger = logging.getLogger("openai")
+ transport_logger = logging.getLogger("httpx2")
+ monkeypatch.setattr(sdk_logger, "level", sdk_logger.level)
+ monkeypatch.setattr(transport_logger, "level", transport_logger.level)
+ monkeypatch.setenv("OPENAI_LOG", setting)
+
+ setup_logging()
+
+ assert sdk_logger.level == level
+ assert transport_logger.level == level
diff --git a/uv.lock b/uv.lock
index 903d4c4093..ab8356f146 100644
--- a/uv.lock
+++ b/uv.lock
@@ -225,15 +225,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0e/f2/4bd8f2f419088feb3ce55f0ca91040ff902f402edfd197450b20a2e1d533/botocore-1.43.46-py3-none-any.whl", hash = "sha256:cb673891e623ae6e6a1bf24d94ef169504f3eb02584adb5d5bee2f6aae819b60", size = 15380350, upload-time = "2026-07-10T19:31:57.616Z" },
]
-[[package]]
-name = "certifi"
-version = "2026.6.17"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" },
-]
-
[[package]]
name = "cffi"
version = "2.0.0"
@@ -476,19 +467,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
]
-[[package]]
-name = "httpcore"
-version = "1.0.9"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "certifi" },
- { name = "h11" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
-]
-
[[package]]
name = "httpcore2"
version = "2.7.0"
@@ -502,34 +480,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6f/6c/62e2e279e63fc4f7a5ee841ef13175a8bbc613f258e9dcc186e9de803a42/httpcore2-2.7.0-py3-none-any.whl", hash = "sha256:1452f589fe23f55b44546cd884294c41a29330af902bc0b71a761fd52d18f92b", size = 81506, upload-time = "2026-07-14T20:39:58.053Z" },
]
-[[package]]
-name = "httpx"
-version = "0.28.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "anyio" },
- { name = "certifi" },
- { name = "httpcore" },
- { name = "idna" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
-]
-
-[[package]]
-name = "httpx-aiohttp"
-version = "0.1.12"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "aiohttp" },
- { name = "httpx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/63/2c/b894861cecf030fb45675ea24aa55b5722e97c602a163d872fca66c5a6d8/httpx_aiohttp-0.1.12.tar.gz", hash = "sha256:81feec51fd82c0ecfa0e9aaf1b1a6c2591260d5e2bcbeb7eb0277a78e610df2c", size = 275945, upload-time = "2025-12-12T10:12:15.283Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/16/8d/85c9701e9af72ca132a1783e2a54364a90c6da832304416a30fc11196ab2/httpx_aiohttp-0.1.12-py3-none-any.whl", hash = "sha256:5b0eac39a7f360fa7867a60bcb46bb1024eada9c01cbfecdb54dc1edb3fb7141", size = 6367, upload-time = "2025-12-12T10:12:14.018Z" },
-]
-
[[package]]
name = "httpx2"
version = "2.7.0"
@@ -959,12 +909,12 @@ wheels = [
[[package]]
name = "openai"
-version = "2.54.0" # x-release-please-version
+version = "3.0.0" # x-release-please-version
source = { editable = "." }
dependencies = [
{ name = "anyio" },
{ name = "distro" },
- { name = "httpx" },
+ { name = "httpx2" },
{ name = "jiter" },
{ name = "pydantic" },
{ name = "sniffio" },
@@ -975,7 +925,6 @@ dependencies = [
[package.optional-dependencies]
aiohttp = [
{ name = "aiohttp" },
- { name = "httpx-aiohttp" },
]
bedrock = [
{ name = "botocore" },
@@ -988,11 +937,6 @@ datalib = [
{ name = "pandas-stubs", version = "2.3.3.260113", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "pandas-stubs", version = "3.0.3.260530", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
]
-httpx2 = [
- { name = "anyio" },
- { name = "httpx" },
- { name = "httpx2" },
-]
realtime = [
{ name = "websockets" },
]
@@ -1005,14 +949,10 @@ voice-helpers = [
[package.metadata]
requires-dist = [
{ name = "aiohttp", marker = "extra == 'aiohttp'", specifier = ">=3.14.1" },
- { name = "anyio", specifier = ">=3.5.0,<5" },
- { name = "anyio", marker = "extra == 'httpx2'", specifier = ">=4.10.0,<5" },
+ { name = "anyio", specifier = ">=4.10.0,<5" },
{ name = "botocore", marker = "extra == 'bedrock'", specifier = ">=1.40.0,<2" },
{ name = "distro", specifier = ">=1.7.0,<2" },
- { name = "httpx", specifier = ">=0.23.0,<1" },
- { name = "httpx", marker = "extra == 'httpx2'", specifier = ">=0.25.1,<1" },
- { name = "httpx-aiohttp", marker = "extra == 'aiohttp'", specifier = ">=0.1.9" },
- { name = "httpx2", marker = "extra == 'httpx2'", specifier = ">=2.7.0,<3" },
+ { name = "httpx2", specifier = ">=2.7.0,<3" },
{ name = "jiter", specifier = ">=0.10.0,<1" },
{ name = "numpy", marker = "extra == 'datalib'", specifier = ">=1" },
{ name = "numpy", marker = "extra == 'voice-helpers'", specifier = ">=2.0.2" },
@@ -1025,7 +965,7 @@ requires-dist = [
{ name = "typing-extensions", specifier = ">=4.14,<5" },
{ name = "websockets", marker = "extra == 'realtime'", specifier = ">=13,<16" },
]
-provides-extras = ["aiohttp", "httpx2", "realtime", "datalib", "voice-helpers", "bedrock"]
+provides-extras = ["aiohttp", "realtime", "datalib", "voice-helpers", "bedrock"]
[[package]]
name = "pandas"