classiq 0.59.0__py3-none-any.whl → 0.60.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  from typing import Any, Optional, Protocol, TypeVar
3
3
 
4
+ import httpx
4
5
  import pydantic
5
6
 
6
7
  import classiq.interface.executor.execution_result
@@ -70,13 +71,18 @@ class ApiWrapper:
70
71
  url: str,
71
72
  model: pydantic.BaseModel,
72
73
  use_versioned_url: bool = True,
74
+ http_client: Optional[httpx.AsyncClient] = None,
73
75
  ) -> dict:
74
76
  # TODO: we can't use model.dict() - it doesn't serialize complex class.
75
77
  # This was added because JSON serializer doesn't serialize complex type, and pydantic does.
76
78
  # We should add support for smarter json serialization.
77
79
  body = json.loads(model.model_dump_json())
78
80
  return await cls._call_task(
79
- http_method, url, body, use_versioned_url=use_versioned_url
81
+ http_method,
82
+ url,
83
+ body,
84
+ use_versioned_url=use_versioned_url,
85
+ http_client=http_client,
80
86
  )
81
87
 
82
88
  @classmethod
@@ -89,6 +95,7 @@ class ApiWrapper:
89
95
  use_versioned_url: bool = True,
90
96
  headers: Optional[dict[str, str]] = None,
91
97
  allow_none: bool = False,
98
+ http_client: Optional[httpx.AsyncClient] = None,
92
99
  ) -> dict:
93
100
  res: Any = await client().call_api(
94
101
  http_method=http_method,
@@ -97,6 +104,7 @@ class ApiWrapper:
97
104
  headers=headers,
98
105
  params=params,
99
106
  use_versioned_url=use_versioned_url,
107
+ http_client=http_client,
100
108
  )
101
109
  if allow_none and res is None:
102
110
  return {}
@@ -106,25 +114,34 @@ class ApiWrapper:
106
114
 
107
115
  @classmethod
108
116
  async def call_generation_task(
109
- cls, model: Model
117
+ cls,
118
+ model: Model,
119
+ http_client: Optional[httpx.AsyncClient] = None,
110
120
  ) -> generator_result.QuantumProgram:
111
121
  poller = JobPoller(base_url=routes.TASKS_GENERATE_FULL_PATH)
112
- result = await poller.run_pydantic(model, timeout_sec=None)
122
+ result = await poller.run_pydantic(
123
+ model, timeout_sec=None, http_client=http_client
124
+ )
113
125
  return _parse_job_response(result, generator_result.QuantumProgram)
114
126
 
115
127
  @classmethod
116
128
  async def call_convert_quantum_program(
117
- cls, circuit: generator_result.QuantumProgram
129
+ cls,
130
+ circuit: generator_result.QuantumProgram,
131
+ http_client: Optional[httpx.AsyncClient] = None,
118
132
  ) -> dict:
119
133
  return await cls._call_task_pydantic(
120
134
  http_method=HTTPMethod.POST,
121
135
  url=routes.CONVERSION_GENERATED_CIRCUIT_TO_EXECUTION_INPUT_FULL,
122
136
  model=circuit,
137
+ http_client=http_client,
123
138
  )
124
139
 
125
140
  @classmethod
126
141
  async def call_execute_execution_input(
127
- cls, execution_input: dict
142
+ cls,
143
+ execution_input: dict,
144
+ http_client: Optional[httpx.AsyncClient] = None,
128
145
  ) -> execution_request.ExecutionJobDetails:
129
146
  headers = {
130
147
  _ACCEPT_HEADER: "v1",
@@ -136,6 +153,7 @@ class ApiWrapper:
136
153
  url=routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH,
137
154
  body=execution_input,
138
155
  use_versioned_url=False,
156
+ http_client=http_client,
139
157
  )
140
158
  return execution_request.ExecutionJobDetails.model_validate(data)
141
159
 
@@ -143,6 +161,7 @@ class ApiWrapper:
143
161
  async def call_get_execution_job_details(
144
162
  cls,
145
163
  job_id: JobID,
164
+ http_client: Optional[httpx.AsyncClient] = None,
146
165
  ) -> execution_request.ExecutionJobDetails:
147
166
  headers = {_ACCEPT_HEADER: "v1"}
148
167
  data = await cls._call_task(
@@ -150,6 +169,7 @@ class ApiWrapper:
150
169
  headers=headers,
151
170
  url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}",
152
171
  use_versioned_url=False,
172
+ http_client=http_client,
153
173
  )
154
174
  return execution_request.ExecutionJobDetails.model_validate(data)
155
175
 
@@ -158,12 +178,14 @@ class ApiWrapper:
158
178
  cls,
159
179
  job_id: JobID,
160
180
  version: str,
181
+ http_client: Optional[httpx.AsyncClient] = None,
161
182
  ) -> classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults:
162
183
  data = await cls._call_task(
163
184
  http_method=HTTPMethod.GET,
164
185
  url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}/result",
165
186
  use_versioned_url=False,
166
187
  headers={CLASSIQ_ACCEPT_HEADER: version},
188
+ http_client=http_client,
167
189
  )
168
190
  return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.model_validate(
169
191
  data
@@ -174,6 +196,7 @@ class ApiWrapper:
174
196
  cls,
175
197
  job_id: JobID,
176
198
  name: str,
199
+ http_client: Optional[httpx.AsyncClient] = None,
177
200
  ) -> ExecutionJobDetailsV1:
178
201
  data = await cls._call_task(
179
202
  http_method=HTTPMethod.PATCH,
@@ -182,6 +205,7 @@ class ApiWrapper:
182
205
  "name": name,
183
206
  },
184
207
  use_versioned_url=False,
208
+ http_client=http_client,
185
209
  )
186
210
  return ExecutionJobDetailsV1.model_validate(data)
187
211
 
@@ -189,12 +213,14 @@ class ApiWrapper:
189
213
  async def call_cancel_execution_job(
190
214
  cls,
191
215
  job_id: JobID,
216
+ http_client: Optional[httpx.AsyncClient] = None,
192
217
  ) -> None:
193
218
  await cls._call_task(
194
219
  http_method=HTTPMethod.PUT,
195
220
  url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}/cancel",
196
221
  use_versioned_url=False,
197
222
  allow_none=True,
223
+ http_client=http_client,
198
224
  )
199
225
 
200
226
  @classmethod
@@ -202,6 +228,7 @@ class ApiWrapper:
202
228
  cls,
203
229
  offset: int,
204
230
  limit: int,
