From f8cd02bb84937bbf70560766022597cb71e2c8c8 Mon Sep 17 00:00:00 2001 From: Narasimha Badrinath Date: Tue, 16 Sep 2025 15:37:39 +0530 Subject: [PATCH 1/4] feat(api): add user agent parameters to base_client and client classes for tracking usage --- src/gradient/_base_client.py | 17 ++++++++++++++++- src/gradient/_client.py | 10 ++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/gradient/_base_client.py b/src/gradient/_base_client.py index 74f3c57a..cd0a8c95 100644 --- a/src/gradient/_base_client.py +++ b/src/gradient/_base_client.py @@ -376,6 +376,8 @@ def __init__( timeout: float | Timeout | None = DEFAULT_TIMEOUT, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, + user_agent: str | None = None, + user_agent_version: str | None = None, ) -> None: self._version = version self._base_url = self._enforce_trailing_slash(URL(base_url)) @@ -386,6 +388,8 @@ def __init__( self._strict_response_validation = _strict_response_validation self._idempotency_header = None self._platform: Platform | None = None + self._user_agent_name = user_agent + self._user_agent_version = user_agent_version if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] raise TypeError( @@ -671,7 +675,10 @@ def _validate_headers( @property def user_agent(self) -> str: - return f"{self.__class__.__name__}/Python {self._version}" + # Format: "Gradient/package/version" + package = self._user_agent_name or "Python" + version = self._user_agent_version if self._user_agent_name and self._user_agent_version else self._version + return f"Gradient/{package}/{version}" @property def base_url(self) -> URL: @@ -830,6 +837,8 @@ def __init__( custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, + user_agent: str | None = None, + user_agent_version: str | None = None, ) -> None: if not is_given(timeout): # if the user passed in a custom http client with a non-default @@ -858,6 +867,8 @@ def __init__( custom_query=custom_query, custom_headers=custom_headers, _strict_response_validation=_strict_response_validation, + user_agent=user_agent, + user_agent_version=user_agent_version, ) self._client = http_client or SyncHttpxClientWrapper( base_url=base_url, @@ -1360,6 +1371,8 @@ def __init__( http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, + user_agent: str | None = None, + user_agent_version: str | None = None, ) -> None: if not is_given(timeout): # if the user passed in a custom http client with a non-default @@ -1388,6 +1401,8 @@ def __init__( custom_query=custom_query, custom_headers=custom_headers, _strict_response_validation=_strict_response_validation, + user_agent=user_agent, + user_agent_version=user_agent_version, ) self._client = http_client or AsyncHttpxClientWrapper( base_url=base_url, diff --git a/src/gradient/_client.py b/src/gradient/_client.py index 74b57d84..13751b09 100644 --- a/src/gradient/_client.py +++ b/src/gradient/_client.py @@ -106,6 +106,9 @@ def __init__( # outlining your use-case to help us decide if it should be # part of our public interface in the future. _strict_response_validation: bool = False, + # User agent tracking parameters + user_agent: str | None = None, + user_agent_version: str | None = None, ) -> None: """Construct a new synchronous Gradient client instance. @@ -169,6 +172,8 @@ def __init__( custom_headers=default_headers, custom_query=default_query, _strict_response_validation=_strict_response_validation, + user_agent=user_agent, + user_agent_version=user_agent_version, ) self._default_stream_cls = Stream @@ -410,6 +415,9 @@ def __init__( # outlining your use-case to help us decide if it should be # part of our public interface in the future. _strict_response_validation: bool = False, + # User agent tracking parameters + user_agent: str | None = None, + user_agent_version: str | None = None, ) -> None: """Construct a new async AsyncGradient client instance. @@ -473,6 +481,8 @@ def __init__( custom_headers=default_headers, custom_query=default_query, _strict_response_validation=_strict_response_validation, + user_agent=user_agent, + user_agent_version=user_agent_version, ) self._default_stream_cls = AsyncStream From 7f515bccd69b434c875053b05ff83736051a498c Mon Sep 17 00:00:00 2001 From: Narasimha Badrinath Date: Tue, 16 Sep 2025 16:06:08 +0530 Subject: [PATCH 2/4] feat(api): implement user agent parameters in Gradient and AsyncGradient classes to fix failing tests --- src/gradient/_client.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gradient/_client.py b/src/gradient/_client.py index 13751b09..c3f5b35d 100644 --- a/src/gradient/_client.py +++ b/src/gradient/_client.py @@ -299,6 +299,8 @@ 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, + user_agent: str | None = None, + user_agent_version: str | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -335,6 +337,8 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, + user_agent=user_agent or self._user_agent_name, + user_agent_version=user_agent_version or self._user_agent_version, **_extra_kwargs, ) client._base_url_overridden = self._base_url_overridden or base_url is not None @@ -608,6 +612,8 @@ 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, + user_agent: str | None = None, + user_agent_version: str | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -644,6 +650,8 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, + user_agent=user_agent or self._user_agent_name, + user_agent_version=user_agent_version or self._user_agent_version, **_extra_kwargs, ) client._base_url_overridden = self._base_url_overridden or base_url is not None From dba36f7bae0b3d28a0013f5d23c482b7be5e238a Mon Sep 17 00:00:00 2001 From: Narasimha Badrinath Date: Thu, 18 Sep 2025 14:55:36 +0530 Subject: [PATCH 3/4] refactor(api): rename user_agent parameter to user_agent_package in BaseClient, SyncAPIClient, and AsyncAPIClient for better clarity --- src/gradient/_base_client.py | 12 ++++++------ src/gradient/_client.py | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/gradient/_base_client.py b/src/gradient/_base_client.py index cd0a8c95..3c05d812 100644 --- a/src/gradient/_base_client.py +++ b/src/gradient/_base_client.py @@ -376,7 +376,7 @@ def __init__( timeout: float | Timeout | None = DEFAULT_TIMEOUT, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, ) -> None: self._version = version @@ -388,7 +388,7 @@ def __init__( self._strict_response_validation = _strict_response_validation self._idempotency_header = None self._platform: Platform | None = None - self._user_agent_name = user_agent + self._user_agent_package = user_agent_package self._user_agent_version = user_agent_version if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] @@ -676,8 +676,8 @@ def _validate_headers( @property def user_agent(self) -> str: # Format: "Gradient/package/version" - package = self._user_agent_name or "Python" - version = self._user_agent_version if self._user_agent_name and self._user_agent_version else self._version + package = self._user_agent_package or "Python" + version = self._user_agent_version if self._user_agent_package and self._user_agent_version else self._version return f"Gradient/{package}/{version}" @property @@ -867,7 +867,7 @@ def __init__( custom_query=custom_query, custom_headers=custom_headers, _strict_response_validation=_strict_response_validation, - user_agent=user_agent, + user_agent_package=user_agent_package, user_agent_version=user_agent_version, ) self._client = http_client or SyncHttpxClientWrapper( @@ -1401,7 +1401,7 @@ def __init__( custom_query=custom_query, custom_headers=custom_headers, _strict_response_validation=_strict_response_validation, - user_agent=user_agent, + user_agent_package=user_agent_package, user_agent_version=user_agent_version, ) self._client = http_client or AsyncHttpxClientWrapper( diff --git a/src/gradient/_client.py b/src/gradient/_client.py index c3f5b35d..8df330fb 100644 --- a/src/gradient/_client.py +++ b/src/gradient/_client.py @@ -107,7 +107,7 @@ def __init__( # part of our public interface in the future. _strict_response_validation: bool = False, # User agent tracking parameters - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, ) -> None: """Construct a new synchronous Gradient client instance. @@ -172,7 +172,7 @@ def __init__( custom_headers=default_headers, custom_query=default_query, _strict_response_validation=_strict_response_validation, - user_agent=user_agent, + user_agent_package=user_agent_package, user_agent_version=user_agent_version, ) @@ -420,7 +420,7 @@ def __init__( # part of our public interface in the future. _strict_response_validation: bool = False, # User agent tracking parameters - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, ) -> None: """Construct a new async AsyncGradient client instance. @@ -485,7 +485,7 @@ def __init__( custom_headers=default_headers, custom_query=default_query, _strict_response_validation=_strict_response_validation, - user_agent=user_agent, + user_agent_package=user_agent_package, user_agent_version=user_agent_version, ) From af7420c654bd30af4e30a939e31960ba6414adb7 Mon Sep 17 00:00:00 2001 From: Narasimha Badrinath Date: Thu, 18 Sep 2025 18:28:17 +0530 Subject: [PATCH 4/4] refactor(api): consistently rename user_agent parameter to user_agent_package in Gradient and AsyncGradient classes for clarity --- src/gradient/_base_client.py | 4 ++-- src/gradient/_client.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gradient/_base_client.py b/src/gradient/_base_client.py index 9c64f2bf..15fbd174 100644 --- a/src/gradient/_base_client.py +++ b/src/gradient/_base_client.py @@ -837,7 +837,7 @@ def __init__( custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, ) -> None: if not is_given(timeout): @@ -1371,7 +1371,7 @@ def __init__( http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, ) -> None: if not is_given(timeout): diff --git a/src/gradient/_client.py b/src/gradient/_client.py index 8df330fb..a809e56b 100644 --- a/src/gradient/_client.py +++ b/src/gradient/_client.py @@ -299,7 +299,7 @@ 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, - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: @@ -337,7 +337,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, - user_agent=user_agent or self._user_agent_name, + user_agent_package=user_agent_package or self._user_agent_package, user_agent_version=user_agent_version or self._user_agent_version, **_extra_kwargs, ) @@ -612,7 +612,7 @@ 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, - user_agent: str | None = None, + user_agent_package: str | None = None, user_agent_version: str | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: @@ -650,7 +650,7 @@ def copy( max_retries=max_retries if is_given(max_retries) else self.max_retries, default_headers=headers, default_query=params, - user_agent=user_agent or self._user_agent_name, + user_agent_package=user_agent_package or self._user_agent_package, user_agent_version=user_agent_version or self._user_agent_version, **_extra_kwargs, )