# Copyright 2026 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # pyformat: disable """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from . import errors, types, utils from ._hooks import ( AfterErrorContext, AfterSuccessContext, BeforeRequestContext, HookContext, ) from .sdkconfiguration import SDKConfiguration from .utils import RetryConfig, SerializedRequestBody, get_body_content import httpx from typing import Any, Callable, List, Mapping, Optional, Tuple from urllib.parse import parse_qs, urlparse class BaseSDK: sdk_configuration: SDKConfiguration parent_ref: Optional[object] = None """ Reference to the root SDK instance, if any. This will prevent it from being garbage collected while there are active streams. """ def __init__( self, sdk_config: SDKConfiguration, parent_ref: Optional[object] = None, ) -> None: self.sdk_configuration = sdk_config self.parent_ref = parent_ref def _get_url(self, base_url, url_variables): sdk_url, sdk_variables = self.sdk_configuration.get_server_details() if base_url is None: base_url = sdk_url if url_variables is None: url_variables = sdk_variables return utils.template_url(base_url, url_variables) def _coerce_timeout_ms(self, timeout: Optional[Any]) -> Optional[int]: if timeout is None: return None if isinstance(timeout, (int, float)): return int(timeout * 1000) if isinstance(timeout, httpx.Timeout): values = [timeout.connect, timeout.read, timeout.write, timeout.pool] finite_values = [value for value in values if value is not None] if not finite_values: return None return int(max(finite_values) * 1000) raise TypeError("timeout must be a float, int, httpx.Timeout, or None") def _build_request( self, method, path, base_url, url_variables, request, request_body_required, request_has_path_params, request_has_query_params, user_agent_header, accept_header_value, _globals=None, security=None, timeout_ms: Optional[int] = None, get_serialized_body: Optional[ Callable[[], Optional[SerializedRequestBody]] ] = None, url_override: Optional[str] = None, http_headers: Optional[Mapping[str, str]] = None, extra_query_params: Optional[Mapping[str, Any]] = None, allow_empty_value: Optional[List[str]] = None, allowed_fields: Optional[List[str]] = None, ) -> httpx.Request: client = self.sdk_configuration.client return self._build_request_with_client( client, method, path, base_url, url_variables, request, request_body_required, request_has_path_params, request_has_query_params, user_agent_header, accept_header_value, _globals, security, timeout_ms, get_serialized_body, url_override, http_headers, extra_query_params, allow_empty_value, allowed_fields, ) def _build_request_with_client( self, client, method, path, base_url, url_variables, request, request_body_required, request_has_path_params, request_has_query_params, user_agent_header, accept_header_value, _globals=None, security=None, timeout_ms: Optional[int] = None, get_serialized_body: Optional[ Callable[[], Optional[SerializedRequestBody]] ] = None, url_override: Optional[str] = None, http_headers: Optional[Mapping[str, str]] = None, extra_query_params: Optional[Mapping[str, Any]] = None, allow_empty_value: Optional[List[str]] = None, allowed_fields: Optional[List[str]] = None, ) -> httpx.Request: query_params = {} url = url_override if url is None: url = utils.generate_url( self._get_url(base_url, url_variables), path, request if request_has_path_params else None, _globals if request_has_path_params else None, ) query_params = utils.get_query_params( request if request_has_query_params else None, _globals if request_has_query_params else None, allow_empty_value, ) else: # Pick up the query parameter from the override so they can be # preserved when building the request later on (necessary as of # httpx 0.28). parsed_override = urlparse(str(url_override)) query_params = parse_qs(parsed_override.query, keep_blank_values=True) headers = utils.get_headers(request, _globals) headers["Accept"] = accept_header_value headers[user_agent_header] = self.sdk_configuration.user_agent if security is not None: if callable(security): security = security() security = utils.get_security_from_env(security, types.Security) if security is not None: security_headers, security_query_params = utils.get_security( security, allowed_fields ) headers = {**headers, **security_headers} query_params = {**query_params, **security_query_params} if extra_query_params is not None: for name, value in extra_query_params.items(): if value is None: continue if isinstance(value, (list, tuple)): query_params[name] = [str(v) for v in value] else: query_params[name] = [str(value)] serialized_request_body = SerializedRequestBody() if get_serialized_body is not None: rb = get_serialized_body() if request_body_required and rb is None: raise ValueError("request body is required") if rb is not None: serialized_request_body = rb if ( serialized_request_body.media_type is not None and serialized_request_body.media_type not in ( "multipart/form-data", "multipart/mixed", ) ): headers["content-type"] = serialized_request_body.media_type if http_headers is not None: for header, value in http_headers.items(): headers[header] = value timeout = timeout_ms / 1000 if timeout_ms is not None else None return client.build_request( method, url, params=query_params, content=serialized_request_body.content, data=serialized_request_body.data, files=serialized_request_body.files, headers=headers, timeout=timeout if timeout is not None else httpx.USE_CLIENT_DEFAULT, ) def do_request( self, hook_ctx: HookContext, request: httpx.Request, is_error_status_code: Callable[[int], bool], stream: bool = False, retry_config: Optional[Tuple[RetryConfig, List[str]]] = None, ) -> httpx.Response: client = self.sdk_configuration.client logger = self.sdk_configuration.debug_logger hooks = self.sdk_configuration.__dict__["_hooks"] def do(_attempt: int = 0): http_res = None try: req = hooks.before_request(BeforeRequestContext(hook_ctx), request) if "timeout" in request.extensions and "timeout" not in req.extensions: req.extensions["timeout"] = request.extensions["timeout"] logger.debug( "Request:\nMethod: %s\nURL: %s\nHeaders: %s\nBody: %s", req.method, req.url, req.headers, get_body_content(req), ) if client is None: raise ValueError("client is required") http_res = client.send(req, stream=stream) except Exception as e: _, e = hooks.after_error(AfterErrorContext(hook_ctx), None, e) if e is not None: logger.debug("Request Exception", exc_info=True) raise e if http_res is None: logger.debug("Raising no response SDK error") raise errors.NoResponseError("No response received") logger.debug( "Response:\nStatus Code: %s\nURL: %s\nHeaders: %s\nBody: %s", http_res.status_code, http_res.url, http_res.headers, "" if stream else http_res.text, ) return http_res if retry_config is not None: http_res = utils.retry(do, utils.Retries(retry_config[0], retry_config[1])) else: http_res = do() if is_error_status_code(http_res.status_code): result, err = hooks.after_error(AfterErrorContext(hook_ctx), http_res, None) if err is not None: logger.debug("Request Exception", exc_info=True) raise err if result is not None: http_res = result else: logger.debug("Raising unexpected SDK error") raise errors.GenAiDefaultError("Unexpected error occurred", http_res) else: http_res = hooks.after_success(AfterSuccessContext(hook_ctx), http_res) return http_res class AsyncBaseSDK: sdk_configuration: SDKConfiguration parent_ref: Optional[object] = None """ Reference to the root SDK instance, if any. This will prevent it from being garbage collected while there are active streams. """ def __init__( self, sdk_config: SDKConfiguration, parent_ref: Optional[object] = None, ) -> None: self.sdk_configuration = sdk_config self.parent_ref = parent_ref def _get_url(self, base_url, url_variables): sdk_url, sdk_variables = self.sdk_configuration.get_server_details() if base_url is None: base_url = sdk_url if url_variables is None: url_variables = sdk_variables return utils.template_url(base_url, url_variables) def _coerce_timeout_ms(self, timeout: Optional[Any]) -> Optional[int]: if timeout is None: return None if isinstance(timeout, (int, float)): return int(timeout * 1000) if isinstance(timeout, httpx.Timeout): values = [timeout.connect, timeout.read, timeout.write, timeout.pool] finite_values = [value for value in values if value is not None] if not finite_values: return None return int(max(finite_values) * 1000) raise TypeError("timeout must be a float, int, httpx.Timeout, or None") def _build_request_async( self, method, path, base_url, url_variables, request, request_body_required, request_has_path_params, request_has_query_params, user_agent_header, accept_header_value, _globals=None, security=None, timeout_ms: Optional[int] = None, get_serialized_body: Optional[ Callable[[], Optional[SerializedRequestBody]] ] = None, url_override: Optional[str] = None, http_headers: Optional[Mapping[str, str]] = None, extra_query_params: Optional[Mapping[str, Any]] = None, allow_empty_value: Optional[List[str]] = None, allowed_fields: Optional[List[str]] = None, ) -> httpx.Request: client = self.sdk_configuration.async_client return self._build_request_with_client( client, method, path, base_url, url_variables, request, request_body_required, request_has_path_params, request_has_query_params, user_agent_header, accept_header_value, _globals, security, timeout_ms, get_serialized_body, url_override, http_headers, extra_query_params, allow_empty_value, allowed_fields, ) def _build_request_with_client( self, client, method, path, base_url, url_variables, request, request_body_required, request_has_path_params, request_has_query_params, user_agent_header, accept_header_value, _globals=None, security=None, timeout_ms: Optional[int] = None, get_serialized_body: Optional[ Callable[[], Optional[SerializedRequestBody]] ] = None, url_override: Optional[str] = None, http_headers: Optional[Mapping[str, str]] = None, extra_query_params: Optional[Mapping[str, Any]] = None, allow_empty_value: Optional[List[str]] = None, allowed_fields: Optional[List[str]] = None, ) -> httpx.Request: query_params = {} url = url_override if url is None: url = utils.generate_url( self._get_url(base_url, url_variables), path, request if request_has_path_params else None, _globals if request_has_path_params else None, ) query_params = utils.get_query_params( request if request_has_query_params else None, _globals if request_has_query_params else None, allow_empty_value, ) else: # Pick up the query parameter from the override so they can be # preserved when building the request later on (necessary as of # httpx 0.28). parsed_override = urlparse(str(url_override)) query_params = parse_qs(parsed_override.query, keep_blank_values=True) headers = utils.get_headers(request, _globals) headers["Accept"] = accept_header_value headers[user_agent_header] = self.sdk_configuration.user_agent if security is not None: if callable(security): security = security() security = utils.get_security_from_env(security, types.Security) if security is not None: security_headers, security_query_params = utils.get_security( security, allowed_fields ) headers = {**headers, **security_headers} query_params = {**query_params, **security_query_params} if extra_query_params is not None: for name, value in extra_query_params.items(): if value is None: continue if isinstance(value, (list, tuple)): query_params[name] = [str(v) for v in value] else: query_params[name] = [str(value)] serialized_request_body = SerializedRequestBody() if get_serialized_body is not None: rb = get_serialized_body() if request_body_required and rb is None: raise ValueError("request body is required") if rb is not None: serialized_request_body = rb if ( serialized_request_body.media_type is not None and serialized_request_body.media_type not in ( "multipart/form-data", "multipart/mixed", ) ): headers["content-type"] = serialized_request_body.media_type if http_headers is not None: for header, value in http_headers.items(): headers[header] = value timeout = timeout_ms / 1000 if timeout_ms is not None else None return client.build_request( method, url, params=query_params, content=serialized_request_body.content, data=serialized_request_body.data, files=serialized_request_body.files, headers=headers, timeout=timeout if timeout is not None else httpx.USE_CLIENT_DEFAULT, ) async def do_request_async( self, hook_ctx: HookContext, request: httpx.Request, is_error_status_code: Callable[[int], bool], stream: bool = False, retry_config: Optional[Tuple[RetryConfig, List[str]]] = None, ) -> httpx.Response: client = self.sdk_configuration.async_client logger = self.sdk_configuration.debug_logger async_hooks = self.sdk_configuration.__dict__["_async_hooks"] async def do(_attempt: int = 0): http_res = None try: req = await async_hooks.before_request( BeforeRequestContext(hook_ctx), request ) if "timeout" in request.extensions and "timeout" not in req.extensions: req.extensions["timeout"] = request.extensions["timeout"] logger.debug( "Request:\nMethod: %s\nURL: %s\nHeaders: %s\nBody: %s", req.method, req.url, req.headers, get_body_content(req), ) if client is None: raise ValueError("client is required") http_res = await client.send(req, stream=stream) except Exception as e: _, e = await async_hooks.after_error( AfterErrorContext(hook_ctx), None, e ) if e is not None: logger.debug("Request Exception", exc_info=True) raise e if http_res is None: logger.debug("Raising no response SDK error") raise errors.NoResponseError("No response received") logger.debug( "Response:\nStatus Code: %s\nURL: %s\nHeaders: %s\nBody: %s", http_res.status_code, http_res.url, http_res.headers, "" if stream else http_res.text, ) return http_res if retry_config is not None: http_res = await utils.retry_async( do, utils.Retries(retry_config[0], retry_config[1]) ) else: http_res = await do() if is_error_status_code(http_res.status_code): result, err = await async_hooks.after_error( AfterErrorContext(hook_ctx), http_res, None ) if err is not None: logger.debug("Request Exception", exc_info=True) raise err if result is not None: http_res = result else: logger.debug("Raising unexpected SDK error") raise errors.GenAiDefaultError("Unexpected error occurred", http_res) else: http_res = await async_hooks.after_success( AfterSuccessContext(hook_ctx), http_res ) return http_res