231
+ http_client: Optional[httpx.AsyncClient] = None,
205
232
  ) -> ExecutionJobsQueryResultsV1:
206
233
  data = await cls._call_task(
207
234
  http_method=HTTPMethod.GET,
@@ -211,73 +238,92 @@ class ApiWrapper:
211
238
  "limit": limit,
212
239
  },
213
240
  use_versioned_url=False,
241
+ http_client=http_client,
214
242
  )
215
243
  return ExecutionJobsQueryResultsV1.model_validate(data)
216
244
 
217
245
  @classmethod
218
246
  async def call_analysis_task(
219
- cls, params: analysis_params.AnalysisParams
247
+ cls,
248
+ params: analysis_params.AnalysisParams,
249
+ http_client: Optional[httpx.AsyncClient] = None,
220
250
  ) -> analysis_result.Analysis:
221
251
  data = await cls._call_task_pydantic(
222
252
  http_method=HTTPMethod.POST,
223
253
  url=routes.ANALYZER_FULL_PATH,
224
254
  model=params,
255
+ http_client=http_client,
225
256
  )
226
257
 
227
258
  return analysis_result.Analysis.model_validate(data)
228
259
 
229
260
  @classmethod
230
261
  async def call_analyzer_app(
231
- cls, params: generator_result.QuantumProgram
262
+ cls,
263
+ params: generator_result.QuantumProgram,
264
+ http_client: Optional[httpx.AsyncClient] = None,
232
265
  ) -> analysis_result.DataID:
233
266
  data = await cls._call_task_pydantic(
234
267
  http_method=HTTPMethod.POST,
235
268
  url=routes.ANALYZER_DATA_FULL_PATH,
236
269
  model=params,
270
+ http_client=http_client,
237
271
  )
238
272
  return analysis_result.DataID.model_validate(data)
239
273
 
240
274
  @classmethod
241
275
  async def get_generated_circuit_from_qasm(
242
- cls, params: analysis_result.QasmCode
276
+ cls,
277
+ params: analysis_result.QasmCode,
278
+ http_client: Optional[httpx.AsyncClient] = None,
243
279
  ) -> generator_result.QuantumProgram:
244
280
  data = await cls._call_task_pydantic(
245
281
  http_method=HTTPMethod.POST,
246
282
  url=routes.IDE_QASM_FULL_PATH,
247
283
  model=params,
284
+ http_client=http_client,
248
285
  )
249
286
  return generator_result.QuantumProgram.model_validate(data)
250
287
 
251
288
  @classmethod
252
289
  async def get_analyzer_app_data(
253
- cls, params: analysis_result.DataID
290
+ cls,
291
+ params: analysis_result.DataID,
292
+ http_client: Optional[httpx.AsyncClient] = None,
254
293
  ) -> generator_result.QuantumProgram:
255
294
  data = await cls._call_task(
256
295
  http_method=HTTPMethod.GET,
257
296
  url=f"{routes.ANALYZER_DATA_FULL_PATH}/{params.id}",
297
+ http_client=http_client,
258
298
  )
259
299
  return generator_result.QuantumProgram.model_validate(data)
260
300
 
261
301
  @classmethod
262
302
  async def call_rb_analysis_task(
263
- cls, params: AnalysisRBParams
303
+ cls,
304
+ params: AnalysisRBParams,
305
+ http_client: Optional[httpx.AsyncClient] = None,
264
306
  ) -> analysis_result.RbResults:
265
307
  data = await cls._call_task(
266
308
  http_method=HTTPMethod.POST,
267
309
  url=routes.ANALYZER_RB_FULL_PATH,
268
310
  body=params.model_dump(),
311
+ http_client=http_client,
269
312
  )
270
313
 
271
314
  return analysis_result.RbResults.model_validate(data)
272
315
 
273
316
  @classmethod
274
317
  async def call_hardware_connectivity_task(
275
- cls, params: analysis_params.AnalysisHardwareParams
318
+ cls,
319
+ params: analysis_params.AnalysisHardwareParams,
320
+ http_client: Optional[httpx.AsyncClient] = None,
276
321
  ) -> analysis_result.GraphResult:
277
322
  data = await cls._call_task_pydantic(
278
323
  http_method=HTTPMethod.POST,
279
324
  url=routes.ANALYZER_HC_GRAPH_FULL_PATH,
280
325
  model=params,
326
+ http_client=http_client,
281
327
  )
282
328
  return analysis_result.GraphResult.model_validate(data)
283
329
 
@@ -285,17 +331,21 @@ class ApiWrapper:
285
331
  async def call_table_graphs_task(
286
332
  cls,
287
333
  params: analysis_params.AnalysisHardwareListParams,
334
+ http_client: Optional[httpx.AsyncClient] = None,
288
335
  ) -> analysis_result.GraphResult:
289
336
  poller = JobPoller(base_url=routes.ANALYZER_HC_TABLE_GRAPH_FULL_PATH)
290
- result = await poller.run_pydantic(params, timeout_sec=None)
337
+ result = await poller.run_pydantic(
338
+ params, timeout_sec=None, http_client=http_client
339
+ )
291
340
  return _parse_job_response(result, analysis_result.GraphResult)
292
341
 
293
342
  @classmethod
294
343
  async def call_available_devices_task(
295
344
  cls,
296
345
  params: analysis_params.AnalysisOptionalDevicesParams,
346
+ http_client: Optional[httpx.AsyncClient] = None,
297
347
  ) -> analysis_result.DevicesResult:
298
- hardware_info = await cls.call_get_all_hardware_devices()
348
+ hardware_info = await cls.call_get_all_hardware_devices(http_client=http_client)
299
349
  return cls._get_devices_from_hardware_info(hardware_info, params)
300
350
 
301
351
  @staticmethod
@@ -323,11 +373,15 @@ class ApiWrapper:
323
373
  )
324
374
 
325
375
  @classmethod
326
- async def call_get_all_hardware_devices(cls) -> list[HardwareInformation]:
376
+ async def call_get_all_hardware_devices(
377
+ cls,
378
+ http_client: Optional[httpx.AsyncClient] = None,
379
+ ) -> list[HardwareInformation]:
327
380
  data = await client().call_api(
328
381
  http_method=HTTPMethod.GET,
329
382
  url="/hardware-catalog/v1/hardwares",
330
383
  use_versioned_url=False,
384
+ http_client=http_client,
331
385
  )
332
386
  if not isinstance(data, list):
333
387
  raise ClassiqAPIError(f"Unexpected value: {data}")
@@ -335,33 +389,45 @@ class ApiWrapper:
335
389
 
