ionq_core
A client library for accessing IonQ Cloud Platform API
1# SPDX-FileCopyrightText: 2026 IonQ, Inc. 2# SPDX-License-Identifier: Apache-2.0 3# @generated 4 5"""A client library for accessing IonQ Cloud Platform API""" 6 7from . import exceptions, extensions, gates, ionq_client, pagination, polling, session 8from .client import AuthenticatedClient, Client # noqa: F401 9from .exceptions import * # noqa: F403 10from .extensions import * # noqa: F403 11from .gates import * # noqa: F403 12from .ionq_client import * # noqa: F403 13from .pagination import * # noqa: F403 14from .polling import * # noqa: F403 15from .session import * # noqa: F403 16from .types import UNSET, Unset # noqa: F401 17 18__all__ = sorted( 19 { 20 "exceptions", 21 "extensions", 22 "gates", 23 "ionq_client", 24 "pagination", 25 "polling", 26 "session", 27 "AuthenticatedClient", 28 "Client", 29 "UNSET", 30 "Unset", 31 *exceptions.__all__, 32 *extensions.__all__, 33 *gates.__all__, 34 *ionq_client.__all__, 35 *pagination.__all__, 36 *polling.__all__, 37 *session.__all__, 38 } 39)
58class APIConnectionError(IonQError): 59 """Raised when a connection to the IonQ API cannot be established. 60 61 This covers DNS resolution failures, refused connections, and other 62 network-level errors. The original ``httpx`` exception is chained 63 via ``__cause__``. 64 """
Raised when a connection to the IonQ API cannot be established.
This covers DNS resolution failures, refused connections, and other
network-level errors. The original httpx exception is chained
via __cause__.
75class APIError(IonQError): 76 """Raised when the IonQ API returns an HTTP error response (4xx or 5xx). 77 78 Attributes: 79 status_code: The HTTP status code. 80 body: The parsed response body (``dict`` if JSON, ``str`` otherwise, 81 or ``None`` if the body could not be read). 82 message: A human-readable error message extracted from the response, 83 or a default ``"HTTP <status>"`` string. 84 request_id: The ``x-request-id`` header from the response, useful for 85 contacting IonQ support about a specific request. 86 """ 87 88 def __init__( 89 self, 90 status_code: int, 91 body: dict | str | None = None, 92 message: str | None = None, 93 *, 94 request_id: str | None = None, 95 ) -> None: 96 self.status_code = status_code 97 self.body = body 98 self.request_id = request_id 99 self.message = message or f"HTTP {status_code}" 100 super().__init__(self.message)
Raised when the IonQ API returns an HTTP error response (4xx or 5xx).
Attributes:
- status_code: The HTTP status code.
- body: The parsed response body (
dictif JSON,strotherwise, orNoneif the body could not be read). - message: A human-readable error message extracted from the response,
or a default
"HTTP <status>"string. - request_id: The
x-request-idheader from the response, useful for contacting IonQ support about a specific request.
88 def __init__( 89 self, 90 status_code: int, 91 body: dict | str | None = None, 92 message: str | None = None, 93 *, 94 request_id: str | None = None, 95 ) -> None: 96 self.status_code = status_code 97 self.body = body 98 self.request_id = request_id 99 self.message = message or f"HTTP {status_code}" 100 super().__init__(self.message)
67class APITimeoutError(APIConnectionError): 68 """Raised when a request to the IonQ API times out. 69 70 Inherits from `APIConnectionError` so that catching connection errors 71 also catches timeouts. 72 """
Raised when a request to the IonQ API times out.
Inherits from APIConnectionError so that catching connection errors
also catches timeouts.
76@runtime_checkable 77class AsyncEventHook(Protocol): 78 """Async counterpart of `EventHook` for the async client path. 79 80 Implement this protocol and pass instances via 81 `ClientExtension.async_event_hooks`. 82 """ 83 84 async def on_request(self, request: httpx.Request) -> None: 85 """Called after the request is built but before it is sent. 86 87 Args: 88 request: The outgoing HTTP request. 89 """ 90 ... 91 92 async def on_response(self, request: httpx.Request, response: httpx.Response) -> None: 93 """Called after a response is received. 94 95 Args: 96 request: The original HTTP request. 97 response: The HTTP response. 98 """ 99 ...
Async counterpart of EventHook for the async client path.
Implement this protocol and pass instances via
ClientExtension.async_event_hooks.
1953def _no_init_or_replace_init(self, *args, **kwargs): 1954 cls = type(self) 1955 1956 if cls._is_protocol: 1957 raise TypeError('Protocols cannot be instantiated') 1958 1959 # Already using a custom `__init__`. No need to calculate correct 1960 # `__init__` to call. This can lead to RecursionError. See bpo-45121. 1961 if cls.__init__ is not _no_init_or_replace_init: 1962 return 1963 1964 # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`. 1965 # The first instantiation of the subclass will call `_no_init_or_replace_init` which 1966 # searches for a proper new `__init__` in the MRO. The new `__init__` 1967 # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent 1968 # instantiation of the protocol subclass will thus use the new 1969 # `__init__` and no longer call `_no_init_or_replace_init`. 1970 for base in cls.__mro__: 1971 init = base.__dict__.get('__init__', _no_init_or_replace_init) 1972 if init is not _no_init_or_replace_init: 1973 cls.__init__ = init 1974 break 1975 else: 1976 # should not happen 1977 cls.__init__ = object.__init__ 1978 1979 cls.__init__(self, *args, **kwargs)
84 async def on_request(self, request: httpx.Request) -> None: 85 """Called after the request is built but before it is sent. 86 87 Args: 88 request: The outgoing HTTP request. 89 """ 90 ...
Called after the request is built but before it is sent.
Arguments:
- request: The outgoing HTTP request.
92 async def on_response(self, request: httpx.Request, response: httpx.Response) -> None: 93 """Called after a response is received. 94 95 Args: 96 request: The original HTTP request. 97 response: The HTTP response. 98 """ 99 ...
Called after a response is received.
Arguments:
- request: The original HTTP request.
- response: The HTTP response.
142@define 143class AuthenticatedClient: 144 """A Client which has been authenticated for use on secured endpoints 145 146 The following are accepted as keyword arguments and will be used to construct httpx Clients internally: 147 148 ``base_url``: The base URL for the API, all requests are made to a relative path to this URL 149 150 ``cookies``: A dictionary of cookies to be sent with every request 151 152 ``headers``: A dictionary of headers to be sent with every request 153 154 ``timeout``: The maximum amount of a time a request can take. API functions will raise 155 httpx.TimeoutException if this is exceeded. 156 157 ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, 158 but can be set to False for testing purposes. 159 160 ``follow_redirects``: Whether or not to follow redirects. Default value is False. 161 162 ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. 163 164 165 Attributes: 166 raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a 167 status code that was not documented in the source OpenAPI document. Can also be provided as a keyword 168 argument to the constructor. 169 token: The token to use for authentication 170 prefix: The prefix to use for the Authorization header 171 auth_header_name: The name of the Authorization header 172 """ 173 174 raise_on_unexpected_status: bool = field(default=False, kw_only=True) 175 _base_url: str = field(alias="base_url") 176 _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") 177 _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") 178 _timeout: httpx.Timeout | None = field(default=None, kw_only=True, alias="timeout") 179 _verify_ssl: str | bool | ssl.SSLContext = field(default=True, kw_only=True, alias="verify_ssl") 180 _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") 181 _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") 182 _client: httpx.Client | None = field(default=None, init=False) 183 _async_client: httpx.AsyncClient | None = field(default=None, init=False) 184 185 token: str = field(repr=False) 186 prefix: str = "Bearer" 187 auth_header_name: str = "Authorization" 188 189 def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": 190 """Get a new client matching this one with additional headers""" 191 if self._client is not None: 192 self._client.headers.update(headers) 193 if self._async_client is not None: 194 self._async_client.headers.update(headers) 195 return evolve(self, headers={**self._headers, **headers}) 196 197 def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": 198 """Get a new client matching this one with additional cookies""" 199 if self._client is not None: 200 self._client.cookies.update(cookies) 201 if self._async_client is not None: 202 self._async_client.cookies.update(cookies) 203 return evolve(self, cookies={**self._cookies, **cookies}) 204 205 def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": 206 """Get a new client matching this one with a new timeout configuration""" 207 if self._client is not None: 208 self._client.timeout = timeout 209 if self._async_client is not None: 210 self._async_client.timeout = timeout 211 return evolve(self, timeout=timeout) 212 213 def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": 214 """Manually set the underlying httpx.Client 215 216 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 217 """ 218 self._client = client 219 return self 220 221 def get_httpx_client(self) -> httpx.Client: 222 """Get the underlying httpx.Client, constructing a new one if not previously set""" 223 if self._client is None: 224 self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token 225 self._client = httpx.Client( 226 base_url=self._base_url, 227 cookies=self._cookies, 228 headers=self._headers, 229 timeout=self._timeout, 230 verify=self._verify_ssl, 231 follow_redirects=self._follow_redirects, 232 **self._httpx_args, 233 ) 234 return self._client 235 236 def __enter__(self) -> "AuthenticatedClient": 237 """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" 238 self.get_httpx_client().__enter__() 239 return self 240 241 def __exit__(self, *args: Any, **kwargs: Any) -> None: 242 """Exit a context manager for internal httpx.Client (see httpx docs)""" 243 self.get_httpx_client().__exit__(*args, **kwargs) 244 245 def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": 246 """Manually set the underlying httpx.AsyncClient 247 248 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 249 """ 250 self._async_client = async_client 251 return self 252 253 def get_async_httpx_client(self) -> httpx.AsyncClient: 254 """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" 255 if self._async_client is None: 256 self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token 257 self._async_client = httpx.AsyncClient( 258 base_url=self._base_url, 259 cookies=self._cookies, 260 headers=self._headers, 261 timeout=self._timeout, 262 verify=self._verify_ssl, 263 follow_redirects=self._follow_redirects, 264 **self._httpx_args, 265 ) 266 return self._async_client 267 268 async def __aenter__(self) -> "AuthenticatedClient": 269 """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" 270 await self.get_async_httpx_client().__aenter__() 271 return self 272 273 async def __aexit__(self, *args: Any, **kwargs: Any) -> None: 274 """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" 275 await self.get_async_httpx_client().__aexit__(*args, **kwargs)
A Client which has been authenticated for use on secured endpoints
The following are accepted as keyword arguments and will be used to construct httpx Clients internally:
base_url: The base URL for the API, all requests are made to a relative path to this URL
cookies: A dictionary of cookies to be sent with every request
headers: A dictionary of headers to be sent with every request
timeout: The maximum amount of a time a request can take. API functions will raise httpx.TimeoutException if this is exceeded.
verify_ssl: Whether or not to verify the SSL certificate of the API server. This should be True in production, but can be set to False for testing purposes.
follow_redirects: Whether or not to follow redirects. Default value is False.
httpx_args: A dictionary of additional arguments to be passed to thehttpx.Clientandhttpx.AsyncClientconstructor.
Attributes:
- raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a status code that was not documented in the source OpenAPI document. Can also be provided as a keyword argument to the constructor.
- token: The token to use for authentication
- prefix: The prefix to use for the Authorization header
- auth_header_name: The name of the Authorization header
35def __init__(self, base_url, token, prefix=attr_dict['prefix'].default, auth_header_name=attr_dict['auth_header_name'].default, *, raise_on_unexpected_status=attr_dict['raise_on_unexpected_status'].default, cookies=NOTHING, headers=NOTHING, timeout=attr_dict['_timeout'].default, verify_ssl=attr_dict['_verify_ssl'].default, follow_redirects=attr_dict['_follow_redirects'].default, httpx_args=NOTHING): 36 self.raise_on_unexpected_status = raise_on_unexpected_status 37 self._base_url = base_url 38 if cookies is not NOTHING: 39 self._cookies = cookies 40 else: 41 self._cookies = __attr_factory__cookies() 42 if headers is not NOTHING: 43 self._headers = headers 44 else: 45 self._headers = __attr_factory__headers() 46 self._timeout = timeout 47 self._verify_ssl = verify_ssl 48 self._follow_redirects = follow_redirects 49 if httpx_args is not NOTHING: 50 self._httpx_args = httpx_args 51 else: 52 self._httpx_args = __attr_factory__httpx_args() 53 self._client = attr_dict['_client'].default 54 self._async_client = attr_dict['_async_client'].default 55 self.token = token 56 self.prefix = prefix 57 self.auth_header_name = auth_header_name
Method generated by attrs for class AuthenticatedClient.
189 def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": 190 """Get a new client matching this one with additional headers""" 191 if self._client is not None: 192 self._client.headers.update(headers) 193 if self._async_client is not None: 194 self._async_client.headers.update(headers) 195 return evolve(self, headers={**self._headers, **headers})
Get a new client matching this one with additional headers
205 def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": 206 """Get a new client matching this one with a new timeout configuration""" 207 if self._client is not None: 208 self._client.timeout = timeout 209 if self._async_client is not None: 210 self._async_client.timeout = timeout 211 return evolve(self, timeout=timeout)
Get a new client matching this one with a new timeout configuration
213 def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": 214 """Manually set the underlying httpx.Client 215 216 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 217 """ 218 self._client = client 219 return self
Manually set the underlying httpx.Client
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
221 def get_httpx_client(self) -> httpx.Client: 222 """Get the underlying httpx.Client, constructing a new one if not previously set""" 223 if self._client is None: 224 self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token 225 self._client = httpx.Client( 226 base_url=self._base_url, 227 cookies=self._cookies, 228 headers=self._headers, 229 timeout=self._timeout, 230 verify=self._verify_ssl, 231 follow_redirects=self._follow_redirects, 232 **self._httpx_args, 233 ) 234 return self._client
Get the underlying httpx.Client, constructing a new one if not previously set
245 def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": 246 """Manually set the underlying httpx.AsyncClient 247 248 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 249 """ 250 self._async_client = async_client 251 return self
Manually set the underlying httpx.AsyncClient
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
253 def get_async_httpx_client(self) -> httpx.AsyncClient: 254 """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" 255 if self._async_client is None: 256 self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token 257 self._async_client = httpx.AsyncClient( 258 base_url=self._base_url, 259 cookies=self._cookies, 260 headers=self._headers, 261 timeout=self._timeout, 262 verify=self._verify_ssl, 263 follow_redirects=self._follow_redirects, 264 **self._httpx_args, 265 ) 266 return self._async_client
Get the underlying httpx.AsyncClient, constructing a new one if not previously set
103class AuthenticationError(APIError): 104 """Raised on ``401 Unauthorized``. 105 106 Typically means the API key is missing, invalid, or revoked. 107 """
Raised on 401 Unauthorized.
Typically means the API key is missing, invalid, or revoked.
Inherited Members
124class BadRequestError(APIError): 125 """Raised on ``400 Bad Request``. 126 127 The request body or query parameters failed server-side validation. 128 Inspect ``body`` for details. 129 """
Raised on 400 Bad Request.
The request body or query parameters failed server-side validation.
Inspect body for details.
Inherited Members
16@define 17class Client: 18 """A class for keeping track of data related to the API 19 20 The following are accepted as keyword arguments and will be used to construct httpx Clients internally: 21 22 ``base_url``: The base URL for the API, all requests are made to a relative path to this URL 23 24 ``cookies``: A dictionary of cookies to be sent with every request 25 26 ``headers``: A dictionary of headers to be sent with every request 27 28 ``timeout``: The maximum amount of a time a request can take. API functions will raise 29 httpx.TimeoutException if this is exceeded. 30 31 ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, 32 but can be set to False for testing purposes. 33 34 ``follow_redirects``: Whether or not to follow redirects. Default value is False. 35 36 ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. 37 38 39 Attributes: 40 raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a 41 status code that was not documented in the source OpenAPI document. Can also be provided as a keyword 42 argument to the constructor. 43 """ 44 raise_on_unexpected_status: bool = field(default=False, kw_only=True) 45 _base_url: str = field(alias="base_url") 46 _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") 47 _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") 48 _timeout: httpx.Timeout | None = field(default=None, kw_only=True, alias="timeout") 49 _verify_ssl: str | bool | ssl.SSLContext = field(default=True, kw_only=True, alias="verify_ssl") 50 _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") 51 _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") 52 _client: httpx.Client | None = field(default=None, init=False) 53 _async_client: httpx.AsyncClient | None = field(default=None, init=False) 54 55 def with_headers(self, headers: dict[str, str]) -> "Client": 56 """Get a new client matching this one with additional headers""" 57 if self._client is not None: 58 self._client.headers.update(headers) 59 if self._async_client is not None: 60 self._async_client.headers.update(headers) 61 return evolve(self, headers={**self._headers, **headers}) 62 63 def with_cookies(self, cookies: dict[str, str]) -> "Client": 64 """Get a new client matching this one with additional cookies""" 65 if self._client is not None: 66 self._client.cookies.update(cookies) 67 if self._async_client is not None: 68 self._async_client.cookies.update(cookies) 69 return evolve(self, cookies={**self._cookies, **cookies}) 70 71 def with_timeout(self, timeout: httpx.Timeout) -> "Client": 72 """Get a new client matching this one with a new timeout configuration""" 73 if self._client is not None: 74 self._client.timeout = timeout 75 if self._async_client is not None: 76 self._async_client.timeout = timeout 77 return evolve(self, timeout=timeout) 78 79 def set_httpx_client(self, client: httpx.Client) -> "Client": 80 """Manually set the underlying httpx.Client 81 82 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 83 """ 84 self._client = client 85 return self 86 87 def get_httpx_client(self) -> httpx.Client: 88 """Get the underlying httpx.Client, constructing a new one if not previously set""" 89 if self._client is None: 90 self._client = httpx.Client( 91 base_url=self._base_url, 92 cookies=self._cookies, 93 headers=self._headers, 94 timeout=self._timeout, 95 verify=self._verify_ssl, 96 follow_redirects=self._follow_redirects, 97 **self._httpx_args, 98 ) 99 return self._client 100 101 def __enter__(self) -> "Client": 102 """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" 103 self.get_httpx_client().__enter__() 104 return self 105 106 def __exit__(self, *args: Any, **kwargs: Any) -> None: 107 """Exit a context manager for internal httpx.Client (see httpx docs)""" 108 self.get_httpx_client().__exit__(*args, **kwargs) 109 110 def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": 111 """Manually set the underlying httpx.AsyncClient 112 113 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 114 """ 115 self._async_client = async_client 116 return self 117 118 def get_async_httpx_client(self) -> httpx.AsyncClient: 119 """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" 120 if self._async_client is None: 121 self._async_client = httpx.AsyncClient( 122 base_url=self._base_url, 123 cookies=self._cookies, 124 headers=self._headers, 125 timeout=self._timeout, 126 verify=self._verify_ssl, 127 follow_redirects=self._follow_redirects, 128 **self._httpx_args, 129 ) 130 return self._async_client 131 132 async def __aenter__(self) -> "Client": 133 """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" 134 await self.get_async_httpx_client().__aenter__() 135 return self 136 137 async def __aexit__(self, *args: Any, **kwargs: Any) -> None: 138 """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" 139 await self.get_async_httpx_client().__aexit__(*args, **kwargs)
A class for keeping track of data related to the API
The following are accepted as keyword arguments and will be used to construct httpx Clients internally:
base_url: The base URL for the API, all requests are made to a relative path to this URL
cookies: A dictionary of cookies to be sent with every request
headers: A dictionary of headers to be sent with every request
timeout: The maximum amount of a time a request can take. API functions will raise httpx.TimeoutException if this is exceeded.
verify_ssl: Whether or not to verify the SSL certificate of the API server. This should be True in production, but can be set to False for testing purposes.
follow_redirects: Whether or not to follow redirects. Default value is False.
httpx_args: A dictionary of additional arguments to be passed to thehttpx.Clientandhttpx.AsyncClientconstructor.
Attributes:
- raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a status code that was not documented in the source OpenAPI document. Can also be provided as a keyword argument to the constructor.
32def __init__(self, base_url, *, raise_on_unexpected_status=attr_dict['raise_on_unexpected_status'].default, cookies=NOTHING, headers=NOTHING, timeout=attr_dict['_timeout'].default, verify_ssl=attr_dict['_verify_ssl'].default, follow_redirects=attr_dict['_follow_redirects'].default, httpx_args=NOTHING): 33 self.raise_on_unexpected_status = raise_on_unexpected_status 34 self._base_url = base_url 35 if cookies is not NOTHING: 36 self._cookies = cookies 37 else: 38 self._cookies = __attr_factory__cookies() 39 if headers is not NOTHING: 40 self._headers = headers 41 else: 42 self._headers = __attr_factory__headers() 43 self._timeout = timeout 44 self._verify_ssl = verify_ssl 45 self._follow_redirects = follow_redirects 46 if httpx_args is not NOTHING: 47 self._httpx_args = httpx_args 48 else: 49 self._httpx_args = __attr_factory__httpx_args() 50 self._client = attr_dict['_client'].default 51 self._async_client = attr_dict['_async_client'].default
Method generated by attrs for class Client.
55 def with_headers(self, headers: dict[str, str]) -> "Client": 56 """Get a new client matching this one with additional headers""" 57 if self._client is not None: 58 self._client.headers.update(headers) 59 if self._async_client is not None: 60 self._async_client.headers.update(headers) 61 return evolve(self, headers={**self._headers, **headers})
Get a new client matching this one with additional headers
71 def with_timeout(self, timeout: httpx.Timeout) -> "Client": 72 """Get a new client matching this one with a new timeout configuration""" 73 if self._client is not None: 74 self._client.timeout = timeout 75 if self._async_client is not None: 76 self._async_client.timeout = timeout 77 return evolve(self, timeout=timeout)
Get a new client matching this one with a new timeout configuration
79 def set_httpx_client(self, client: httpx.Client) -> "Client": 80 """Manually set the underlying httpx.Client 81 82 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 83 """ 84 self._client = client 85 return self
Manually set the underlying httpx.Client
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
87 def get_httpx_client(self) -> httpx.Client: 88 """Get the underlying httpx.Client, constructing a new one if not previously set""" 89 if self._client is None: 90 self._client = httpx.Client( 91 base_url=self._base_url, 92 cookies=self._cookies, 93 headers=self._headers, 94 timeout=self._timeout, 95 verify=self._verify_ssl, 96 follow_redirects=self._follow_redirects, 97 **self._httpx_args, 98 ) 99 return self._client
Get the underlying httpx.Client, constructing a new one if not previously set
110 def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": 111 """Manually set the underlying httpx.AsyncClient 112 113 **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. 114 """ 115 self._async_client = async_client 116 return self
Manually set the underlying httpx.AsyncClient
NOTE: This will override any other settings on the client, including cookies, headers, and timeout.
118 def get_async_httpx_client(self) -> httpx.AsyncClient: 119 """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" 120 if self._async_client is None: 121 self._async_client = httpx.AsyncClient( 122 base_url=self._base_url, 123 cookies=self._cookies, 124 headers=self._headers, 125 timeout=self._timeout, 126 verify=self._verify_ssl, 127 follow_redirects=self._follow_redirects, 128 **self._httpx_args, 129 ) 130 return self._async_client
Get the underlying httpx.AsyncClient, constructing a new one if not previously set
102@attrs.frozen 103class ClientExtension: 104 """Declarative configuration bundle for downstream SDK integration. 105 106 All fields are optional. Pass an instance to `IonQClient` via the 107 ``extension`` parameter to customize client behavior. 108 109 Attributes: 110 user_agent_token: Extra token appended to the ``User-Agent`` header 111 (e.g. ``"my-sdk/1.0"``). 112 default_headers: Headers merged into every request. 113 event_hooks: Sync `EventHook` instances invoked on every request. 114 async_event_hooks: Async `AsyncEventHook` instances invoked on 115 every async request. 116 retryable_status_codes: HTTP status codes that should trigger a retry. 117 Overrides the default set (429, 500, 502, 503, 520-529). 118 max_retries: Maximum retry attempts. Overrides the default of 2. 119 timeout: Request timeout. Overrides the default of 60 seconds. 120 transport_wrapper: Callable that wraps the sync transport, useful for 121 adding middleware (e.g. caching, tracing). 122 async_transport_wrapper: Callable that wraps the async transport. 123 error_mapper: Callable that maps exceptions raised by the transport 124 to downstream-specific exception types. Return the original 125 exception to leave it unchanged. 126 debug_hooks: If ``True``, hook exceptions are re-raised instead of 127 being logged and suppressed. Useful during development. 128 """ 129 130 user_agent_token: str | None = None 131 default_headers: dict[str, str] = attrs.Factory(dict) 132 event_hooks: tuple[EventHook, ...] = () 133 async_event_hooks: tuple[AsyncEventHook, ...] = () 134 retryable_status_codes: frozenset[int] | None = None 135 max_retries: int | None = None 136 timeout: httpx.Timeout | None = None 137 transport_wrapper: Callable[[httpx.BaseTransport], httpx.BaseTransport] | None = None 138 async_transport_wrapper: Callable[[httpx.AsyncBaseTransport], httpx.AsyncBaseTransport] | None = None 139 error_mapper: Callable[[Exception], Exception] | None = None 140 debug_hooks: bool = False
Declarative configuration bundle for downstream SDK integration.
All fields are optional. Pass an instance to IonQClient via the
extension parameter to customize client behavior.
Attributes:
- user_agent_token: Extra token appended to the
User-Agentheader (e.g."my-sdk/1.0"). - default_headers: Headers merged into every request.
- event_hooks: Sync
EventHookinstances invoked on every request. - async_event_hooks: Async
AsyncEventHookinstances invoked on every async request. - retryable_status_codes: HTTP status codes that should trigger a retry. Overrides the default set (429, 500, 502, 503, 520-529).
- max_retries: Maximum retry attempts. Overrides the default of 2.
- timeout: Request timeout. Overrides the default of 60 seconds.
- transport_wrapper: Callable that wraps the sync transport, useful for adding middleware (e.g. caching, tracing).
- async_transport_wrapper: Callable that wraps the async transport.
- error_mapper: Callable that maps exceptions raised by the transport to downstream-specific exception types. Return the original exception to leave it unchanged.
- debug_hooks: If
True, hook exceptions are re-raised instead of being logged and suppressed. Useful during development.
48def __init__(self, user_agent_token=attr_dict['user_agent_token'].default, default_headers=NOTHING, event_hooks=attr_dict['event_hooks'].default, async_event_hooks=attr_dict['async_event_hooks'].default, retryable_status_codes=attr_dict['retryable_status_codes'].default, max_retries=attr_dict['max_retries'].default, timeout=attr_dict['timeout'].default, transport_wrapper=attr_dict['transport_wrapper'].default, async_transport_wrapper=attr_dict['async_transport_wrapper'].default, error_mapper=attr_dict['error_mapper'].default, debug_hooks=attr_dict['debug_hooks'].default): 49 _setattr = _cached_setattr_get(self) 50 _setattr('user_agent_token', user_agent_token) 51 if default_headers is not NOTHING: 52 _setattr('default_headers', default_headers) 53 else: 54 _setattr('default_headers', __attr_factory_default_headers()) 55 _setattr('event_hooks', event_hooks) 56 _setattr('async_event_hooks', async_event_hooks) 57 _setattr('retryable_status_codes', retryable_status_codes) 58 _setattr('max_retries', max_retries) 59 _setattr('timeout', timeout) 60 _setattr('transport_wrapper', transport_wrapper) 61 _setattr('async_transport_wrapper', async_transport_wrapper) 62 _setattr('error_mapper', error_mapper) 63 _setattr('debug_hooks', debug_hooks)
Method generated by attrs for class ClientExtension.
47@runtime_checkable 48class EventHook(Protocol): 49 """Protocol for observing HTTP requests and responses (sync). 50 51 Implement this protocol and pass instances via 52 `ClientExtension.event_hooks` to receive callbacks on every request. 53 54 Hook exceptions are logged and suppressed by default. Set 55 ``debug_hooks=True`` on `ClientExtension` to re-raise them instead. 56 """ 57 58 def on_request(self, request: httpx.Request) -> None: 59 """Called after the request is built but before it is sent. 60 61 Args: 62 request: The outgoing HTTP request. 63 """ 64 ... 65 66 def on_response(self, request: httpx.Request, response: httpx.Response) -> None: 67 """Called after a response is received. 68 69 Args: 70 request: The original HTTP request. 71 response: The HTTP response. The body has already been read. 72 """ 73 ...
Protocol for observing HTTP requests and responses (sync).
Implement this protocol and pass instances via
ClientExtension.event_hooks to receive callbacks on every request.
Hook exceptions are logged and suppressed by default. Set
debug_hooks=True on ClientExtension to re-raise them instead.
1953def _no_init_or_replace_init(self, *args, **kwargs): 1954 cls = type(self) 1955 1956 if cls._is_protocol: 1957 raise TypeError('Protocols cannot be instantiated') 1958 1959 # Already using a custom `__init__`. No need to calculate correct 1960 # `__init__` to call. This can lead to RecursionError. See bpo-45121. 1961 if cls.__init__ is not _no_init_or_replace_init: 1962 return 1963 1964 # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`. 1965 # The first instantiation of the subclass will call `_no_init_or_replace_init` which 1966 # searches for a proper new `__init__` in the MRO. The new `__init__` 1967 # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent 1968 # instantiation of the protocol subclass will thus use the new 1969 # `__init__` and no longer call `_no_init_or_replace_init`. 1970 for base in cls.__mro__: 1971 init = base.__dict__.get('__init__', _no_init_or_replace_init) 1972 if init is not _no_init_or_replace_init: 1973 cls.__init__ = init 1974 break 1975 else: 1976 # should not happen 1977 cls.__init__ = object.__init__ 1978 1979 cls.__init__(self, *args, **kwargs)
58 def on_request(self, request: httpx.Request) -> None: 59 """Called after the request is built but before it is sent. 60 61 Args: 62 request: The outgoing HTTP request. 63 """ 64 ...
Called after the request is built but before it is sent.
Arguments:
- request: The outgoing HTTP request.
66 def on_response(self, request: httpx.Request, response: httpx.Response) -> None: 67 """Called after a response is received. 68 69 Args: 70 request: The original HTTP request. 71 response: The HTTP response. The body has already been read. 72 """ 73 ...
Called after a response is received.
Arguments:
- request: The original HTTP request.
- response: The HTTP response. The body has already been read.
40def IonQClient( 41 *, 42 api_key: str | None = None, 43 base_url: str = DEFAULT_BASE_URL, 44 max_retries: int | None = None, 45 timeout: httpx.Timeout | None = None, 46 additional_user_agent: str | None = None, 47 extension: ClientExtension | None = None, 48 **kwargs, 49) -> AuthenticatedClient: 50 """Create an authenticated IonQ API client. 51 52 This is the recommended entry point for using the library. It handles 53 authentication, retry configuration, User-Agent construction, and transport 54 setup for both sync and async usage. 55 56 Args: 57 api_key: IonQ API key. If not provided, reads the ``IONQ_API_KEY`` 58 environment variable. 59 base_url: API base URL. Defaults to the IonQ production API. 60 max_retries: Maximum retry attempts for transient errors (429, 5xx). 61 Defaults to 2. Set to 0 to disable retries. 62 timeout: Request timeout as an ``httpx.Timeout`` instance. Defaults to 63 60 seconds with a 10-second connect timeout. 64 additional_user_agent: Extra token appended to the User-Agent header, 65 useful for identifying calling applications. 66 extension: A `ClientExtension` bundle provided by a downstream SDK. 67 Allows injecting hooks, custom headers, transport wrappers, and 68 error mappers. 69 **kwargs: Passed through to `AuthenticatedClient`. 70 71 Returns: 72 An `AuthenticatedClient` configured with retry transport and 73 authentication headers, ready for both sync and async API calls. 74 75 Raises: 76 ValueError: If no API key is provided and ``IONQ_API_KEY`` is not set. 77 78 Examples: 79 Basic usage with environment variable: 80 81 ```python 82 from ionq_core import IonQClient 83 from ionq_core.api.backends import get_backends 84 85 client = IonQClient() 86 backends = get_backends.sync(client=client) 87 ``` 88 89 Explicit configuration: 90 91 ```python 92 import httpx 93 from ionq_core import IonQClient 94 95 client = IonQClient( 96 api_key="your-api-key", 97 max_retries=5, 98 timeout=httpx.Timeout(30.0, connect=10.0), 99 ) 100 ``` 101 102 Async usage with context manager: 103 104 ```python 105 async with IonQClient() as client: 106 backends = await get_backends.asyncio(client=client) 107 ``` 108 """ 109 key = api_key or os.environ.get("IONQ_API_KEY") 110 if not key: 111 raise ValueError("api_key or IONQ_API_KEY environment variable required") 112 113 if not base_url.startswith("https://"): 114 warnings.warn( 115 f"base_url {base_url!r} does not use HTTPS. API keys will be sent in cleartext.", 116 UserWarning, 117 stacklevel=2, 118 ) 119 if kwargs.get("verify_ssl") is False: 120 warnings.warn( 121 "verify_ssl=False disables TLS certificate verification. " 122 "Your API key may be intercepted by a network attacker.", 123 UserWarning, 124 stacklevel=2, 125 ) 126 127 ext = extension or ClientExtension() 128 ua_parts = [ 129 f"ionq-core/{__version__}", 130 f"python/{platform.python_version()}", 131 f"httpx/{httpx.__version__}", 132 f"os/{platform.system().lower()}", 133 *filter(None, (additional_user_agent, ext.user_agent_token)), 134 ] 135 user_agent = " ".join(ua_parts) 136 effective_timeout = timeout or ext.timeout or DEFAULT_TIMEOUT 137 effective_retries = next(v for v in (max_retries, ext.max_retries, DEFAULT_MAX_RETRIES) if v is not None) 138 139 headers = {**ext.default_headers, "User-Agent": user_agent} 140 141 sync_transport = async_transport = build_transport( 142 effective_retries, 143 ext.retryable_status_codes or RETRYABLE_STATUS_CODES, 144 ) 145 146 if ext.event_hooks or ext.error_mapper: 147 sync_transport = HookTransport( 148 sync_transport, 149 ext.event_hooks, 150 debug=ext.debug_hooks, 151 error_mapper=ext.error_mapper, 152 ) 153 if ext.async_event_hooks or ext.error_mapper: 154 async_transport = HookTransport( 155 async_transport, 156 ext.async_event_hooks, 157 debug=ext.debug_hooks, 158 error_mapper=ext.error_mapper, 159 ) 160 if ext.transport_wrapper: 161 sync_transport = ext.transport_wrapper(sync_transport) 162 if ext.async_transport_wrapper: 163 async_transport = ext.async_transport_wrapper(async_transport) 164 165 client = AuthenticatedClient( 166 base_url=base_url, 167 token=key, 168 prefix=_AUTH_PREFIX, 169 auth_header_name=_AUTH_HEADER, 170 timeout=effective_timeout, 171 headers=headers, 172 httpx_args={"transport": sync_transport}, 173 **kwargs, 174 ) 175 # `set_async_httpx_client` bypasses `AuthenticatedClient`'s lazy auth-header 176 # injection (see generated `client.py::get_async_httpx_client`), so we merge 177 # `Authorization` in manually here. The `_verify_ssl` / `_follow_redirects` 178 # fields are private on the generated `AuthenticatedClient` but are the only 179 # way to mirror the caller's choices onto the async transport; do not add a 180 # public accessor in the hand-written layer — they belong to generated code. 181 client.set_async_httpx_client( 182 httpx.AsyncClient( 183 base_url=base_url, 184 headers={**headers, _AUTH_HEADER: f"{_AUTH_PREFIX} {key}"}, 185 timeout=effective_timeout, 186 transport=async_transport, 187 verify=client._verify_ssl, 188 follow_redirects=client._follow_redirects, 189 ) 190 ) 191 return client
Create an authenticated IonQ API client.
This is the recommended entry point for using the library. It handles authentication, retry configuration, User-Agent construction, and transport setup for both sync and async usage.
Arguments:
- api_key: IonQ API key. If not provided, reads the
IONQ_API_KEYenvironment variable. - base_url: API base URL. Defaults to the IonQ production API.
- max_retries: Maximum retry attempts for transient errors (429, 5xx). Defaults to 2. Set to 0 to disable retries.
- timeout: Request timeout as an
httpx.Timeoutinstance. Defaults to 60 seconds with a 10-second connect timeout. - additional_user_agent: Extra token appended to the User-Agent header, useful for identifying calling applications.
- extension: A
ClientExtensionbundle provided by a downstream SDK. Allows injecting hooks, custom headers, transport wrappers, and error mappers. - **kwargs: Passed through to
AuthenticatedClient.
Returns:
An
AuthenticatedClientconfigured with retry transport and authentication headers, ready for both sync and async API calls.
Raises:
- ValueError: If no API key is provided and
IONQ_API_KEYis not set.
Examples:
Basic usage with environment variable:
from ionq_core import IonQClient from ionq_core.api.backends import get_backends client = IonQClient() backends = get_backends.sync(client=client)Explicit configuration:
import httpx from ionq_core import IonQClient client = IonQClient( api_key="your-api-key", max_retries=5, timeout=httpx.Timeout(30.0, connect=10.0), )Async usage with context manager:
async with IonQClient() as client: backends = await get_backends.asyncio(client=client)
50class IonQError(Exception): 51 """Base exception for all IonQ errors. 52 53 Catch this to handle any error raised by the library, including connection 54 failures, API errors, polling timeouts, and job failures. 55 """
Base exception for all IonQ errors.
Catch this to handle any error raised by the library, including connection failures, API errors, polling timeouts, and job failures.
68class JobFailedError(IonQError): 69 """Raised when a polled job reaches ``"failed"`` status. 70 71 Attributes: 72 job_id: The ID of the failed job. 73 failure: The failure detail object from the API response, or ``None`` 74 if no failure details were provided. 75 """ 76 77 def __init__(self, job_id: str, failure: object) -> None: 78 self.job_id = job_id 79 self.failure = failure 80 super().__init__(f"Job {job_id} failed: {failure}")
Raised when a polled job reaches "failed" status.
Attributes:
- job_id: The ID of the failed job.
- failure: The failure detail object from the API response, or
Noneif no failure details were provided.
51class JobTimeoutError(IonQError): 52 """Raised when a job does not reach a terminal state within the timeout. 53 54 Attributes: 55 job_id: The ID of the job that timed out. 56 timeout: The timeout value in seconds that was exceeded. 57 last_status: The last observed status before the timeout 58 (e.g. ``"running"``, ``"submitted"``). 59 """ 60 61 def __init__(self, job_id: str, timeout: float, last_status: str) -> None: 62 self.job_id = job_id 63 self.timeout = timeout 64 self.last_status = last_status 65 super().__init__(f"Job {job_id} did not complete within {timeout}s (last status: {last_status})")
Raised when a job does not reach a terminal state within the timeout.
Attributes:
- job_id: The ID of the job that timed out.
- timeout: The timeout value in seconds that was exceeded.
- last_status: The last observed status before the timeout
(e.g.
"running","submitted").
117class NotFoundError(APIError): 118 """Raised on ``404 Not Found``. 119 120 The requested resource (job, session, backend, etc.) does not exist. 121 """
Raised on 404 Not Found.
The requested resource (job, session, backend, etc.) does not exist.
Inherited Members
110class PermissionDeniedError(APIError): 111 """Raised on ``403 Forbidden``. 112 113 The API key is valid but lacks permission for the requested operation. 114 """
Raised on 403 Forbidden.
The API key is valid but lacks permission for the requested operation.
Inherited Members
132class RateLimitError(APIError): 133 """Raised on ``429 Too Many Requests``. 134 135 The client has exceeded the API rate limit. The ``retry_after`` attribute 136 indicates how many seconds to wait before retrying, if the server provided 137 a ``Retry-After`` header. 138 139 Attributes: 140 retry_after: Seconds to wait before retrying, or ``None`` if the 141 server did not include a ``Retry-After`` header. 142 """ 143 144 def __init__( 145 self, 146 status_code: int = 429, 147 body: dict | str | None = None, 148 message: str | None = None, 149 retry_after: float | None = None, 150 *, 151 request_id: str | None = None, 152 ) -> None: 153 super().__init__(status_code, body, message, request_id=request_id) 154 self.retry_after = retry_after
Raised on 429 Too Many Requests.
The client has exceeded the API rate limit. The retry_after attribute
indicates how many seconds to wait before retrying, if the server provided
a Retry-After header.
Attributes:
- retry_after: Seconds to wait before retrying, or
Noneif the server did not include aRetry-Afterheader.
144 def __init__( 145 self, 146 status_code: int = 429, 147 body: dict | str | None = None, 148 message: str | None = None, 149 retry_after: float | None = None, 150 *, 151 request_id: str | None = None, 152 ) -> None: 153 super().__init__(status_code, body, message, request_id=request_id) 154 self.retry_after = retry_after
Inherited Members
157class ServerError(APIError): 158 """Raised on ``5xx`` server errors. 159 160 These are typically transient and are automatically retried by the default 161 transport (see `IonQClient`). 162 """
Raised on 5xx server errors.
These are typically transient and are automatically retried by the default
transport (see IonQClient).
Inherited Members
49class SessionManager: 50 """Convenience wrapper around session create / end / status APIs. 51 52 Can be used as both a sync and async context manager. On exit the 53 session is automatically ended. Exceptions during close are logged 54 and suppressed so that cleanup does not mask the original error. 55 56 Args: 57 client: An authenticated API client. 58 backend: The backend to create a session on (e.g. ``"qpu.aria-1"``). 59 max_jobs: Optional maximum number of jobs for this session. 60 max_time: Optional maximum session duration in minutes. 61 max_cost: Optional maximum cost in USD for the session. 62 63 Examples: 64 Sync context manager: 65 66 ```python 67 with SessionManager(client, "qpu.aria-1", max_jobs=10) as session: 68 print(session.session_id) 69 ``` 70 71 Async context manager: 72 73 ```python 74 async with SessionManager(client, "qpu.aria-1") as session: 75 print(session.session_id) 76 ``` 77 """ 78 79 def __init__( 80 self, 81 client: AuthenticatedClient, 82 backend: str, 83 *, 84 max_jobs: int | None = None, 85 max_time: int | None = None, 86 max_cost: float | None = None, 87 ) -> None: 88 self._client = client 89 self._backend = backend 90 self._max_jobs = max_jobs 91 self._max_time = max_time 92 self._max_cost = max_cost 93 self._session_id: str | None = None 94 95 @classmethod 96 def from_id(cls, client: AuthenticatedClient, session_id: str) -> SessionManager: 97 """Reconnect to an existing session without creating a new one. 98 99 This is useful for resuming work with a session that was created 100 in a previous process or by another client. 101 102 Args: 103 client: An authenticated API client. 104 session_id: The ID of the existing session. 105 106 Returns: 107 A `SessionManager` bound to the given session ID. The ``backend`` 108 field will be empty since it is not needed for status checks 109 or ending the session. 110 """ 111 mgr = cls(client, backend="") 112 mgr._session_id = session_id 113 return mgr 114 115 @property 116 def session_id(self) -> str | None: 117 """The session ID, or ``None`` if `open` has not been called.""" 118 return self._session_id 119 120 def _build_settings(self) -> SessionSettingsRequest | Unset: 121 kw: dict = {} 122 if self._max_jobs is not None: 123 kw["job_count_limit"] = self._max_jobs 124 if self._max_time is not None: 125 kw["duration_limit_min"] = self._max_time 126 if self._max_cost is not None: 127 kw["cost_limit"] = SessionCostLimit(unit="usd", value=self._max_cost) 128 return SessionSettingsRequest(**kw) if kw else UNSET 129 130 def open(self) -> None: 131 """Create a new session on the configured backend. 132 133 Raises: 134 IonQError: If a session is already open or creation fails. 135 """ 136 if self._session_id is not None: 137 raise IonQError("Session already open") 138 body = CreateSessionRequest(backend=self._backend, settings=self._build_settings()) 139 session = create_session.sync(client=self._client, body=body) 140 if session is None: 141 raise IonQError("Failed to create session") 142 self._session_id = session.id 143 logger.info("Opened session %s", self._session_id) 144 145 def close(self) -> None: 146 """End the session. Suppresses exceptions so cleanup is safe.""" 147 if self._session_id is None: 148 return 149 try: 150 end_session.sync(session_id=self._session_id, client=self._client) 151 logger.info("Closed session %s", self._session_id) 152 except Exception: 153 logger.warning("Failed to end session %s", self._session_id, exc_info=True) 154 155 def status(self) -> str: 156 """Get the current session status (e.g. ``"created"``, ``"started"``, ``"ended"``). 157 158 Raises: 159 IonQError: If no session is open or the status fetch fails. 160 """ 161 if self._session_id is None: 162 raise IonQError("No session ID; call open() first") 163 session = get_session.sync(session_id=self._session_id, client=self._client) 164 if session is None: 165 raise IonQError(f"Failed to fetch session {self._session_id}") 166 return session.status 167 168 async def async_open(self) -> None: 169 """Async version of `open`.""" 170 if self._session_id is not None: 171 raise IonQError("Session already open") 172 body = CreateSessionRequest(backend=self._backend, settings=self._build_settings()) 173 session = await create_session.asyncio(client=self._client, body=body) 174 if session is None: 175 raise IonQError("Failed to create session") 176 self._session_id = session.id 177 logger.info("Opened session %s", self._session_id) 178 179 async def async_close(self) -> None: 180 """End the session (async). Suppresses exceptions so cleanup is safe.""" 181 if self._session_id is None: 182 return 183 try: 184 await end_session.asyncio(session_id=self._session_id, client=self._client) 185 logger.info("Closed session %s", self._session_id) 186 except Exception: 187 logger.warning("Failed to end session %s", self._session_id, exc_info=True) 188 189 async def async_status(self) -> str: 190 """Async version of `status`.""" 191 if self._session_id is None: 192 raise IonQError("No session ID; call open() first") 193 session = await get_session.asyncio(session_id=self._session_id, client=self._client) 194 if session is None: 195 raise IonQError(f"Failed to fetch session {self._session_id}") 196 return session.status 197 198 def __enter__(self) -> SessionManager: 199 self.open() 200 return self 201 202 def __exit__(self, *exc: object) -> None: 203 self.close() 204 205 async def __aenter__(self) -> SessionManager: 206 await self.async_open() 207 return self 208 209 async def __aexit__(self, *exc: object) -> None: 210 await self.async_close()
Convenience wrapper around session create / end / status APIs.
Can be used as both a sync and async context manager. On exit the session is automatically ended. Exceptions during close are logged and suppressed so that cleanup does not mask the original error.
Arguments:
- client: An authenticated API client.
- backend: The backend to create a session on (e.g.
"qpu.aria-1"). - max_jobs: Optional maximum number of jobs for this session.
- max_time: Optional maximum session duration in minutes.
- max_cost: Optional maximum cost in USD for the session.
Examples:
Sync context manager:
with SessionManager(client, "qpu.aria-1", max_jobs=10) as session: print(session.session_id)Async context manager:
async with SessionManager(client, "qpu.aria-1") as session: print(session.session_id)
79 def __init__( 80 self, 81 client: AuthenticatedClient, 82 backend: str, 83 *, 84 max_jobs: int | None = None, 85 max_time: int | None = None, 86 max_cost: float | None = None, 87 ) -> None: 88 self._client = client 89 self._backend = backend 90 self._max_jobs = max_jobs 91 self._max_time = max_time 92 self._max_cost = max_cost 93 self._session_id: str | None = None
95 @classmethod 96 def from_id(cls, client: AuthenticatedClient, session_id: str) -> SessionManager: 97 """Reconnect to an existing session without creating a new one. 98 99 This is useful for resuming work with a session that was created 100 in a previous process or by another client. 101 102 Args: 103 client: An authenticated API client. 104 session_id: The ID of the existing session. 105 106 Returns: 107 A `SessionManager` bound to the given session ID. The ``backend`` 108 field will be empty since it is not needed for status checks 109 or ending the session. 110 """ 111 mgr = cls(client, backend="") 112 mgr._session_id = session_id 113 return mgr
Reconnect to an existing session without creating a new one.
This is useful for resuming work with a session that was created in a previous process or by another client.
Arguments:
- client: An authenticated API client.
- session_id: The ID of the existing session.
Returns:
A
SessionManagerbound to the given session ID. Thebackendfield will be empty since it is not needed for status checks or ending the session.
115 @property 116 def session_id(self) -> str | None: 117 """The session ID, or ``None`` if `open` has not been called.""" 118 return self._session_id
The session ID, or None if open has not been called.
130 def open(self) -> None: 131 """Create a new session on the configured backend. 132 133 Raises: 134 IonQError: If a session is already open or creation fails. 135 """ 136 if self._session_id is not None: 137 raise IonQError("Session already open") 138 body = CreateSessionRequest(backend=self._backend, settings=self._build_settings()) 139 session = create_session.sync(client=self._client, body=body) 140 if session is None: 141 raise IonQError("Failed to create session") 142 self._session_id = session.id 143 logger.info("Opened session %s", self._session_id)
Create a new session on the configured backend.
Raises:
- IonQError: If a session is already open or creation fails.
145 def close(self) -> None: 146 """End the session. Suppresses exceptions so cleanup is safe.""" 147 if self._session_id is None: 148 return 149 try: 150 end_session.sync(session_id=self._session_id, client=self._client) 151 logger.info("Closed session %s", self._session_id) 152 except Exception: 153 logger.warning("Failed to end session %s", self._session_id, exc_info=True)
End the session. Suppresses exceptions so cleanup is safe.
155 def status(self) -> str: 156 """Get the current session status (e.g. ``"created"``, ``"started"``, ``"ended"``). 157 158 Raises: 159 IonQError: If no session is open or the status fetch fails. 160 """ 161 if self._session_id is None: 162 raise IonQError("No session ID; call open() first") 163 session = get_session.sync(session_id=self._session_id, client=self._client) 164 if session is None: 165 raise IonQError(f"Failed to fetch session {self._session_id}") 166 return session.status
Get the current session status (e.g. "created", "started", "ended").
Raises:
- IonQError: If no session is open or the status fetch fails.
168 async def async_open(self) -> None: 169 """Async version of `open`.""" 170 if self._session_id is not None: 171 raise IonQError("Session already open") 172 body = CreateSessionRequest(backend=self._backend, settings=self._build_settings()) 173 session = await create_session.asyncio(client=self._client, body=body) 174 if session is None: 175 raise IonQError("Failed to create session") 176 self._session_id = session.id 177 logger.info("Opened session %s", self._session_id)
Async version of open.
179 async def async_close(self) -> None: 180 """End the session (async). Suppresses exceptions so cleanup is safe.""" 181 if self._session_id is None: 182 return 183 try: 184 await end_session.asyncio(session_id=self._session_id, client=self._client) 185 logger.info("Closed session %s", self._session_id) 186 except Exception: 187 logger.warning("Failed to end session %s", self._session_id, exc_info=True)
End the session (async). Suppresses exceptions so cleanup is safe.
189 async def async_status(self) -> str: 190 """Async version of `status`.""" 191 if self._session_id is None: 192 raise IonQError("No session ID; call open() first") 193 session = await get_session.asyncio(session_id=self._session_id, client=self._client) 194 if session is None: 195 raise IonQError(f"Failed to fetch session {self._session_id}") 196 return session.status
Async version of status.
106def aiter_jobs( 107 client: AuthenticatedClient, 108 *, 109 status: JobStatus | Unset = UNSET, 110 target: str | Unset = UNSET, 111 session_id: str | Unset = UNSET, 112 submitter_id: str | Unset = UNSET, 113 limit: int | Unset = UNSET, 114) -> AsyncIterator[Job]: 115 """Async version of `iter_jobs`. 116 117 Args: 118 client: An authenticated API client. 119 status: Filter by job status. 120 target: Filter by backend target name. 121 session_id: Filter by session ID. 122 submitter_id: Filter by submitter user ID. 123 limit: Maximum number of jobs per page. 124 125 Yields: 126 Individual job objects across all pages. 127 128 Raises: 129 IonQError: If the API returns a ``None`` response. 130 """ 131 return _apaginate( 132 get_jobs.asyncio, 133 "jobs", 134 client=client, 135 status=status, 136 target=target, 137 session_id=session_id, 138 submitter_id=submitter_id, 139 limit=limit, 140 )
Async version of iter_jobs.
Arguments:
- client: An authenticated API client.
- status: Filter by job status.
- target: Filter by backend target name.
- session_id: Filter by session ID.
- submitter_id: Filter by submitter user ID.
- limit: Maximum number of jobs per page.
Yields:
Individual job objects across all pages.
Raises:
- IonQError: If the API returns a
Noneresponse.
182def aiter_session_jobs( 183 client: AuthenticatedClient, 184 session_id: str, 185 *, 186 status: JobStatus | Unset = UNSET, 187 target: str | Unset = UNSET, 188 submitter_id: str | Unset = UNSET, 189 limit: int | Unset = UNSET, 190) -> AsyncIterator[Job]: 191 """Async version of `iter_session_jobs`. 192 193 Args: 194 client: An authenticated API client. 195 session_id: The session ID to list jobs for. 196 status: Filter by job status. 197 target: Filter by backend target name. 198 submitter_id: Filter by submitter user ID. 199 limit: Maximum number of jobs per page. 200 201 Yields: 202 Individual job objects across all pages. 203 204 Raises: 205 IonQError: If the API returns a ``None`` response. 206 """ 207 return _apaginate( 208 get_session_jobs.asyncio, 209 "session jobs", 210 session_id, 211 client=client, 212 status=status, 213 target=target, 214 submitter_id=submitter_id, 215 limit=limit, 216 )
Async version of iter_session_jobs.
Arguments:
- client: An authenticated API client.
- session_id: The session ID to list jobs for.
- status: Filter by job status.
- target: Filter by backend target name.
- submitter_id: Filter by submitter user ID.
- limit: Maximum number of jobs per page.
Yields:
Individual job objects across all pages.
Raises:
- IonQError: If the API returns a
Noneresponse.
140async def async_wait_for_job( 141 client: AuthenticatedClient, 142 job_id: str, 143 *, 144 poll_interval: float = _DEFAULT_INTERVAL, 145 timeout: float = _DEFAULT_TIMEOUT, 146 raise_on_failure: bool = True, 147) -> GetJobResponse: 148 """Async version of `wait_for_job`. 149 150 Args: 151 client: An authenticated API client. 152 job_id: The UUID of the job to poll. 153 poll_interval: Initial interval between polls in seconds. 154 Defaults to 1.0. 155 timeout: Maximum total wait time in seconds. Defaults to 300. 156 raise_on_failure: If ``True``, raise `JobFailedError` on failure. 157 158 Returns: 159 The final job response once a terminal state is reached. 160 161 Raises: 162 JobTimeoutError: If the job does not finish within ``timeout``. 163 JobFailedError: If ``raise_on_failure`` is ``True`` and the job fails. 164 IonQError: If the API returns a ``None`` response. 165 """ 166 deadline = time.monotonic() + timeout 167 interval = poll_interval 168 while True: 169 job = await get_job.asyncio(uuid=job_id, client=client) 170 if job is None: 171 raise IonQError(f"Failed to fetch job {job_id}") 172 logger.debug("Job %s status: %s", job_id, job.status) 173 if _check_terminal(job, raise_on_failure): 174 return job 175 if time.monotonic() >= deadline: 176 raise JobTimeoutError(job_id, timeout, job.status) 177 await asyncio.sleep(max(0, min(interval, deadline - time.monotonic()))) 178 interval = min(interval * _BACKOFF_FACTOR, _MAX_INTERVAL)
Async version of wait_for_job.
Arguments:
- client: An authenticated API client.
- job_id: The UUID of the job to poll.
- poll_interval: Initial interval between polls in seconds. Defaults to 1.0.
- timeout: Maximum total wait time in seconds. Defaults to 300.
- raise_on_failure: If
True, raiseJobFailedErroron failure.
Returns:
The final job response once a terminal state is reached.
Raises:
- JobTimeoutError: If the job does not finish within
timeout. - JobFailedError: If
raise_on_failureisTrueand the job fails. - IonQError: If the API returns a
Noneresponse.
74def gpi2_matrix(phi: float) -> Matrix2x2: 75 """Single-qubit GPI2 gate (pi/2 rotation about an axis in the XY plane). 76 77 Args: 78 phi: Phase angle in turns (fractions of 2*pi) defining the 79 rotation axis in the XY plane. 80 81 Returns: 82 A `Matrix2x2` unitary matrix. 83 """ 84 e = cmath.exp(1j * _2PI * phi) 85 s = 1 / math.sqrt(2) 86 return ((s, -1j * s / e), (-1j * s * e, s))
Single-qubit GPI2 gate (pi/2 rotation about an axis in the XY plane).
Arguments:
- phi: Phase angle in turns (fractions of 2*pi) defining the rotation axis in the XY plane.
Returns:
A
Matrix2x2unitary matrix.
51def gpi_matrix(phi: float) -> Matrix2x2: 52 r"""Single-qubit GPI gate. 53 54 Matrix form: ``[[0, e^{-i*2*pi*phi}], [e^{i*2*pi*phi}, 0]]`` 55 56 At ``phi=0`` this is the Pauli X gate. 57 58 Args: 59 phi: Phase angle in turns (fractions of 2*pi). 60 61 Returns: 62 A `Matrix2x2` unitary matrix. 63 64 Examples: 65 ```python 66 >>> gpi_matrix(0) # Pauli X 67 ((0, (1+0j)), ((1+0j), 0)) 68 ``` 69 """ 70 e = cmath.exp(1j * _2PI * phi) 71 return ((0, 1 / e), (e, 0))
Single-qubit GPI gate.
Matrix form: [[0, e^{-i*2*pi*phi}], [e^{i*2*pi*phi}, 0]]
At phi=0 this is the Pauli X gate.
Arguments:
- phi: Phase angle in turns (fractions of 2*pi).
Returns:
A
Matrix2x2unitary matrix.
Examples:
>>> gpi_matrix(0) # Pauli X ((0, (1+0j)), ((1+0j), 0))
68def iter_jobs( 69 client: AuthenticatedClient, 70 *, 71 status: JobStatus | Unset = UNSET, 72 target: str | Unset = UNSET, 73 session_id: str | Unset = UNSET, 74 submitter_id: str | Unset = UNSET, 75 limit: int | Unset = UNSET, 76) -> Iterator[Job]: 77 """Iterate over all jobs, automatically following pagination cursors. 78 79 Args: 80 client: An authenticated API client. 81 status: Filter by job status (e.g. ``"completed"``, ``"failed"``). 82 target: Filter by backend target name. 83 session_id: Filter by session ID. 84 submitter_id: Filter by submitter user ID. 85 limit: Maximum number of jobs per page (server default applies 86 if unset). 87 88 Yields: 89 Individual job objects across all pages. 90 91 Raises: 92 IonQError: If the API returns a ``None`` response. 93 """ 94 return _paginate( 95 get_jobs.sync, 96 "jobs", 97 client=client, 98 status=status, 99 target=target, 100 session_id=session_id, 101 submitter_id=submitter_id, 102 limit=limit, 103 )
Iterate over all jobs, automatically following pagination cursors.
Arguments:
- client: An authenticated API client.
- status: Filter by job status (e.g.
"completed","failed"). - target: Filter by backend target name.
- session_id: Filter by session ID.
- submitter_id: Filter by submitter user ID.
- limit: Maximum number of jobs per page (server default applies if unset).
Yields:
Individual job objects across all pages.
Raises:
- IonQError: If the API returns a
Noneresponse.
143def iter_session_jobs( 144 client: AuthenticatedClient, 145 session_id: str, 146 *, 147 status: JobStatus | Unset = UNSET, 148 target: str | Unset = UNSET, 149 submitter_id: str | Unset = UNSET, 150 limit: int | Unset = UNSET, 151) -> Iterator[Job]: 152 """Iterate over all jobs in a specific session. 153 154 Like `iter_jobs`, but scoped to a single session. 155 156 Args: 157 client: An authenticated API client. 158 session_id: The session ID to list jobs for. 159 status: Filter by job status. 160 target: Filter by backend target name. 161 submitter_id: Filter by submitter user ID. 162 limit: Maximum number of jobs per page. 163 164 Yields: 165 Individual job objects across all pages. 166 167 Raises: 168 IonQError: If the API returns a ``None`` response. 169 """ 170 return _paginate( 171 get_session_jobs.sync, 172 "session jobs", 173 session_id, 174 client=client, 175 status=status, 176 target=target, 177 submitter_id=submitter_id, 178 limit=limit, 179 )
Iterate over all jobs in a specific session.
Like iter_jobs, but scoped to a single session.
Arguments:
- client: An authenticated API client.
- session_id: The session ID to list jobs for.
- status: Filter by job status.
- target: Filter by backend target name.
- submitter_id: Filter by submitter user ID.
- limit: Maximum number of jobs per page.
Yields:
Individual job objects across all pages.
Raises:
- IonQError: If the API returns a
Noneresponse.
89def ms_matrix(phi0: float, phi1: float, angle: float = 0.25) -> Matrix4x4: 90 """Two-qubit Molmer-Sorensen (MS) gate. 91 92 The default ``angle=0.25`` produces a maximally-entangling gate. 93 94 Args: 95 phi0: Frame rotation phase for qubit 0 in turns. 96 phi1: Frame rotation phase for qubit 1 in turns. 97 angle: Interaction angle in units of pi. Defaults to 0.25 98 (i.e. pi/4 radians). 99 100 Returns: 101 A `Matrix4x4` unitary matrix. 102 103 Examples: 104 ```python 105 >>> ms_matrix(0, 0) # maximally-entangling MS gate 106 >>> ms_matrix(0, 0, 0.125) # partial entanglement 107 ``` 108 """ 109 a = math.pi * angle 110 ca, sa = math.cos(a), math.sin(a) 111 ep = cmath.exp(1j * _2PI * (phi0 + phi1)) 112 em = cmath.exp(1j * _2PI * (phi0 - phi1)) 113 return ( 114 (ca, 0, 0, -1j * sa / ep), 115 (0, ca, -1j * sa / em, 0), 116 (0, -1j * sa * em, ca, 0), 117 (-1j * sa * ep, 0, 0, ca), 118 )
Two-qubit Molmer-Sorensen (MS) gate.
The default angle=0.25 produces a maximally-entangling gate.
Arguments:
- phi0: Frame rotation phase for qubit 0 in turns.
- phi1: Frame rotation phase for qubit 1 in turns.
- angle: Interaction angle in units of pi. Defaults to 0.25 (i.e. pi/4 radians).
Returns:
A
Matrix4x4unitary matrix.
Examples:
>>> ms_matrix(0, 0) # maximally-entangling MS gate >>> ms_matrix(0, 0, 0.125) # partial entanglement
92def wait_for_job( 93 client: AuthenticatedClient, 94 job_id: str, 95 *, 96 poll_interval: float = _DEFAULT_INTERVAL, 97 timeout: float = _DEFAULT_TIMEOUT, 98 raise_on_failure: bool = True, 99) -> GetJobResponse: 100 """Poll a job until it reaches a terminal state. 101 102 Terminal states are ``"completed"``, ``"failed"``, and ``"canceled"``. 103 Polling starts at ``poll_interval`` and increases by 1.5x each 104 iteration, capped at 30 seconds. 105 106 Args: 107 client: An authenticated API client. 108 job_id: The UUID of the job to poll. 109 poll_interval: Initial interval between polls in seconds. 110 Defaults to 1.0. 111 timeout: Maximum total wait time in seconds. Defaults to 300 112 (5 minutes). 113 raise_on_failure: If ``True`` (the default), raise `JobFailedError` 114 when the job status is ``"failed"``. If ``False``, return the 115 failed job response instead. 116 117 Returns: 118 The final job response once a terminal state is reached. 119 120 Raises: 121 JobTimeoutError: If the job does not finish within ``timeout``. 122 JobFailedError: If ``raise_on_failure`` is ``True`` and the job fails. 123 IonQError: If the API returns a ``None`` response. 124 """ 125 deadline = time.monotonic() + timeout 126 interval = poll_interval 127 while True: 128 job = get_job.sync(uuid=job_id, client=client) 129 if job is None: 130 raise IonQError(f"Failed to fetch job {job_id}") 131 logger.debug("Job %s status: %s", job_id, job.status) 132 if _check_terminal(job, raise_on_failure): 133 return job 134 if time.monotonic() >= deadline: 135 raise JobTimeoutError(job_id, timeout, job.status) 136 time.sleep(max(0, min(interval, deadline - time.monotonic()))) 137 interval = min(interval * _BACKOFF_FACTOR, _MAX_INTERVAL)
Poll a job until it reaches a terminal state.
Terminal states are "completed", "failed", and "canceled".
Polling starts at poll_interval and increases by 1.5x each
iteration, capped at 30 seconds.
Arguments:
- client: An authenticated API client.
- job_id: The UUID of the job to poll.
- poll_interval: Initial interval between polls in seconds. Defaults to 1.0.
- timeout: Maximum total wait time in seconds. Defaults to 300 (5 minutes).
- raise_on_failure: If
True(the default), raiseJobFailedErrorwhen the job status is"failed". IfFalse, return the failed job response instead.
Returns:
The final job response once a terminal state is reached.
Raises:
- JobTimeoutError: If the job does not finish within
timeout. - JobFailedError: If
raise_on_failureisTrueand the job fails. - IonQError: If the API returns a
Noneresponse.
121def zz_matrix(angle: float) -> Matrix4x4: 122 """Two-qubit ZZ interaction gate. 123 124 Diagonal matrix: ``diag(e^{-i*pi*a}, e^{i*pi*a}, e^{i*pi*a}, e^{-i*pi*a})`` 125 126 At ``angle=0`` this is the identity gate. 127 128 Args: 129 angle: Interaction angle in units of pi. 130 131 Returns: 132 A `Matrix4x4` unitary matrix. 133 """ 134 em = cmath.exp(-1j * math.pi * angle) 135 ep = cmath.exp(1j * math.pi * angle) 136 return ( 137 (em, 0, 0, 0), 138 (0, ep, 0, 0), 139 (0, 0, ep, 0), 140 (0, 0, 0, em), 141 )
Two-qubit ZZ interaction gate.
Diagonal matrix: diag(e^{-i*pi*a}, e^{i*pi*a}, e^{i*pi*a}, e^{-i*pi*a})
At angle=0 this is the identity gate.
Arguments:
- angle: Interaction angle in units of pi.
Returns:
A
Matrix4x4unitary matrix.