Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ Functionality between the synchronous and asynchronous clients is otherwise iden

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.

You can enable this by installing `aiohttp`:

```sh
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ Homepage = "https://github.com/openai/openai-python"
Repository = "https://github.com/openai/openai-python"

[project.optional-dependencies]
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"]
aiohttp = [
"aiohttp>=3.14.1; python_version >= '3.10'",
"httpx_aiohttp>=0.1.9; python_version >= '3.10'",
]
realtime = ["websockets >= 13, < 16"]
datalib = ["numpy >= 1", "pandas >= 1.2.3", "pandas-stubs >= 1.1.0.11"]
voice_helpers = ["sounddevice>=0.5.1", "numpy>=2.0.2"]
Expand Down
27 changes: 0 additions & 27 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@
# universal: false

-e file:.
aiohappyeyeballs==2.6.1
# via aiohttp
aiohttp==3.13.3
# via httpx-aiohttp
# via openai
aiosignal==1.4.0
# via aiohttp
annotated-types==0.7.0
# via pydantic
anyio==4.12.1
Expand All @@ -26,10 +19,7 @@ argcomplete==3.6.3
# via nox
asttokens==3.0.1
# via inline-snapshot
async-timeout==5.0.1
# via aiohttp
attrs==25.4.0
# via aiohttp
# via jsonschema
# via nox
# via outcome
Expand Down Expand Up @@ -76,28 +66,21 @@ executing==2.2.1
# via inline-snapshot
filelock==3.19.1
# via virtualenv
frozenlist==1.8.0
# via aiohttp
# via aiosignal
griffe==1.14.0
h11==0.16.0
# via httpcore
httpcore==1.0.9
# via httpx
httpx==0.28.1
# via httpx-aiohttp
# via openai
# via respx
httpx-aiohttp==0.1.12
# via openai
humanize==4.13.0
# via nox
idna==3.11
# via anyio
# via httpx
# via requests
# via trio
# via yarl
importlib-metadata==8.7.1
iniconfig==2.1.0
# via pytest
Expand All @@ -118,9 +101,6 @@ msal==1.34.0
# via msal-extensions
msal-extensions==1.3.1
# via azure-identity
multidict==6.7.0
# via aiohttp
# via yarl
mypy==1.17.0
mypy-extensions==1.1.0
# via mypy
Expand Down Expand Up @@ -148,9 +128,6 @@ platformdirs==4.4.0
# via virtualenv
pluggy==1.6.0
# via pytest
propcache==0.4.1
# via aiohttp
# via yarl
pycparser==2.23
# via cffi
pydantic==2.12.5
Expand Down Expand Up @@ -216,13 +193,11 @@ types-tqdm==4.67.0.20250809
types-urllib3==1.26.25.14
# via types-requests
typing-extensions==4.15.0
# via aiosignal
# via anyio
# via azure-core
# via azure-identity
# via cryptography
# via exceptiongroup
# via multidict
# via mypy
# via openai
# via pydantic
Expand All @@ -243,7 +218,5 @@ virtualenv==20.35.4
# via nox
websockets==15.0.1
# via openai
yarl==1.22.0
# via aiohttp
zipp==3.23.0
# via importlib-metadata
28 changes: 0 additions & 28 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,11 @@
# universal: false

-e file:.
aiohappyeyeballs==2.6.1
# via aiohttp
aiohttp==3.13.3
# 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 openai
async-timeout==5.0.1
# via aiohttp
attrs==25.4.0
# via aiohttp
botocore==1.42.97
# via openai
certifi==2026.1.4
Expand All @@ -37,29 +26,19 @@ distro==1.9.0
# via openai
exceptiongroup==1.3.1
# via anyio
frozenlist==1.8.0
# via aiohttp
# via aiosignal
h11==0.16.0
# via httpcore
httpcore==1.0.9
# via httpx
httpx==0.28.1
# via httpx-aiohttp
# via openai
httpx-aiohttp==0.1.12
# via openai
idna==3.11
# via anyio
# via httpx
# via yarl
jiter==0.12.0
# via openai
jmespath==1.1.0
# via botocore
multidict==6.7.0
# via aiohttp
# via yarl
numpy==2.0.2
# via openai
# via pandas
Expand All @@ -68,9 +47,6 @@ pandas==2.3.3
# via openai
pandas-stubs==2.2.2.240807
# via openai
propcache==0.4.1
# via aiohttp
# via yarl
pycparser==2.23
# via cffi
pydantic==2.12.5
Expand All @@ -93,10 +69,8 @@ tqdm==4.67.1
types-pytz==2025.2.0.20251108
# via pandas-stubs
typing-extensions==4.15.0
# via aiosignal
# via anyio
# via exceptiongroup
# via multidict
# via openai
# via pydantic
# via pydantic-core
Expand All @@ -109,5 +83,3 @@ urllib3==1.26.20
# via botocore
websockets==15.0.1
# via openai
yarl==1.22.0
# via aiohttp
29 changes: 18 additions & 11 deletions src/openai/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1426,22 +1426,29 @@ def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)


try:
import httpx_aiohttp
except ImportError:

if sys.version_info < (3, 10):
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")
raise RuntimeError("The aiohttp client requires Python 3.10 or later")
else:
try:
import httpx_aiohttp
except ImportError:

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:

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 _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)

super().__init__(**kwargs)
super().__init__(**kwargs)


if TYPE_CHECKING:
Expand Down
4 changes: 4 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import os
import sys
import logging
from typing import TYPE_CHECKING, Iterator, AsyncIterator

Expand Down Expand Up @@ -77,6 +78,9 @@ async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOpenAI]:

http_client_type = param.get("http_client", "httpx")
if http_client_type == "aiohttp":
if sys.version_info < (3, 10):
pytest.skip("the aiohttp client requires Python 3.10 or later")
Comment on lines +81 to +82

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exercise aiohttp on a supported CI interpreter

The sole test job in .github/workflows/ci.yml bootstraps the repository's .python-version (3.9.18), so this condition now skips every {"http_client": "aiohttp"} test variant in CI. Consequently, neither DefaultAioHttpClient nor the newly required aiohttp 3.14.1/httpx-aiohttp combination is exercised by the automated suite; add a Python 3.10+ test job, or otherwise run these variants on a supported interpreter.

Useful? React with 👍 / 👎.


http_client = DefaultAioHttpClient()
else:
raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict")
Expand Down
Loading
Loading