diff --git a/src/gradient/_base_client.py b/src/gradient/_base_client.py index a5a9ad8c..15fbd174 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_package: 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_package = user_agent_package + 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_package or "Python" + version = self._user_agent_version if self._user_agent_package and self._user_agent_version else self._version + return f"{self.__class__.__name__}/{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_package: 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_package=user_agent_package, + 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_package: 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_package=user_agent_package, + 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..a809e56b 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_package: 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_package=user_agent_package, + user_agent_version=user_agent_version, ) self._default_stream_cls = Stream @@ -294,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_package: str | None = None, + user_agent_version: str | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -330,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_package=user_agent_package or self._user_agent_package, + 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 @@ -410,6 +419,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_package: str | None = None, + user_agent_version: str | None = None, ) -> None: """Construct a new async AsyncGradient client instance. @@ -473,6 +485,8 @@ def __init__( custom_headers=default_headers, custom_query=default_query, _strict_response_validation=_strict_response_validation, + user_agent_package=user_agent_package, + user_agent_version=user_agent_version, ) self._default_stream_cls = AsyncStream @@ -598,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_package: str | None = None, + user_agent_version: str | None = None, _extra_kwargs: Mapping[str, Any] = {}, ) -> Self: """ @@ -634,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_package=user_agent_package or self._user_agent_package, + 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