336
390
  @classmethod
337
391
  async def call_generate_hamiltonian_task(
338
- cls, problem: ground_state_problem.CHEMISTRY_PROBLEMS_TYPE
392
+ cls,
393
+ problem: ground_state_problem.CHEMISTRY_PROBLEMS_TYPE,
394
+ http_client: Optional[httpx.AsyncClient] = None,
339
395
  ) -> operator.PauliOperator:
340
396
  poller = JobPoller(
341
397
  base_url=routes.GENERATE_HAMILTONIAN_FULL_PATH,
342
398
  use_versioned_url=False,
343
399
  )
344
- result = await poller.run_pydantic(problem, timeout_sec=None)
400
+ result = await poller.run_pydantic(
401
+ problem, timeout_sec=None, http_client=http_client
402
+ )
345
403
  return _parse_job_response(result, operator.PauliOperator)
346
404
 
347
405
  @classmethod
348
- async def call_iqcc_init_auth(cls, data: IQCCInitAuthData) -> IQCCInitAuthResponse:
406
+ async def call_iqcc_init_auth(
407
+ cls,
408
+ data: IQCCInitAuthData,
409
+ http_client: Optional[httpx.AsyncClient] = None,
410
+ ) -> IQCCInitAuthResponse:
349
411
  response = await cls._call_task_pydantic(
350
412
  http_method=HTTPMethod.PUT,
351
413
  url=f"{routes.IQCC_INIT_AUTH_FULL_PATH}",
352
414
  model=data,
415
+ http_client=http_client,
353
416
  )
354
417
  return IQCCInitAuthResponse.model_validate(response)
355
418
 
356
419
  @classmethod
357
420
  async def call_iqcc_probe_auth(
358
- cls, data: IQCCProbeAuthData
421
+ cls,
422
+ data: IQCCProbeAuthData,
423
+ http_client: Optional[httpx.AsyncClient] = None,
359
424
  ) -> Optional[IQCCProbeAuthResponse]:
360
425
  try:
361
426
  response = await cls._call_task_pydantic(
362
427
  http_method=HTTPMethod.PUT,
363
428
  url=f"{routes.IQCC_PROBE_AUTH_FULL_PATH}",
364
429
  model=data,
430
+ http_client=http_client,
365
431
  )
366
432
  except ClassiqAPIError as ex:
367
433
  if ex.status_code == 418:
@@ -1,11 +1,12 @@
1
1
  import asyncio
2
+ import contextlib
2
3
  import functools
3
4
  import inspect
4
5
  import logging
5
6
  import os
6
7
  import platform
7
- import ssl
8
8
  import sys
9
+ import time
9
10
  from collections.abc import Awaitable
