From 05ca0d68e84d40f975614d27cb52c0f382104377 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:14:58 -0500 Subject: [PATCH 1/4] fix(azure): ensure custom options can be passed to copy (#858) --- src/openai/_client.py | 18 ++++---- src/openai/lib/azure.py | 94 +++++++++++++++++++++++++++++++++++++++-- tests/lib/test_azure.py | 30 +++++++++++++ 3 files changed, 129 insertions(+), 13 deletions(-) diff --git a/src/openai/_client.py b/src/openai/_client.py index 6664dc4233..aa00073281 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -4,8 +4,8 @@ import os import asyncio -from typing import Union, Mapping -from typing_extensions import override +from typing import Any, Union, Mapping +from typing_extensions import Self, override import httpx @@ -164,12 +164,10 @@ def copy( set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, set_default_query: Mapping[str, object] | None = None, - ) -> OpenAI: + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: """ Create a new client instance re-using the same options given to the current client with optional overriding. - - It should be noted that this does not share the underlying httpx client class which may lead - to performance issues. """ if default_headers is not None and set_default_headers is not None: raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") @@ -199,6 +197,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, + **_extra_kwargs, ) # Alias for `copy` for nicer inline usage, e.g. @@ -374,12 +373,10 @@ def copy( set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, set_default_query: Mapping[str, object] | None = None, - ) -> AsyncOpenAI: + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: """ Create a new client instance re-using the same options given to the current client with optional overriding. - - It should be noted that this does not share the underlying httpx client class which may lead - to performance issues. """ if default_headers is not None and set_default_headers is not None: raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") @@ -409,6 +406,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, + **_extra_kwargs, ) # Alias for `copy` for nicer inline usage, e.g. diff --git a/src/openai/lib/azure.py b/src/openai/lib/azure.py index d31313e95a..27bebd8cab 100644 --- a/src/openai/lib/azure.py +++ b/src/openai/lib/azure.py @@ -3,7 +3,7 @@ import os import inspect from typing import Any, Union, Mapping, TypeVar, Callable, Awaitable, overload -from typing_extensions import override +from typing_extensions import Self, override import httpx @@ -178,7 +178,7 @@ def __init__( if default_query is None: default_query = {"api-version": api_version} else: - default_query = {"api-version": api_version, **default_query} + default_query = {**default_query, "api-version": api_version} if base_url is None: if azure_endpoint is None: @@ -212,9 +212,53 @@ def __init__( http_client=http_client, _strict_response_validation=_strict_response_validation, ) + self._api_version = api_version self._azure_ad_token = azure_ad_token self._azure_ad_token_provider = azure_ad_token_provider + @override + def copy( + self, + *, + api_key: str | None = None, + organization: str | 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, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.Client | None = None, + max_retries: int | NotGiven = NOT_GIVEN, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + """ + Create a new client instance re-using the same options given to the current client with optional overriding. + """ + return super().copy( + api_key=api_key, + organization=organization, + base_url=base_url, + timeout=timeout, + http_client=http_client, + max_retries=max_retries, + default_headers=default_headers, + set_default_headers=set_default_headers, + default_query=default_query, + set_default_query=set_default_query, + _extra_kwargs={ + "api_version": api_version or self._api_version, + "azure_ad_token": azure_ad_token or self._azure_ad_token, + "azure_ad_token_provider": azure_ad_token_provider or self._azure_ad_token_provider, + **_extra_kwargs, + }, + ) + + with_options = copy + def _get_azure_ad_token(self) -> str | None: if self._azure_ad_token is not None: return self._azure_ad_token @@ -367,7 +411,7 @@ def __init__( if default_query is None: default_query = {"api-version": api_version} else: - default_query = {"api-version": api_version, **default_query} + default_query = {**default_query, "api-version": api_version} if base_url is None: if azure_endpoint is None: @@ -401,9 +445,53 @@ def __init__( http_client=http_client, _strict_response_validation=_strict_response_validation, ) + self._api_version = api_version self._azure_ad_token = azure_ad_token self._azure_ad_token_provider = azure_ad_token_provider + @override + def copy( + self, + *, + api_key: str | None = None, + organization: str | 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, + timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + http_client: httpx.AsyncClient | None = None, + max_retries: int | NotGiven = NOT_GIVEN, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + """ + Create a new client instance re-using the same options given to the current client with optional overriding. + """ + return super().copy( + api_key=api_key, + organization=organization, + base_url=base_url, + timeout=timeout, + http_client=http_client, + max_retries=max_retries, + default_headers=default_headers, + set_default_headers=set_default_headers, + default_query=default_query, + set_default_query=set_default_query, + _extra_kwargs={ + "api_version": api_version or self._api_version, + "azure_ad_token": azure_ad_token or self._azure_ad_token, + "azure_ad_token_provider": azure_ad_token_provider or self._azure_ad_token_provider, + **_extra_kwargs, + }, + ) + + with_options = copy + async def _get_azure_ad_token(self) -> str | None: if self._azure_ad_token is not None: return self._azure_ad_token diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index b0bd87571b..9360b2925a 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -1,4 +1,5 @@ from typing import Union +from typing_extensions import Literal import pytest @@ -34,3 +35,32 @@ def test_implicit_deployment_path(client: Client) -> None: req.url == "https://example-resource.azure.openai.com/openai/deployments/my-deployment-model/chat/completions?api-version=2023-07-01" ) + + +@pytest.mark.parametrize( + "client,method", + [ + (sync_client, "copy"), + (sync_client, "with_options"), + (async_client, "copy"), + (async_client, "with_options"), + ], +) +def test_client_copying(client: Client, method: Literal["copy", "with_options"]) -> None: + if method == "copy": + copied = client.copy() + else: + copied = client.with_options() + + assert copied._custom_query == {"api-version": "2023-07-01"} + + +@pytest.mark.parametrize( + "client", + [sync_client, async_client], +) +def test_client_copying_override_options(client: Client) -> None: + copied = client.copy( + api_version="2022-05-01", + ) + assert copied._custom_query == {"api-version": "2022-05-01"} From bec004d030b277e05bdd51f66fae1e881291c30b Mon Sep 17 00:00:00 2001 From: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:26:55 +0100 Subject: [PATCH 2/4] chore(package): add license classifier (#826) Having the license classifier in PyPI is also important so that it is uplaoded as part of the package's metadata. Otherwise, when querying it to PyPI this information is not shown in the package's metadata. --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index ae6fbaeeca..21004dac06 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ classifiers = [ "Operating System :: POSIX :: Linux", "Operating System :: Microsoft :: Windows", "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: Apache Software License", ] [project.optional-dependencies] From 80dffb17ff0a10b0b9ea704c4247521e48b68408 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:34:24 -0500 Subject: [PATCH 3/4] chore(package): add license classifier metadata (#860) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 21004dac06..85ad9e2177 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ "Operating System :: POSIX :: Linux", "Operating System :: Microsoft :: Windows", "Topic :: Software Development :: Libraries :: Python Modules", - "License :: OSI Approved :: Apache Software License", + "License :: OSI Approved :: Apache Software License" ] [project.optional-dependencies] From 9472bd122d4393f3ddc893d6976aff8c33316364 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:35:04 -0500 Subject: [PATCH 4/4] release: 1.3.5 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c050b0fe03..13787787c4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.3.4" + ".": "1.3.5" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1caef71db9..0869b3888c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.3.5 (2023-11-21) + +Full Changelog: [v1.3.4...v1.3.5](https://github.com/openai/openai-python/compare/v1.3.4...v1.3.5) + +### Bug Fixes + +* **azure:** ensure custom options can be passed to copy ([#858](https://github.com/openai/openai-python/issues/858)) ([05ca0d6](https://github.com/openai/openai-python/commit/05ca0d68e84d40f975614d27cb52c0f382104377)) + + +### Chores + +* **package:** add license classifier ([#826](https://github.com/openai/openai-python/issues/826)) ([bec004d](https://github.com/openai/openai-python/commit/bec004d030b277e05bdd51f66fae1e881291c30b)) +* **package:** add license classifier metadata ([#860](https://github.com/openai/openai-python/issues/860)) ([80dffb1](https://github.com/openai/openai-python/commit/80dffb17ff0a10b0b9ea704c4247521e48b68408)) + ## 1.3.4 (2023-11-21) Full Changelog: [v1.3.3...v1.3.4](https://github.com/openai/openai-python/compare/v1.3.3...v1.3.4) diff --git a/pyproject.toml b/pyproject.toml index 85ad9e2177..f17def16b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "1.3.4" +version = "1.3.5" description = "The official Python library for the openai API" readme = "README.md" license = "Apache-2.0" diff --git a/src/openai/_version.py b/src/openai/_version.py index ddfc847864..1ef6479491 100644 --- a/src/openai/_version.py +++ b/src/openai/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. __title__ = "openai" -__version__ = "1.3.4" # x-release-please-version +__version__ = "1.3.5" # x-release-please-version