From 7f8cb0f9a85b51f29539787b89fe72fd6c24ebf7 Mon Sep 17 00:00:00 2001 From: stainless-bot Date: Thu, 23 May 2024 01:47:44 +0000 Subject: [PATCH] feat(api): update via SDK Studio --- README.md | 6 +++--- src/honcho/_client.py | 49 ++++++++++++++++++++++++++++++------------- tests/test_client.py | 33 ++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index a094185..db78819 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ from honcho import Honcho client = Honcho( # This is the default and can be omitted - api_key=os.environ.get("HONCHO_AUTH_TOKEN"), + api_key=os.environ.get("HONCHO_API_KEY"), # defaults to "local". environment="demo", ) @@ -42,7 +42,7 @@ print(app.id) While you can provide an `api_key` keyword argument, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) -to add `HONCHO_AUTH_TOKEN="My API Key"` to your `.env` file +to add `HONCHO_API_KEY="My API Key"` to your `.env` file so that your API Key is not stored in source control. ## Async usage @@ -56,7 +56,7 @@ from honcho import AsyncHoncho client = AsyncHoncho( # This is the default and can be omitted - api_key=os.environ.get("HONCHO_AUTH_TOKEN"), + api_key=os.environ.get("HONCHO_API_KEY"), # defaults to "local". environment="demo", ) diff --git a/src/honcho/_client.py b/src/honcho/_client.py index 9fd368b..7aad5a9 100644 --- a/src/honcho/_client.py +++ b/src/honcho/_client.py @@ -13,6 +13,7 @@ from ._types import ( NOT_GIVEN, Omit, + Headers, Timeout, NotGiven, Transport, @@ -25,7 +26,7 @@ ) from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import HonchoError, APIStatusError +from ._exceptions import APIStatusError from ._base_client import ( DEFAULT_MAX_RETRIES, SyncAPIClient, @@ -57,7 +58,7 @@ class Honcho(SyncAPIClient): with_streaming_response: HonchoWithStreamedResponse # client options - api_key: str + api_key: str | None _environment: Literal["local", "demo"] | NotGiven @@ -87,14 +88,10 @@ def __init__( ) -> None: """Construct a new synchronous honcho client instance. - This automatically infers the `api_key` argument from the `HONCHO_AUTH_TOKEN` environment variable if it is not provided. + This automatically infers the `api_key` argument from the `HONCHO_API_KEY` environment variable if it is not provided. """ if api_key is None: - api_key = os.environ.get("HONCHO_AUTH_TOKEN") - if api_key is None: - raise HonchoError( - "The api_key client option must be set either by passing api_key to the client or by setting the HONCHO_AUTH_TOKEN environment variable" - ) + api_key = os.environ.get("HONCHO_API_KEY") self.api_key = api_key self._environment = environment @@ -147,6 +144,8 @@ def qs(self) -> Querystring: @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key + if api_key is None: + return {} return {"Authorization": f"Bearer {api_key}"} @property @@ -158,6 +157,17 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if self.api_key and headers.get("Authorization"): + return + if isinstance(custom_headers.get("Authorization"), Omit): + return + + raise TypeError( + '"Could not resolve authentication method. Expected the api_key to be set. Or for the `Authorization` headers to be explicitly omitted"' + ) + def copy( self, *, @@ -251,7 +261,7 @@ class AsyncHoncho(AsyncAPIClient): with_streaming_response: AsyncHonchoWithStreamedResponse # client options - api_key: str + api_key: str | None _environment: Literal["local", "demo"] | NotGiven @@ -281,14 +291,10 @@ def __init__( ) -> None: """Construct a new async honcho client instance. - This automatically infers the `api_key` argument from the `HONCHO_AUTH_TOKEN` environment variable if it is not provided. + This automatically infers the `api_key` argument from the `HONCHO_API_KEY` environment variable if it is not provided. """ if api_key is None: - api_key = os.environ.get("HONCHO_AUTH_TOKEN") - if api_key is None: - raise HonchoError( - "The api_key client option must be set either by passing api_key to the client or by setting the HONCHO_AUTH_TOKEN environment variable" - ) + api_key = os.environ.get("HONCHO_API_KEY") self.api_key = api_key self._environment = environment @@ -341,6 +347,8 @@ def qs(self) -> Querystring: @override def auth_headers(self) -> dict[str, str]: api_key = self.api_key + if api_key is None: + return {} return {"Authorization": f"Bearer {api_key}"} @property @@ -352,6 +360,17 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @override + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + if self.api_key and headers.get("Authorization"): + return + if isinstance(custom_headers.get("Authorization"), Omit): + return + + raise TypeError( + '"Could not resolve authentication method. Expected the api_key to be set. Or for the `Authorization` headers to be explicitly omitted"' + ) + def copy( self, *, diff --git a/tests/test_client.py b/tests/test_client.py index 28614bf..f3f0516 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -17,9 +17,10 @@ from pydantic import ValidationError from honcho import Honcho, AsyncHoncho, APIResponseValidationError +from honcho._types import Omit from honcho._models import BaseModel, FinalRequestOptions from honcho._constants import RAW_RESPONSE_HEADER -from honcho._exceptions import HonchoError, APIStatusError, APITimeoutError, APIResponseValidationError +from honcho._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError from honcho._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options from .utils import update_env @@ -326,9 +327,18 @@ def test_validate_headers(self) -> None: request = client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("Authorization") == f"Bearer {api_key}" - with pytest.raises(HonchoError): - client2 = Honcho(base_url=base_url, api_key=None, _strict_response_validation=True) - _ = client2 + client2 = Honcho(base_url=base_url, api_key=None, _strict_response_validation=True) + + with pytest.raises( + TypeError, + match="Could not resolve authentication method. Expected the api_key to be set. Or for the `Authorization` headers to be explicitly omitted", + ): + client2._build_request(FinalRequestOptions(method="get", url="/foo")) + + request2 = client2._build_request( + FinalRequestOptions(method="get", url="/foo", headers={"Authorization": Omit()}) + ) + assert request2.headers.get("Authorization") is None def test_default_query_option(self) -> None: client = Honcho( @@ -1017,9 +1027,18 @@ def test_validate_headers(self) -> None: request = client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("Authorization") == f"Bearer {api_key}" - with pytest.raises(HonchoError): - client2 = AsyncHoncho(base_url=base_url, api_key=None, _strict_response_validation=True) - _ = client2 + client2 = AsyncHoncho(base_url=base_url, api_key=None, _strict_response_validation=True) + + with pytest.raises( + TypeError, + match="Could not resolve authentication method. Expected the api_key to be set. Or for the `Authorization` headers to be explicitly omitted", + ): + client2._build_request(FinalRequestOptions(method="get", url="/foo")) + + request2 = client2._build_request( + FinalRequestOptions(method="get", url="/foo", headers={"Authorization": Omit()}) + ) + assert request2.headers.get("Authorization") is None def test_default_query_option(self) -> None: client = AsyncHoncho(