From 13b9605063a1246d409b1e68ef94e886095e16a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:51:25 +0000 Subject: [PATCH 1/4] chore(readme): update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b83cb47c74..80077038f9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OpenAI Python API library -[![PyPI version](https://img.shields.io/pypi/v/openai.svg)](https://pypi.org/project/openai/) +[![PyPI version]()](https://pypi.org/project/openai/) The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From 0bef1d02cf7c188f114f481f0d87e55f1e26b7dd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:10:09 +0000 Subject: [PATCH 2/4] fix(tests): fix: tests which call HTTP endpoints directly with the example parameters --- tests/test_client.py | 129 ++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 89 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 1026b78921..3d08a0a601 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,9 +23,7 @@ from openai import OpenAI, AsyncOpenAI, APIResponseValidationError from openai._types import Omit -from openai._utils import maybe_transform from openai._models import BaseModel, FinalRequestOptions -from openai._constants import RAW_RESPONSE_HEADER from openai._streaming import Stream, AsyncStream from openai._exceptions import OpenAIError, APIStatusError, APITimeoutError, APIResponseValidationError from openai._base_client import ( @@ -36,7 +34,6 @@ DefaultAsyncHttpxClient, make_request_options, ) -from openai.types.chat.completion_create_params import CompletionCreateParamsNonStreaming from .utils import update_env @@ -725,60 +722,37 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @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) -> None: + 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")) with pytest.raises(APITimeoutError): - self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__enter__() assert _get_open_connections(self.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) -> None: + 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)) with pytest.raises(APIStatusError): - self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1647,60 +1621,37 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte @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) -> None: + 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")) with pytest.raises(APITimeoutError): - await self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + await async_client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__aenter__() assert _get_open_connections(self.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) -> None: + 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)) with pytest.raises(APIStatusError): - await self.client.post( - "/chat/completions", - body=cast( - object, - maybe_transform( - dict( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ), - CompletionCreateParamsNonStreaming, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + await async_client.chat.completions.with_streaming_response.create( + messages=[ + { + "content": "string", + "role": "developer", + } + ], + model="gpt-4o", + ).__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) From c62e99070389d026b77d048184fe0b05af00ce72 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:01:32 +0000 Subject: [PATCH 3/4] feat(client): add support for aiohttp --- README.md | 39 +++++++++++++++++ pyproject.toml | 1 + requirements-dev.lock | 26 +++++++++++ requirements.lock | 27 ++++++++++++ src/openai/__init__.py | 3 +- src/openai/_base_client.py | 22 ++++++++++ tests/api_resources/audio/test_speech.py | 4 +- .../audio/test_transcriptions.py | 4 +- .../api_resources/audio/test_translations.py | 4 +- .../beta/realtime/test_sessions.py | 4 +- .../realtime/test_transcription_sessions.py | 4 +- tests/api_resources/beta/test_assistants.py | 4 +- tests/api_resources/beta/test_realtime.py | 4 +- tests/api_resources/beta/test_threads.py | 4 +- .../beta/threads/runs/test_steps.py | 4 +- .../beta/threads/test_messages.py | 4 +- tests/api_resources/beta/threads/test_runs.py | 4 +- .../chat/completions/test_messages.py | 4 +- tests/api_resources/chat/test_completions.py | 4 +- .../containers/files/test_content.py | 4 +- tests/api_resources/containers/test_files.py | 4 +- .../evals/runs/test_output_items.py | 4 +- tests/api_resources/evals/test_runs.py | 4 +- .../fine_tuning/alpha/test_graders.py | 4 +- .../checkpoints/test_permissions.py | 4 +- .../fine_tuning/jobs/test_checkpoints.py | 4 +- tests/api_resources/fine_tuning/test_jobs.py | 4 +- .../responses/test_input_items.py | 4 +- tests/api_resources/test_batches.py | 4 +- tests/api_resources/test_completions.py | 4 +- tests/api_resources/test_containers.py | 4 +- tests/api_resources/test_embeddings.py | 4 +- tests/api_resources/test_evals.py | 4 +- tests/api_resources/test_files.py | 4 +- tests/api_resources/test_images.py | 4 +- tests/api_resources/test_models.py | 4 +- tests/api_resources/test_moderations.py | 4 +- tests/api_resources/test_responses.py | 4 +- tests/api_resources/test_uploads.py | 4 +- tests/api_resources/test_vector_stores.py | 4 +- tests/api_resources/uploads/test_parts.py | 4 +- .../vector_stores/test_file_batches.py | 4 +- .../api_resources/vector_stores/test_files.py | 4 +- tests/conftest.py | 43 ++++++++++++++++--- 44 files changed, 265 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 80077038f9..4861e4aaab 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,45 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### 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. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +pip install openai[aiohttp] +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import os +import asyncio +from openai import DefaultAioHttpClient +from openai import AsyncOpenAI + + +async def main() -> None: + async with AsyncOpenAI( + api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted + http_client=DefaultAioHttpClient(), + ) as client: + chat_completion = await client.chat.completions.create( + messages=[ + { + "role": "user", + "content": "Say this is a test", + } + ], + model="gpt-4o", + ) + + +asyncio.run(main()) +``` + ## Streaming responses We provide support for streaming responses using Server Side Events (SSE). diff --git a/pyproject.toml b/pyproject.toml index 963a8cb1aa..b531a822dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,7 @@ Repository = "https://github.com/openai/openai-python" openai = "openai.cli:main" [project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] 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"] diff --git a/requirements-dev.lock b/requirements-dev.lock index 787c15be6a..138fd3b4f6 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,6 +10,13 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.13 + # via httpx-aiohttp + # via openai +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.1.0 @@ -19,7 +26,10 @@ argcomplete==3.1.2 # via nox asttokens==2.4.1 # via inline-snapshot +async-timeout==5.0.1 + # via aiohttp attrs==24.2.0 + # via aiohttp # via outcome # via trio azure-core==1.31.0 @@ -60,18 +70,25 @@ executing==2.1.0 # via inline-snapshot filelock==3.12.4 # via virtualenv +frozenlist==1.7.0 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp # via openai # via respx +httpx-aiohttp==0.1.6 + # via openai idna==3.4 # via anyio # via httpx # via requests # via trio + # via yarl importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -87,6 +104,9 @@ msal==1.31.0 # via msal-extensions msal-extensions==1.2.0 # via azure-identity +multidict==6.5.0 + # via aiohttp + # via yarl mypy==1.14.1 mypy-extensions==1.0.0 # via black @@ -118,6 +138,9 @@ pluggy==1.5.0 # via pytest portalocker==2.10.1 # via msal-extensions +propcache==0.3.2 + # via aiohttp + # via yarl pycparser==2.22 # via cffi pydantic==2.10.3 @@ -181,6 +204,7 @@ typing-extensions==4.12.2 # via azure-core # via azure-identity # via black + # via multidict # via mypy # via openai # via pydantic @@ -194,5 +218,7 @@ virtualenv==20.24.5 # via nox websockets==15.0.1 # via openai +yarl==1.20.1 + # via aiohttp zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 467abc6e90..84cb9276d8 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,11 +10,22 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.13 + # via httpx-aiohttp + # via openai +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.1.0 # via httpx # via openai +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -24,17 +35,27 @@ distro==1.8.0 # via openai exceptiongroup==1.2.2 # via anyio +frozenlist==1.7.0 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp + # via openai +httpx-aiohttp==0.1.6 # via openai idna==3.4 # via anyio # via httpx + # via yarl jiter==0.6.1 # via openai +multidict==6.5.0 + # via aiohttp + # via yarl numpy==2.0.2 # via openai # via pandas @@ -43,6 +64,9 @@ pandas==2.2.3 # via openai pandas-stubs==2.2.2.240807 # via openai +propcache==0.3.2 + # via aiohttp + # via yarl pycparser==2.22 # via cffi pydantic==2.10.3 @@ -65,6 +89,7 @@ tqdm==4.66.5 types-pytz==2024.2.0.20241003 # via pandas-stubs typing-extensions==4.12.2 + # via multidict # via openai # via pydantic # via pydantic-core @@ -72,3 +97,5 @@ tzdata==2024.1 # via pandas websockets==15.0.1 # via openai +yarl==1.20.1 + # via aiohttp diff --git a/src/openai/__init__.py b/src/openai/__init__.py index 92beeb5da1..5fb1520549 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -32,7 +32,7 @@ APIResponseValidationError, ContentFilterFinishReasonError, ) -from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging from ._legacy_response import HttpxBinaryResponseContent as HttpxBinaryResponseContent @@ -77,6 +77,7 @@ "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] if not _t.TYPE_CHECKING: diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index 2f87d23aaa..0a6385a7b5 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -1306,6 +1306,24 @@ def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) +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) + + super().__init__(**kwargs) + + if TYPE_CHECKING: DefaultAsyncHttpxClient = httpx.AsyncClient """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK @@ -1314,8 +1332,12 @@ def __init__(self, **kwargs: Any) -> None: 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. """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" else: DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index ce9ed59ce3..01746b3a3a 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -83,7 +83,9 @@ def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter) class TestAsyncSpeech: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize @pytest.mark.respx(base_url=base_url) diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index 753acdecf6..11cbe2349c 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -121,7 +121,9 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: class TestAsyncTranscriptions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index e12ab7e6c0..ead69e9369 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -64,7 +64,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncTranslations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/realtime/test_sessions.py b/tests/api_resources/beta/realtime/test_sessions.py index efc52e0d57..9b78956a98 100644 --- a/tests/api_resources/beta/realtime/test_sessions.py +++ b/tests/api_resources/beta/realtime/test_sessions.py @@ -90,7 +90,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncSessions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/realtime/test_transcription_sessions.py b/tests/api_resources/beta/realtime/test_transcription_sessions.py index 5a6b4f6c92..ac52489e74 100644 --- a/tests/api_resources/beta/realtime/test_transcription_sessions.py +++ b/tests/api_resources/beta/realtime/test_transcription_sessions.py @@ -74,7 +74,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncTranscriptionSessions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index 82aaf87b1c..8aeb654e38 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -253,7 +253,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncAssistants: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/test_realtime.py b/tests/api_resources/beta/test_realtime.py index 537017ffd3..2b0c7f7d8d 100644 --- a/tests/api_resources/beta/test_realtime.py +++ b/tests/api_resources/beta/test_realtime.py @@ -14,4 +14,6 @@ class TestRealtime: class TestAsyncRealtime: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index eab94f0f8a..f392c86729 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -420,7 +420,9 @@ def test_streaming_response_create_and_run_overload_2(self, client: OpenAI) -> N class TestAsyncThreads: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/threads/runs/test_steps.py b/tests/api_resources/beta/threads/runs/test_steps.py index 9ca70657ec..ba44eec63d 100644 --- a/tests/api_resources/beta/threads/runs/test_steps.py +++ b/tests/api_resources/beta/threads/runs/test_steps.py @@ -167,7 +167,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncSteps: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index bf3f22e8a3..7f57002f27 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -321,7 +321,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncMessages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index fdef5e40db..86a296627e 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -568,7 +568,9 @@ def test_path_params_submit_tool_outputs_overload_2(self, client: OpenAI) -> Non class TestAsyncRuns: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/chat/completions/test_messages.py b/tests/api_resources/chat/completions/test_messages.py index 5caac9ec6c..4a4267e539 100644 --- a/tests/api_resources/chat/completions/test_messages.py +++ b/tests/api_resources/chat/completions/test_messages.py @@ -68,7 +68,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncMessages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index aaef82e8c5..aa8f58f0e5 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -447,7 +447,9 @@ class MyModel(pydantic.BaseModel): class TestAsyncCompletions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/containers/files/test_content.py b/tests/api_resources/containers/files/test_content.py index 402607058f..67fcdca36c 100644 --- a/tests/api_resources/containers/files/test_content.py +++ b/tests/api_resources/containers/files/test_content.py @@ -86,7 +86,9 @@ def test_path_params_retrieve(self, client: OpenAI) -> None: class TestAsyncContent: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize @pytest.mark.respx(base_url=base_url) diff --git a/tests/api_resources/containers/test_files.py b/tests/api_resources/containers/test_files.py index 6edcc7973a..f9d82d005c 100644 --- a/tests/api_resources/containers/test_files.py +++ b/tests/api_resources/containers/test_files.py @@ -215,7 +215,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/evals/runs/test_output_items.py b/tests/api_resources/evals/runs/test_output_items.py index f764f0336e..673867ac42 100644 --- a/tests/api_resources/evals/runs/test_output_items.py +++ b/tests/api_resources/evals/runs/test_output_items.py @@ -140,7 +140,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncOutputItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/evals/test_runs.py b/tests/api_resources/evals/test_runs.py index cefb1c82ff..1367cb4bab 100644 --- a/tests/api_resources/evals/test_runs.py +++ b/tests/api_resources/evals/test_runs.py @@ -306,7 +306,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: class TestAsyncRuns: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/alpha/test_graders.py b/tests/api_resources/fine_tuning/alpha/test_graders.py index c7fe6670f3..4a237114b6 100644 --- a/tests/api_resources/fine_tuning/alpha/test_graders.py +++ b/tests/api_resources/fine_tuning/alpha/test_graders.py @@ -151,7 +151,9 @@ def test_streaming_response_validate(self, client: OpenAI) -> None: class TestAsyncGraders: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_run(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index 4a7608d8df..4944597624 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -169,7 +169,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncPermissions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/jobs/test_checkpoints.py b/tests/api_resources/fine_tuning/jobs/test_checkpoints.py index 915d5c6f63..bb11529263 100644 --- a/tests/api_resources/fine_tuning/jobs/test_checkpoints.py +++ b/tests/api_resources/fine_tuning/jobs/test_checkpoints.py @@ -67,7 +67,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncCheckpoints: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index 4589f12846..8a35255885 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -354,7 +354,9 @@ def test_path_params_resume(self, client: OpenAI) -> None: class TestAsyncJobs: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/responses/test_input_items.py b/tests/api_resources/responses/test_input_items.py index 2528943c06..b28f5638c5 100644 --- a/tests/api_resources/responses/test_input_items.py +++ b/tests/api_resources/responses/test_input_items.py @@ -70,7 +70,9 @@ def test_path_params_list(self, client: OpenAI) -> None: class TestAsyncInputItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_batches.py b/tests/api_resources/test_batches.py index a2f8fb48a3..6775094a58 100644 --- a/tests/api_resources/test_batches.py +++ b/tests/api_resources/test_batches.py @@ -176,7 +176,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: class TestAsyncBatches: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_completions.py b/tests/api_resources/test_completions.py index 9ec503c1e3..1c5271df75 100644 --- a/tests/api_resources/test_completions.py +++ b/tests/api_resources/test_completions.py @@ -137,7 +137,9 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: class TestAsyncCompletions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_containers.py b/tests/api_resources/test_containers.py index be9787c4d6..c972f6539d 100644 --- a/tests/api_resources/test_containers.py +++ b/tests/api_resources/test_containers.py @@ -177,7 +177,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncContainers: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_embeddings.py b/tests/api_resources/test_embeddings.py index e75545b4e2..ce6e213d59 100644 --- a/tests/api_resources/test_embeddings.py +++ b/tests/api_resources/test_embeddings.py @@ -64,7 +64,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncEmbeddings: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_evals.py b/tests/api_resources/test_evals.py index 4ae2c597dd..473a4711ca 100644 --- a/tests/api_resources/test_evals.py +++ b/tests/api_resources/test_evals.py @@ -297,7 +297,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncEvals: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 7402566d95..fc4bb4a18e 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -260,7 +260,9 @@ def test_path_params_retrieve_content(self, client: OpenAI) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index 77bcea10ea..10fc56d685 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -163,7 +163,9 @@ def test_streaming_response_generate(self, client: OpenAI) -> None: class TestAsyncImages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_models.py b/tests/api_resources/test_models.py index 8791507c3e..cf70871ade 100644 --- a/tests/api_resources/test_models.py +++ b/tests/api_resources/test_models.py @@ -121,7 +121,9 @@ def test_path_params_delete(self, client: OpenAI) -> None: class TestAsyncModels: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_moderations.py b/tests/api_resources/test_moderations.py index 6df6464110..870c9e342f 100644 --- a/tests/api_resources/test_moderations.py +++ b/tests/api_resources/test_moderations.py @@ -58,7 +58,9 @@ def test_streaming_response_create(self, client: OpenAI) -> None: class TestAsyncModerations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 3bbf21ba14..6aaf0ea17f 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -352,7 +352,9 @@ def test_path_params_cancel(self, client: OpenAI) -> None: class TestAsyncResponses: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_uploads.py b/tests/api_resources/test_uploads.py index a14c4f8da2..72a2f6c83d 100644 --- a/tests/api_resources/test_uploads.py +++ b/tests/api_resources/test_uploads.py @@ -148,7 +148,9 @@ def test_path_params_complete(self, client: OpenAI) -> None: class TestAsyncUploads: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/test_vector_stores.py b/tests/api_resources/test_vector_stores.py index 54bb75bc1d..5af95fec41 100644 --- a/tests/api_resources/test_vector_stores.py +++ b/tests/api_resources/test_vector_stores.py @@ -286,7 +286,9 @@ def test_path_params_search(self, client: OpenAI) -> None: class TestAsyncVectorStores: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/uploads/test_parts.py b/tests/api_resources/uploads/test_parts.py index 2bba241a6d..191d3a1b04 100644 --- a/tests/api_resources/uploads/test_parts.py +++ b/tests/api_resources/uploads/test_parts.py @@ -61,7 +61,9 @@ def test_path_params_create(self, client: OpenAI) -> None: class TestAsyncParts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/vector_stores/test_file_batches.py b/tests/api_resources/vector_stores/test_file_batches.py index 0587cfc56a..ac678ce912 100644 --- a/tests/api_resources/vector_stores/test_file_batches.py +++ b/tests/api_resources/vector_stores/test_file_batches.py @@ -232,7 +232,9 @@ def test_path_params_list_files(self, client: OpenAI) -> None: class TestAsyncFileBatches: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index c13442261e..0778704d5d 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -323,7 +323,9 @@ def test_path_params_content(self, client: OpenAI) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: diff --git a/tests/conftest.py b/tests/conftest.py index 4b98d20a48..408bcf76c0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,10 +6,12 @@ import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest from pytest_asyncio import is_async_test -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, AsyncOpenAI, DefaultAioHttpClient +from openai._utils import is_dict if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] @@ -27,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: for async_test in pytest_asyncio_tests: async_test.add_marker(session_scope_marker, append=False) + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + 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")) + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -45,9 +60,25 @@ def client(request: FixtureRequest) -> Iterator[OpenAI]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOpenAI]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - - async with AsyncOpenAI(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncOpenAI( + base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + ) as client: yield client From ca9363d4ea5fcc5ad61683bd5fc39f107bc47aa6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:02:27 +0000 Subject: [PATCH 4/4] release: 1.89.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5ae95686ab..e0b8841fba 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.88.0" + ".": "1.89.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 09de5415d0..6557ddeab6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 1.89.0 (2025-06-20) + +Full Changelog: [v1.88.0...v1.89.0](https://github.com/openai/openai-python/compare/v1.88.0...v1.89.0) + +### Features + +* **client:** add support for aiohttp ([9218b07](https://github.com/openai/openai-python/commit/9218b07727bf6f6eb00953df66de6ab061fecddb)) + + +### Bug Fixes + +* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([35bcc4b](https://github.com/openai/openai-python/commit/35bcc4b80bdbaa31108650f2a515902e83794e5a)) + + +### Chores + +* **readme:** update badges ([68044ee](https://github.com/openai/openai-python/commit/68044ee85d1bf324b17d3f60c914df4725d47fc8)) + ## 1.88.0 (2025-06-17) Full Changelog: [v1.87.0...v1.88.0](https://github.com/openai/openai-python/compare/v1.87.0...v1.88.0) diff --git a/pyproject.toml b/pyproject.toml index b531a822dc..90716f994f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.88.0" +version = "1.89.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_version.py b/src/openai/_version.py index 7c606ee49c..46a41a551e 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__ = "1.88.0" # x-release-please-version +__version__ = "1.89.0" # x-release-please-version