10
11
  from typing import (
11
12
  Any,
@@ -148,14 +149,11 @@ class Client:
148
149
  _SESSION_HEADER = "Classiq-Session"
149
150
  _WARNINGS_HEADER = "X-Classiq-Warnings"
150
151
  _LATEST_VERSION_API_PREFIX = "/api/v1"
152
+ _HTTP_TIMEOUT_SECONDS = 3600 # Needs to be synced with load-balancer timeout
151
153
 
152
154
  def __init__(self, conf: config.Configuration) -> None:
153
155
  self._config = conf
154
156
  self._token_manager = token_manager.TokenManager(config=self._config)
155
- self._ssl_context = ssl.create_default_context()
156
- self._HTTP_TIMEOUT_SECONDS = (
157
- 3600 # Needs to be synced with load-balancer timeout
158
- )
159
157
  self._api_prefix = self._make_api_prefix()
160
158
  self._session_id: Optional[str] = None
161
159
 
@@ -203,14 +201,44 @@ class Client:
203
201
  pass
204
202
  raise ClassiqAPIError(message, response.status_code)
205
203
 
204
+ @try_again_on_failure
205
+ async def request(
206
+ self,
207
+ http_client: httpx.AsyncClient,
208
+ method: str,
209
+ url: str,
210
+ json: Optional[dict] = None,
211
+ params: Optional[dict] = None,
212
+ headers: Optional[dict[str, str]] = None,
213
+ ) -> httpx.Response:
214
+ http_client.headers.update(self._get_headers())
215
+
216
+ _logger.debug("HTTP request: %s %s", method.upper(), url)
217
+ start_time = time.monotonic()
218
+ response = await http_client.request(
219
+ method=method,
220
+ url=url,
221
+ json=json,
222
+ params=params,
223
+ headers=headers,
224
+ )
225
+ _logger.debug(
226
+ "HTTP response: %s %s %d (%.0fms)",
227
+ method.upper(),
228
+ url,
229
+ response.status_code,
230
+ (time.monotonic() - start_time) * 1000,
231
+ )
232
+ self.handle_response(response)
233
+ return response
234
+
206
235
  def _make_client_args(self) -> dict[str, Any]:
207
236
  return {
208
237
  "base_url": str(self._config.host),
209
238
  "timeout": self._HTTP_TIMEOUT_SECONDS,
210
- "headers": self.get_headers(),
239
+ "headers": self._get_headers(),
211
240
  }
212
241
 
213
- @try_again_on_failure
214
242
  async def call_api(
215
243
  self,
216
244
  http_method: str,
@@ -219,20 +247,29 @@ class Client:
219
247
  params: Optional[dict] = None,
220
248
  use_versioned_url: bool = True,
221
249
  headers: Optional[dict[str, str]] = None,
250
+ http_client: Optional[httpx.AsyncClient] = None,
222
251
  ) -> Union[dict, list, str]:
223
252
  if use_versioned_url:
224
253
  url = self.make_versioned_url(url)
225
- async with self.async_client() as async_client:
226
- response = await async_client.request(
254
+ async with self.use_client_or_create(http_client) as async_client:
255
+ response = await self.request(
256
+ http_client=async_client,
227
257
  method=http_method,
228
258
  url=url,
229
259
  json=body,
230
260
  params=params,
231
261
  headers=headers,
232
262
  )
233
- self.handle_response(response)
234
263
  return response.json()
235
264
 
265
+ def use_client_or_create(
266
+ self, http_client: Optional[httpx.AsyncClient]
267
+ ) -> contextlib.AbstractAsyncContextManager[httpx.AsyncClient]:
268
+ if http_client is None:
269
+ return self.async_client()
270
+ else:
271
+ return contextlib.nullcontext(enter_result=http_client)
272
+
236
273
  def sync_call_api(
237
274
  self,
238
275
  http_method: str,
@@ -253,7 +290,7 @@ class Client:
253
290
  def async_client(self) -> httpx.AsyncClient:
254
291
  return httpx.AsyncClient(**self._make_client_args())
255
292
 
256
- def get_headers(self) -> Headers:
293
+ def _get_headers(self) -> Headers:
257
294
  headers = dict()
258
295
  access_token = self._token_manager.get_access_token()
259
296
  if access_token is not None:
@@ -10,7 +10,7 @@ from classiq.interface.exceptions import ClassiqAPIError
10
10
  from classiq.interface.jobs import JobDescription, JobID, JSONObject
11
11
 
12
12
  from classiq._internals.async_utils import poll_for
13
- from classiq._internals.client import client, try_again_on_failure
13
+ from classiq._internals.client import client
14
14
  from classiq._internals.config import SDKMode
15
15
 
16
16
  _URL_PATH_SEP = "/"
@@ -53,11 +53,9 @@ class JobPoller:
53
53
  def __init__(
54
54
  self,
55
55
  base_url: str,
56
- required_headers: Optional[set[str]] = None,
57
56
  use_versioned_url: bool = True,
58
57
  additional_headers: Optional[dict[str, str]] = None,
59
58
  ) -> None:
60
- self._required_headers = required_headers or set()
61
59
  self._additional_headers = additional_headers
62
60
  client_instance = client()
63
61
  self._base_url = (
@@ -65,7 +63,6 @@ class JobPoller:
65
63
  if use_versioned_url
66
64
  else base_url
67
65
  )
68
- self._async_client = client_instance.async_client()
69
66
  self._mode = client_instance.config.mode
70
67
 
71
68
  def _parse_job_id_response(self, response: httpx.Response) -> JobID:
@@ -78,29 +75,27 @@ class JobPoller:
78
75
  def _make_cancel_url(poll_url: str) -> str:
79
76
  return _join_url_path(poll_url, "cancel")
80
77
 
81
- def _update_headers(self, response: httpx.Response) -> None:
82
- for header in self._required_headers:
83
- try:
84
- self._async_client.headers[header] = response.headers[header]
85
- except KeyError as exc:
86
- raise ClassiqAPIError(
87
- f"Response to {self._base_url} is missing header {header}"
88
- ) from exc
89
-
90
- @try_again_on_failure
91
78
  async def _request(
92
- self, http_method: str, url: str, body: Optional[dict] = None
79
+ self,
80
+ http_client: httpx.AsyncClient,
81
+ http_method: str,
82
+ url: str,
83
+ body: Optional[dict] = None,
93
84
  ) -> httpx.Response:
94
- # Update headers in case they change
95
- self._async_client.headers.update(client().get_headers())
96
- response = await self._async_client.request(
97
- method=http_method, url=url, json=body, headers=self._additional_headers
85
+ return await client().request(
86
+ http_client=http_client,
87
+ method=http_method,
88
+ url=url,
89
+ json=body,
90
+ headers=self._additional_headers,
98
91
  )
99
- client().handle_response(response)
100
- return response
101
92
 
102
- async def _submit(self, body: dict) -> httpx.Response:
103
- return await self._request(http_method="POST", url=self._base_url, body=body)
93
+ async def _submit(
94
+ self, http_client: httpx.AsyncClient, body: dict
95
+ ) -> httpx.Response:
96
+ return await self._request(
97
+ http_client=http_client, http_method="POST", url=self._base_url, body=body
98
+ )
104
99
 
105
100
  def _interval_sec(self) -> Iterable[float]:
106
101
  if self._mode == SDKMode.DEV:
@@ -114,13 +109,16 @@ class JobPoller:
114
109
 
115
110
  async def _poll(
116
111
  self,
112
+ http_client: httpx.AsyncClient,
117
113
  poll_url: str,
118
114
  timeout_sec: Optional[float],
119
115
  response_parser: Callable[[JSONObject], Optional[T]] = _general_job_description_parser, # type: ignore[assignment]
120
116
  ) -> T:
121
117
  async def poller() -> JSONObject:
122
118
  nonlocal self, poll_url
123
- raw_response = await self._request(http_method="GET", url=poll_url)
119
+ raw_response = await self._request(
120
+ http_client=http_client, http_method="GET", url=poll_url
121
+ )
124
122
  return raw_response.json()
125
123
 
126
124
  async for json_response in poll_for(
@@ -136,39 +134,50 @@ class JobPoller:
136
134
  job_id: JobID,
137
135
  timeout_sec: Optional[float],
138
136
  response_parser: Callable[[JSONObject], Optional[T]] = _general_job_description_parser, # type: ignore[assignment]
137
+ http_client: Optional[httpx.AsyncClient] = None,
139
138
  ) -> T:
140
139
  poll_url = self._make_poll_url(job_id=job_id)
141
- async with self._async_client:
140
+ async with client().use_client_or_create(http_client) as async_client:
142
141
  return await self._poll(
142
+ http_client=async_client,
143
143
  poll_url=poll_url,
144
144
  response_parser=response_parser,
145
145
  timeout_sec=timeout_sec,
146
146
  )
147
147
 
148
- async def _cancel(self, poll_url: str) -> None:
148
+ async def _cancel(self, http_client: httpx.AsyncClient, poll_url: str) -> None:
149
149
  _logger.info("Cancelling job %s", poll_url, exc_info=True)
150
150
  cancel_url = self._make_cancel_url(poll_url)
151
- await self._request(http_method="PUT", url=cancel_url)
151
+ await self._request(http_client=http_client, http_method="PUT", url=cancel_url)
152
152
 
153
153
  async def run(
154
- self, body: dict, timeout_sec: Optional[float]
154
+ self,
155
+ body: dict,
156
+ timeout_sec: Optional[float],
157
+ http_client: Optional[httpx.AsyncClient] = None,
155
158
  ) -> GeneralJobDescription:
156
- async with self._async_client:
157
- submit_response = await self._submit(body=body)
159
+ async with client().use_client_or_create(http_client) as async_client:
160
+ submit_response = await self._submit(http_client=async_client, body=body)
158
161
  job_id = self._parse_job_id_response(response=submit_response)
159
162
  poll_url = self._make_poll_url(job_id=job_id)
160
- self._update_headers(response=submit_response)
161
163
  try:
162
- return await self._poll(poll_url=poll_url, timeout_sec=timeout_sec)
164
+ return await self._poll(
165
+ http_client=async_client,
166
+ poll_url=poll_url,
167
+ timeout_sec=timeout_sec,
168
+ )
163
169
  except Exception:
164
- await self._cancel(poll_url=poll_url)
170
+ await self._cancel(http_client=async_client, poll_url=poll_url)
165
171
  raise
166
172
 
167
173
  async def run_pydantic(
168
- self, model: pydantic.BaseModel, timeout_sec: Optional[float]
174
+ self,
175
+ model: pydantic.BaseModel,
176
+ timeout_sec: Optional[float],
177
+ http_client: Optional[httpx.AsyncClient] = None,
169
178
  ) -> GeneralJobDescription:
170
179
  # TODO: we can't use model.dict() - it doesn't serialize complex class.
171
180
  # This was added because JSON serializer doesn't serialize complex and UUID,
172
181
  # while pydantic does. We should add support for smarter json serialization.
173
182
  body = json.loads(model.model_dump_json())
174
- return await self.run(body, timeout_sec)
183
+ return await self.run(body, timeout_sec, http_client=http_client)
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  from functools import cached_property
3
+ from types import TracebackType
3
4
  from typing import Any, Callable, Optional, Union, cast
4
5
 
5
6
  import numpy as np
@@ -18,6 +19,7 @@ from classiq.interface.generator.quantum_program import QuantumProgram
18
19
 
19
20
  from classiq._internals import async_utils
20
21
  from classiq._internals.api_wrapper import ApiWrapper
22
+ from classiq._internals.client import client
21
23
  from classiq.applications.combinatorial_helpers.pauli_helpers.pauli_utils import (
22
24
  _pauli_dict_to_pauli_terms,
23
25
  _pauli_terms_to_qmod,
@@ -147,6 +149,7 @@ class ExecutionSession:
147
149
  """
148
150
  A session for executing a quantum program.
149
151
  `ExecutionSession` allows to execute the quantum program with different parameters and operations without the need to re-synthesize the model.
152
+ The session must be closed in order to ensure resources are properly cleaned up. It's recommended to use `ExecutionSession` as a context manager for this purpose. Alternatively, you can directly use the `close` method.
150
153
 
151
154
  Attributes:
152
155
  quantum_program (Union[SerializedQuantumProgram, QuantumProgram]): The quantum program to execute.
@@ -165,9 +168,30 @@ class ExecutionSession:
165
168
  # because cmain is expected in some cases
166
169
  self.program.model.classical_execution_code = "dummy"
167
170
 
171
+ self._async_client = client().async_client()
172
+
173
+ def __enter__(self) -> "ExecutionSession":
174
+ return self
175
+
176
+ def __exit__(
177
+ self,
178
+ exc_type: Optional[type[BaseException]],
179
+ exc_val: Optional[BaseException],
180
+ exc_tb: Optional[TracebackType],
181
+ ) -> None:
182
+ self.close()
183
+
184
+ def close(self) -> None:
185
+ """
186
+ Close the session and clean up its resources.
187
+ """
188
+ async_utils.run(self._async_client.aclose())
189
+
168
190
  @cached_property
169
191
  def _execution_input(self) -> dict:
170
- return async_utils.run(ApiWrapper.call_convert_quantum_program(self.program))
192
+ return async_utils.run(
193
+ ApiWrapper.call_convert_quantum_program(self.program, self._async_client)
194
+ )
171
195
 
172
196
  def _execute(
173
197
  self, classical_execution_code: str, primitives_input: PrimitivesInput
@@ -179,7 +203,7 @@ class ExecutionSession:
179
203
  primitives_input.model_dump_json()
180
204
  )
181
205
  result = async_utils.run(
182
- ApiWrapper.call_execute_execution_input(execution_input)
206
+ ApiWrapper.call_execute_execution_input(execution_input, self._async_client)
183
207
  )
184
208
  return ExecutionJob(details=result)
185
209
 
@@ -209,7 +233,7 @@ class ExecutionSession:
209
233
  The result of the sampling.
210
234
  """
211
235
  job = self.submit_sample(parameters=parameters)
212
- return job.get_sample_result()
236
+ return job.get_sample_result(_http_client=self._async_client)
213
237
 
214
238
  def submit_sample(
215
239
  self, parameters: Optional[ExecutionParams] = None
@@ -245,7 +269,7 @@ class ExecutionSession:
245
269
  List[ExecutionDetails]: The results of all the sampling iterations.
246
270
  """
247
271
  job = self.submit_batch_sample(parameters=parameters)
248
- return job.get_batch_sample_result()
272
+ return job.get_batch_sample_result(_http_client=self._async_client)
249
273
 
250
274
  def submit_batch_sample(self, parameters: list[ExecutionParams]) -> ExecutionJob:
251
275
  """
@@ -282,7 +306,7 @@ class ExecutionSession:
282
306
  EstimationResult: The result of the estimation.
283
307
  """
284
308
  job = self.submit_estimate(hamiltonian=hamiltonian, parameters=parameters)
285
- return job.get_estimate_result()
309
+ return job.get_estimate_result(_http_client=self._async_client)
286
310
 
287
311
  def submit_estimate(
288
312
  self, hamiltonian: Hamiltonian, parameters: Optional[ExecutionParams] = None
@@ -329,7 +353,7 @@ class ExecutionSession:
329
353
  List[EstimationResult]: The results of all the estimation iterations.
330
354
  """
331
355
  job = self.submit_batch_estimate(hamiltonian=hamiltonian, parameters=parameters)
332
- return job.get_batch_estimate_result()
356
+ return job.get_batch_estimate_result(_http_client=self._async_client)
333
357
 
334
358
  def submit_batch_estimate(
335
359
  self, hamiltonian: Hamiltonian, parameters: list[ExecutionParams]
classiq/execution/jobs.py CHANGED
@@ -3,6 +3,8 @@ from datetime import datetime
3
3
  from typing import Any, Optional, Union
4
4
  from urllib.parse import urljoin
5
5
 
6
+ import httpx
7
+
6
8
  from classiq.interface.exceptions import (
7
9
  ClassiqAPIError,
8
10
  ClassiqError,
@@ -100,22 +102,28 @@ class ExecutionJob:
100
102
  return f"{self._details.cost.total_cost} {self._details.cost.currency_code}"
101
103
 
102
104
  @classmethod
103
- async def from_id_async(cls, id: str) -> "ExecutionJob":
104
- details = await ApiWrapper.call_get_execution_job_details(JobID(job_id=id))
105
+ async def from_id_async(
106
+ cls,
107
+ id: str,
108
+ _http_client: Optional[httpx.AsyncClient] = None,
109
+ ) -> "ExecutionJob":
110
+ details = await ApiWrapper.call_get_execution_job_details(
111
+ JobID(job_id=id), http_client=_http_client
112
+ )
105
113
  return cls(details)
106
114
 
107
- @classmethod
108
- def from_id(cls, id: str) -> "ExecutionJob":
109
- return syncify_function(cls.from_id_async)(id)
115
+ from_id = syncify_function(from_id_async)
110
116
 
111
117
  @property
112
118
  def _job_id(self) -> JobID:
113
119
  return JobID(job_id=self.id)
114
120
 
115
121
  async def result_async(
116
- self, timeout_sec: Optional[float] = None
122
+ self,
123
+ timeout_sec: Optional[float] = None,
124
+ _http_client: Optional[httpx.AsyncClient] = None,
117
125
  ) -> ResultsCollection:
118
- await self.poll_async(timeout_sec=timeout_sec)
126
+ await self.poll_async(timeout_sec=timeout_sec, _http_client=_http_client)
119
127
 
120
128
  if self.status == JobStatus.FAILED:
121
129
  raise ClassiqAPIError(self.error or "")
@@ -125,7 +133,9 @@ class ExecutionJob:
125
133
  if self._result is None:
126
134
  self._result = (
127
135
  await ApiWrapper.call_get_execution_job_result(
128
- job_id=self._job_id, version=_JOB_RESULT_VERSION
136
+ job_id=self._job_id,
137
+ version=_JOB_RESULT_VERSION,
138
+ http_client=_http_client,
129
139
  )
130
140
  ).results
131
141
  return self._result
@@ -135,7 +145,9 @@ class ExecutionJob:
135
145
  def result_value(self, *args: Any, **kwargs: Any) -> Any:
136
146
  return self.result(*args, **kwargs)[0].value
137
147
 
138
- def get_sample_result(self) -> ExecutionDetails:
148
+ def get_sample_result(
149
+ self, _http_client: Optional[httpx.AsyncClient] = None
150
+ ) -> ExecutionDetails:
139
151
  """
140
152
  Returns the job's result as a single sample result after validation. If the result is not yet available, waits for it.
141
153
 
@@ -146,7 +158,7 @@ class ExecutionJob:
146
158
  ClassiqExecutionResultError: In case the result does not contain a single sample result.
147
159
  ClassiqAPIError: In case the job has failed.
148
160
  """
149
- results = self.result()
161
+ results = self.result(_http_client=_http_client)
150
162
  if len(results) != 1:
151
163
  raise ClassiqExecutionResultError("sample")
152
164
 
@@ -157,7 +169,9 @@ class ExecutionJob:
157
169
  return result.details[0]
158
170
  raise ClassiqExecutionResultError("sample")
159
171
 
160
- def get_batch_sample_result(self) -> list[ExecutionDetails]:
172
+ def get_batch_sample_result(
173
+ self, _http_client: Optional[httpx.AsyncClient] = None
174
+ ) -> list[ExecutionDetails]:
161
175
  """
162
176
  Returns the job's result as a single batch_sample result after validation. If the result is not yet available, waits for it.
163
177
 
@@ -168,7 +182,7 @@ class ExecutionJob:
168
182
  ClassiqExecutionResultError: In case the result does not contain a single batch_sample result.
169
183
  ClassiqAPIError: In case the job has failed.
170
184
  """
171
- results = self.result()
185
+ results = self.result(_http_client=_http_client)
172
186
  if len(results) != 1:
173
187
  raise ClassiqExecutionResultError("batch_sample")
174
188
 
@@ -180,7 +194,9 @@ class ExecutionJob:
180
194
 
181
195
  raise ClassiqExecutionResultError("batch_sample")
182
196
 
183
- def get_estimate_result(self) -> EstimationResult:
197
+ def get_estimate_result(
198
+ self, _http_client: Optional[httpx.AsyncClient] = None
199
+ ) -> EstimationResult:
184
200
  """
185
201
  Returns the job's result as a single estimate result after validation. If the result is not yet available, waits for it.
186
202
 
@@ -191,7 +207,7 @@ class ExecutionJob:
191
207
  ClassiqExecutionResultError: In case the result does not contain a single estimate result.
192
208
  ClassiqAPIError: In case the job has failed.
193
209
  """
194
- results = self.result()
210
+ results = self.result(_http_client=_http_client)
195
211
  if len(results) != 1:
196
212
  raise ClassiqExecutionResultError("estimate")
197
213
 
@@ -202,7 +218,9 @@ class ExecutionJob:
202
218
  return result.results[0]
203
219
  raise ClassiqExecutionResultError("estimate")
204
220
 
205
- def get_batch_estimate_result(self) -> list[EstimationResult]:
221
+ def get_batch_estimate_result(
222
+ self, _http_client: Optional[httpx.AsyncClient] = None
223
+ ) -> list[EstimationResult]:
206
224
  """
207
225
  Returns the job's result as a single batch_estimate result after validation. If the result is not yet available, waits for it.
208
226
 
@@ -213,7 +231,7 @@ class ExecutionJob:
213
231
  ClassiqExecutionResultError: In case the result does not contain a single batch_estimate result.
214
232
  ClassiqAPIError: In case the job has failed.
215
233
  """
216
- results = self.result()
234
+ results = self.result(_http_client=_http_client)
217
235
  if len(results) != 1:
218
236
  raise ClassiqExecutionResultError("batch_estimate")
219
237
 
@@ -225,13 +243,21 @@ class ExecutionJob:
225
243
 
226
244
  raise ClassiqExecutionResultError("batch_estimate")
227
245
 
228
- async def poll_async(self, timeout_sec: Optional[float] = None) -> None:
246
+ async def poll_async(
247
+ self,
248
+ timeout_sec: Optional[float] = None,
249
+ _http_client: Optional[httpx.AsyncClient] = None,
250
+ ) -> None:
229
251
  if not self.status.is_final():
230
- await self._poll_job(timeout_sec=timeout_sec)
252
+ await self._poll_job(timeout_sec=timeout_sec, _http_client=_http_client)
231
253
 
232
254
  poll = syncify_function(poll_async)
233
255
 
234
- async def _poll_job(self, timeout_sec: Optional[float] = None) -> None:
256
+ async def _poll_job(
257
+ self,
258
+ timeout_sec: Optional[float] = None,
259
+ _http_client: Optional[httpx.AsyncClient] = None,
260
+ ) -> None:
235
261
  def response_parser(json_response: JSONObject) -> Optional[bool]:
236
262
  self._details = ExecutionJobDetails.model_validate(json_response)
237
263
  if self.status.is_final():
@@ -247,14 +273,26 @@ class ExecutionJob:
247
273
  job_id=self._job_id,
248
274
  response_parser=response_parser,
249
275
  timeout_sec=timeout_sec,
276
+ http_client=_http_client,
250
277
  )
251
278
 
252
- async def rename_async(self, name: str) -> None:
253
- self._details = await ApiWrapper.call_patch_execution_job(self._job_id, name)
279
+ async def rename_async(
280
+ self,
281
+ name: str,
282
+ _http_client: Optional[httpx.AsyncClient] = None,
283
+ ) -> None:
284
+ self._details = await ApiWrapper.call_patch_execution_job(
285
+ self._job_id,
286
+ name,
287
+ http_client=_http_client,
288
+ )
254
289
 
255
290
  rename = syncify_function(rename_async)
256
291
 
257
- async def cancel_async(self) -> None:
292
+ async def cancel_async(
293
+ self,
294
+ _http_client: Optional[httpx.AsyncClient] = None,
295
+ ) -> None:
258
296
  """
259
297
  Cancels the execution job. This implies the cancellation of any ongoing jobs
260
298
  sent to the provider during this execution job.
@@ -263,7 +301,10 @@ class ExecutionJob:
263
301
  to continue polling the job in order to ensure its cancellation, which might
264
302
  not be immediate.
265
303
  """
266
- await ApiWrapper.call_cancel_execution_job(self._job_id)
304
+ await ApiWrapper.call_cancel_execution_job(
305
+ self._job_id,
306
+ http_client=_http_client,
307
+ )
267
308
 
268
309
  cancel = syncify_function(cancel_async)
269
310
 
classiq/execution/qaoa.py CHANGED
@@ -65,20 +65,22 @@ def execute_qaoa(
65
65
  model = create_model(main)
66
66
  qprog = synthesize(model)
67
67
 
68
- es = ExecutionSession(qprog, execution_preferences)
69
- initial_params = (
70
- np.concatenate((np.linspace(0, 1, num_layers), np.linspace(1, 0, num_layers)))
71
- * math.pi
72
- )
73
- final_params = scipy.optimize.minimize(
74
- lambda params: es.estimate_cost(
75
- lambda state: cost_func(state["v"]),
76
- {"params": params.tolist()},
77
- ),
78
- x0=initial_params,
79
- method="COBYLA",
80
- options={"maxiter": maxiter},
81
- ).x.tolist()
82
- result = es.sample({"params": final_params})
68
+ with ExecutionSession(qprog, execution_preferences) as es:
69
+ initial_params = (
70
+ np.concatenate(
71
+ (np.linspace(0, 1, num_layers), np.linspace(1, 0, num_layers))
72
+ )
73
+ * math.pi
74
+ )
75
+ final_params = scipy.optimize.minimize(
76
+ lambda params: es.estimate_cost(
77
+ lambda state: cost_func(state["v"]),
78
+ {"params": params.tolist()},
79
+ ),
80
+ x0=initial_params,
81
+ method="COBYLA",
82
+ options={"maxiter": maxiter},
83
+ ).x.tolist()
84
+ result = es.sample({"params": final_params})
83
85
 
84
86
  return model, qprog, result
classiq/execution/qnn.py CHANGED
@@ -59,22 +59,21 @@ def execute_qnn(
59
59
  arguments: MultipleArguments,
60
60
  observable: Optional[PauliOperator] = None,
61
61
  ) -> ResultsCollection:
62
- session = ExecutionSession(quantum_program)
62
+ with ExecutionSession(quantum_program) as session:
63
+ if observable:
64
+ execute_function = functools.partial(
65
+ _execute_qnn_estimate,
66
+ session=session,
67
+ observable=observable,
68
+ )
69
+ else:
70
+ execute_function = functools.partial(
71
+ _execute_qnn_sample,
72
+ session=session,
73
+ )
63
74
 
64
- if observable:
65
- execute_function = functools.partial(
66
- _execute_qnn_estimate,
67
- session=session,
68
- observable=observable,
69
- )
70
- else:
71
- execute_function = functools.partial(
72
- _execute_qnn_sample,
73
- session=session,
74
- )
75
-
76
- result: ResultsCollection = []
77
- for chunk in more_itertools.chunked(arguments, _MAX_ARGUMENTS_SIZE):
78
- chunk_result = execute_function(arguments=chunk)
79
- result.extend(chunk_result)
80
- return result
75
+ result: ResultsCollection = []
76
+ for chunk in more_itertools.chunked(arguments, _MAX_ARGUMENTS_SIZE):
77
+ chunk_result = execute_function(arguments=chunk)
78
+ result.extend(chunk_result)
79
+ return result
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.59.0'
6
+ SEMVER_VERSION = '0.60.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: classiq
3
- Version: 0.59.0
3
+ Version: 0.60.0
4
4
  Summary: Classiq's Python SDK for quantum computing
5
5
  Home-page: https://classiq.io
6
6
  License: Proprietary
@@ -3,7 +3,7 @@ classiq/_analyzer_extras/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
3
3
  classiq/_analyzer_extras/_ipywidgets_async_extension.py,sha256=7zv7mANDaLHH8QRGyY9QGDPPKPTjKKYdoq22iJaq_Ns,2190
4
4
  classiq/_analyzer_extras/interactive_hardware.py,sha256=f7ad2HeFq1f-2dJtPpgOE_w2IFzm49W6P_c-MzqJ5qE,3257
5
5
  classiq/_internals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- classiq/_internals/api_wrapper.py,sha256=CtrQPjCoDtGOJXMmROifX-YcYE6MkQyqJtB2DRwAu2U,12923
6
+ classiq/_internals/api_wrapper.py,sha256=RmaC6gCinBwQat0kff66T1GW6Kf55IwOQgBwxN01nWc,15198
7
7
  classiq/_internals/async_utils.py,sha256=utfzFLuCqmvxTLgg3JhMi-sBMIQFVW2LU5dqUEAJLCM,3370
8
8
  classiq/_internals/authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  classiq/_internals/authentication/auth0.py,sha256=K6yCnDUhIfgx-GfUHivak88_u06USHjXAjx9b3m5iek,3663
@@ -11,11 +11,11 @@ classiq/_internals/authentication/authentication.py,sha256=58Xv1QtynXwEfBqIV5E3L
11
11
  classiq/_internals/authentication/device.py,sha256=dUii1-Z26j0NY4R6J4p0gjYSq5Goj-gwMxXPSnVANuE,4024
12
12
  classiq/_internals/authentication/password_manager.py,sha256=aVR3wt07EJNa1OcUOmM9Nyg9Y4w8-3XzzrxJNsBWUBM,4438
13
13
  classiq/_internals/authentication/token_manager.py,sha256=XStkqCPUQEqc3uj6tt_XzfUIcUlyT-94tBZ8tpQIy_s,5280
14
- classiq/_internals/client.py,sha256=V-hyLXLW2EgE9mPOOemlEDSfz9SgXxez0aYmlv5UaU0,10412
14
+ classiq/_internals/client.py,sha256=0C2FsYcmO4toJ62rIwuGwawCkaJiefKKKjXSPxBo4JE,11604
15
15
  classiq/_internals/config.py,sha256=-UKKvPp_61sxXY-URqU1feLqlfh9ww4wCDH4yl14EiA,3534
16
16
  classiq/_internals/help.py,sha256=9gl64Y8nKW-f-8pYt7lMozOP6uERcIIf8dotgn_WKA0,460
17
17
  classiq/_internals/host_checker.py,sha256=D0rgnoZrHo62rYS32yCuYZSyMrMChZG5ITsJxwj0R5g,3969
18
- classiq/_internals/jobs.py,sha256=s-1-500Q-KrVG9nnTPbxcNfVqWiEfRnVKDL8A8HWnKM,6295
18
+ classiq/_internals/jobs.py,sha256=Wu8FvnhqAjLghBhfrCOHj0cMSH7LV39gI-6Iit_TWOc,6329
19
19
  classiq/_internals/logger.py,sha256=TGV37AR6aezLUzKUz4V1JercHeC68o_nNMlIRNHSRFM,634
20
20
  classiq/_internals/type_validation.py,sha256=kRd6td9krHPSZWgfclNsQcX7sNTqikp5wc3DvNbDsrA,1332
21
21
  classiq/analyzer/__init__.py,sha256=1ASEd3a5BLznMq_uD4ogR6buanALXfJIONZYmCweAgA,186
@@ -88,14 +88,14 @@ classiq/applications/qsvm/qsvm_data_generation.py,sha256=BIXBAxYNAvwZi1pVQJeSPTa
88
88
  classiq/applications/qsvm/qsvm_model_constructor.py,sha256=4Md7FuKZsG9FUCwBVDwkLic2_EtYCfYCkT0mnH-IsVQ,3945
89
89
  classiq/execution/__init__.py,sha256=t43kgz7GlyB8WT4gY10kr6tBBCTsD95oSWy-AZZZF_8,1220
90
90
  classiq/execution/all_hardware_devices.py,sha256=KpLefEISE03FDdgFPGggXeG7NAxBW4090gN4272Dl-E,368
91
- classiq/execution/execution_session.py,sha256=1ZItrjCn5lRdpQfPXGndzWrE_zpg1xY_-AVdhCMsfsU,16628
91
+ classiq/execution/execution_session.py,sha256=LICEO4UcRg0QN-g3gvXxA1IjitaqNy8bUGTAsjZIDwo,17598
92
92
  classiq/execution/iqcc.py,sha256=0wy1tgQFcwqf9wFYyi6_OYRtx4s0AEViIAIvUkyKBmk,2429
93
- classiq/execution/jobs.py,sha256=XCxv2oLF-0XyXmWS5DutuHhvLrmg5thc0j4yBSdvX3Q,9880
94
- classiq/execution/qaoa.py,sha256=IiicS_L41FeR_9kDcqLKnbuBuWj5ABuuGKqyC6SVsHk,3007
95
- classiq/execution/qnn.py,sha256=6lAKO0TpSEkcY_EwbJfVqNeqCeOegmkBQC1AzUrWxy0,2333
93
+ classiq/execution/jobs.py,sha256=d8GxbMgnvsqVFgTl6ZZzE0pLiXMLBp_lytk-XoWN31k,10980
94
+ classiq/execution/qaoa.py,sha256=P2lrUaZrNM9wrkK0wLybwO6tbYi_WVLPAN9p6w5-5Tc,3100
95
+ classiq/execution/qnn.py,sha256=WGPvncz5uS2WxSY3-yBWt2LFiCk6Ug8WKWF-Kp-f7TM,2403
96
96
  classiq/executor.py,sha256=rvcOI95rYtU2OSsuHLSjh9jutAk-CPSP6Bi01Fw3NqQ,2686
97
97
  classiq/interface/__init__.py,sha256=cg7hD_XVu1_jJ1fgwmT0rMIoZHopNVeB8xtlmMx-E_A,83
98
- classiq/interface/_version.py,sha256=rOMLK5Bd2ikoXtLbPc7cjxr3_XaPCsHMXecVZTZmeh0,197
98
+ classiq/interface/_version.py,sha256=wherc0_u11rIfr2I-NK35mQibgwEnZrzCzg99imZV_Y,197
99
99
  classiq/interface/analyzer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
100
  classiq/interface/analyzer/analysis_params.py,sha256=dM5rwSks798cxk4FWe4_X5ToRYtgZQh34F1u0XrFkK8,3881
101
101
  classiq/interface/analyzer/cytoscape_graph.py,sha256=MpeRBIYS1TfwYwiFpgTO51IE0KoxhY510pmEM3S0rbw,2361
@@ -510,6 +510,6 @@ classiq/qmod/type_attribute_remover.py,sha256=NZmTXAsngWqthXjE8n-n6yE72fiWTFM12-
510
510
  classiq/qmod/utilities.py,sha256=z_VnIRmOYTWjJp2UlOcWK0rQRtMqysmP_Gr6WYY_nak,2734
511
511
  classiq/qmod/write_qmod.py,sha256=Oo-j_rSfcmzC5MOn0Vq334vv_OTvdD4P7K9pv-gbo8c,1833
512
512
  classiq/synthesis.py,sha256=WLk3wpX_xPiAMstF9PGMO5SWVb_qqa1sN2Nj3MekX34,8113
513
- classiq-0.59.0.dist-info/METADATA,sha256=nNs_shmuDS6cAFEx9HamByF3V4eWV25bemBS3yh56Mo,3459
514
- classiq-0.59.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
515
- classiq-0.59.0.dist-info/RECORD,,
513
+ classiq-0.60.0.dist-info/METADATA,sha256=du8LH68WEc4MtDvdTmxtrDcXzAu1kNkUqEew0fNZXRw,3459
514
+ classiq-0.60.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
515
+ classiq-0.60.0.dist-info/RECORD,,