classiq 0.51.1__py3-none-any.whl → 0.52.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.
Files changed (149) hide show
  1. classiq/_internals/api_wrapper.py +41 -15
  2. classiq/_internals/authentication/auth0.py +20 -4
  3. classiq/_internals/authentication/password_manager.py +16 -4
  4. classiq/_internals/client.py +2 -2
  5. classiq/_internals/host_checker.py +5 -3
  6. classiq/_internals/jobs.py +3 -3
  7. classiq/analyzer/analyzer_utilities.py +1 -1
  8. classiq/applications/chemistry/ground_state_problem.py +1 -1
  9. classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
  10. classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
  11. classiq/applications/qnn/qlayer.py +2 -2
  12. classiq/execution/__init__.py +3 -0
  13. classiq/execution/execution_session.py +2 -2
  14. classiq/execution/iqcc.py +63 -0
  15. classiq/execution/jobs.py +2 -2
  16. classiq/executor.py +2 -2
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +19 -9
  19. classiq/interface/analyzer/cytoscape_graph.py +10 -3
  20. classiq/interface/analyzer/result.py +6 -5
  21. classiq/interface/applications/qsvm.py +13 -12
  22. classiq/interface/backend/backend_preferences.py +78 -105
  23. classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
  24. classiq/interface/backend/pydantic_backend.py +24 -12
  25. classiq/interface/backend/quantum_backend_providers.py +2 -0
  26. classiq/interface/chemistry/fermionic_operator.py +7 -7
  27. classiq/interface/chemistry/ground_state_problem.py +23 -18
  28. classiq/interface/chemistry/molecule.py +10 -5
  29. classiq/interface/chemistry/operator.py +71 -44
  30. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
  31. classiq/interface/debug_info/debug_info.py +3 -4
  32. classiq/interface/execution/iqcc.py +21 -0
  33. classiq/interface/execution/jobs.py +10 -10
  34. classiq/interface/executor/aws_execution_cost.py +37 -20
  35. classiq/interface/executor/execution_preferences.py +1 -2
  36. classiq/interface/executor/execution_request.py +2 -2
  37. classiq/interface/executor/execution_result.py +4 -2
  38. classiq/interface/executor/iqae_result.py +1 -1
  39. classiq/interface/executor/optimizer_preferences.py +14 -10
  40. classiq/interface/executor/quantum_code.py +21 -16
  41. classiq/interface/executor/register_initialization.py +10 -10
  42. classiq/interface/executor/result.py +19 -16
  43. classiq/interface/executor/vqe_result.py +1 -1
  44. classiq/interface/finance/function_input.py +27 -18
  45. classiq/interface/finance/log_normal_model_input.py +2 -2
  46. classiq/interface/finance/model_input.py +3 -2
  47. classiq/interface/generator/amplitude_loading.py +8 -6
  48. classiq/interface/generator/arith/argument_utils.py +24 -0
  49. classiq/interface/generator/arith/arithmetic.py +5 -3
  50. classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
  51. classiq/interface/generator/arith/arithmetic_operations.py +6 -3
  52. classiq/interface/generator/arith/binary_ops.py +88 -63
  53. classiq/interface/generator/arith/extremum_operations.py +22 -13
  54. classiq/interface/generator/arith/logical_ops.py +6 -4
  55. classiq/interface/generator/arith/number_utils.py +3 -3
  56. classiq/interface/generator/arith/register_user_input.py +32 -17
  57. classiq/interface/generator/arith/unary_ops.py +5 -4
  58. classiq/interface/generator/chemistry_function_params.py +2 -1
  59. classiq/interface/generator/circuit_code/circuit_code.py +2 -1
  60. classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
  61. classiq/interface/generator/complex_type.py +14 -18
  62. classiq/interface/generator/control_state.py +32 -26
  63. classiq/interface/generator/expressions/expression.py +6 -5
  64. classiq/interface/generator/function_params.py +22 -39
  65. classiq/interface/generator/functions/classical_function_declaration.py +1 -1
  66. classiq/interface/generator/functions/classical_type.py +32 -23
  67. classiq/interface/generator/functions/concrete_types.py +8 -7
  68. classiq/interface/generator/functions/function_declaration.py +4 -5
  69. classiq/interface/generator/functions/type_name.py +5 -4
  70. classiq/interface/generator/generated_circuit_data.py +9 -6
  71. classiq/interface/generator/grover_diffuser.py +26 -18
  72. classiq/interface/generator/grover_operator.py +32 -22
  73. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
  74. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  75. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
  76. classiq/interface/generator/hardware/hardware_data.py +27 -26
  77. classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
  78. classiq/interface/generator/hartree_fock.py +2 -1
  79. classiq/interface/generator/identity.py +7 -2
  80. classiq/interface/generator/linear_pauli_rotations.py +27 -14
  81. classiq/interface/generator/mcu.py +15 -12
  82. classiq/interface/generator/mcx.py +18 -10
  83. classiq/interface/generator/model/constraints.py +4 -2
  84. classiq/interface/generator/model/model.py +2 -1
  85. classiq/interface/generator/model/preferences/preferences.py +30 -32
  86. classiq/interface/generator/oracles/custom_oracle.py +13 -10
  87. classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
  88. classiq/interface/generator/qpe.py +38 -26
  89. classiq/interface/generator/qsvm.py +4 -4
  90. classiq/interface/generator/quantum_function_call.py +57 -44
  91. classiq/interface/generator/quantum_program.py +8 -6
  92. classiq/interface/generator/range_types.py +10 -11
  93. classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
  94. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  95. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  96. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  97. classiq/interface/generator/state_preparation/distributions.py +12 -12
  98. classiq/interface/generator/state_preparation/state_preparation.py +22 -16
  99. classiq/interface/generator/types/enum_declaration.py +2 -1
  100. classiq/interface/generator/ucc.py +2 -1
  101. classiq/interface/generator/unitary_gate.py +2 -1
  102. classiq/interface/generator/user_defined_function_params.py +3 -0
  103. classiq/interface/generator/visitor.py +1 -1
  104. classiq/interface/hardware.py +18 -3
  105. classiq/interface/helpers/custom_pydantic_types.py +38 -47
  106. classiq/interface/helpers/pydantic_model_helpers.py +3 -2
  107. classiq/interface/helpers/versioned_model.py +1 -4
  108. classiq/interface/ide/ide_data.py +5 -5
  109. classiq/interface/ide/visual_model.py +5 -5
  110. classiq/interface/interface_version.py +1 -1
  111. classiq/interface/jobs.py +12 -22
  112. classiq/interface/model/bind_operation.py +2 -1
  113. classiq/interface/model/classical_parameter_declaration.py +10 -4
  114. classiq/interface/model/handle_binding.py +20 -24
  115. classiq/interface/model/inplace_binary_operation.py +16 -9
  116. classiq/interface/model/model.py +21 -11
  117. classiq/interface/model/port_declaration.py +10 -7
  118. classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
  119. classiq/interface/model/quantum_function_declaration.py +22 -11
  120. classiq/interface/model/quantum_statement.py +6 -7
  121. classiq/interface/model/quantum_type.py +22 -19
  122. classiq/interface/model/statement_block.py +9 -9
  123. classiq/interface/server/global_versions.py +4 -5
  124. classiq/interface/server/routes.py +8 -0
  125. classiq/model_expansions/evaluators/parameter_types.py +3 -3
  126. classiq/model_expansions/expression_renamer.py +1 -1
  127. classiq/model_expansions/quantum_operations/control.py +11 -12
  128. classiq/model_expansions/quantum_operations/emitter.py +22 -0
  129. classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
  130. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +38 -9
  131. classiq/model_expansions/quantum_operations/invert.py +1 -1
  132. classiq/model_expansions/quantum_operations/phase.py +4 -5
  133. classiq/model_expansions/quantum_operations/power.py +1 -1
  134. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
  135. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  136. classiq/model_expansions/quantum_operations/within_apply.py +1 -1
  137. classiq/qmod/builtins/__init__.py +1 -3
  138. classiq/qmod/builtins/functions/__init__.py +4 -0
  139. classiq/qmod/builtins/functions/arithmetic.py +10 -0
  140. classiq/qmod/create_model_function.py +4 -4
  141. classiq/qmod/quantum_expandable.py +22 -9
  142. classiq/qmod/quantum_function.py +1 -1
  143. classiq/qmod/semantics/static_semantics_visitor.py +3 -1
  144. classiq/qmod/type_attribute_remover.py +1 -1
  145. classiq/qmod/write_qmod.py +2 -4
  146. classiq/synthesis.py +11 -13
  147. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
  148. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/RECORD +149 -147
  149. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -11,6 +11,12 @@ from classiq.interface.analyzer.result import GraphStatus
11
11
  from classiq.interface.chemistry import ground_state_problem, operator
12
12
  from classiq.interface.enum_utils import StrEnum
13
13
  from classiq.interface.exceptions import ClassiqAPIError, ClassiqValueError
14
+ from classiq.interface.execution.iqcc import (
15
+ IQCCInitAuthData,
16
+ IQCCInitAuthResponse,
17
+ IQCCProbeAuthData,
18
+ IQCCProbeAuthResponse,
19
+ )
14
20
  from classiq.interface.execution.jobs import (
15
21
  ExecutionJobDetailsV1,
16
22
  ExecutionJobsQueryResultsV1,
@@ -49,7 +55,7 @@ def _parse_job_response(
49
55
  output_type: Type[ResultType],
50
56
  ) -> ResultType:
51
57
  if job_result.result is not None:
52
- return output_type.parse_obj(job_result.result)
58
+ return output_type.model_validate(job_result.result)
53
59
  if job_result.failure_details:
54
60
  raise ClassiqAPIError(job_result.failure_details)
55
61
 
@@ -68,7 +74,7 @@ class ApiWrapper:
68
74
  # TODO: we can't use model.dict() - it doesn't serialize complex class.
69
75
  # This was added because JSON serializer doesn't serialize complex type, and pydantic does.
70
76
  # We should add support for smarter json serialization.
71
- body = json.loads(model.json())
77
+ body = json.loads(model.model_dump_json())
72
78
  return await cls._call_task(
73
79
  http_method, url, body, use_versioned_url=use_versioned_url
74
80
  )
@@ -126,7 +132,7 @@ class ApiWrapper:
126
132
  body=execution_input,
127
133
  use_versioned_url=False,
128
134
  )
129
- return execution_request.ExecutionJobDetails.parse_obj(data)
135
+ return execution_request.ExecutionJobDetails.model_validate(data)
130
136
 
131
137
  @classmethod
132
138
  async def call_get_execution_job_details(
@@ -140,7 +146,7 @@ class ApiWrapper:
140
146
  url=f"{routes.EXECUTION_JOBS_NON_VERSIONED_FULL_PATH}/{job_id.job_id}",
141
147
  use_versioned_url=False,
142
148
  )
143
- return execution_request.ExecutionJobDetails.parse_obj(data)
149
+ return execution_request.ExecutionJobDetails.model_validate(data)
144
150
 
145
151
  @classmethod
146
152
  async def call_get_execution_job_result(
@@ -154,7 +160,7 @@ class ApiWrapper:
154
160
  use_versioned_url=False,
155
161
  headers={CLASSIQ_ACCEPT_HEADER: version},
156
162
  )
157
- return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.parse_obj(
163
+ return classiq.interface.executor.execution_result.ExecuteGeneratedCircuitResults.model_validate(
158
164
  data
159
165
  )
160
166
 
@@ -172,7 +178,7 @@ class ApiWrapper:
172
178
  },
173
179
  use_versioned_url=False,
174
180
  )
175
- return ExecutionJobDetailsV1.parse_obj(data)
181
+ return ExecutionJobDetailsV1.model_validate(data)
176
182
 
177
183
  @classmethod
178
184
  async def call_cancel_execution_job(
@@ -201,7 +207,7 @@ class ApiWrapper:
201
207
  },
202
208
  use_versioned_url=False,
203
209
  )
204
- return ExecutionJobsQueryResultsV1.parse_obj(data)
210
+ return ExecutionJobsQueryResultsV1.model_validate(data)
205
211
 
206
212
  @classmethod
207
213
  async def call_analysis_task(
@@ -213,7 +219,7 @@ class ApiWrapper:
213
219
  model=params,
214
220
  )
215
221
 
216
- return analysis_result.Analysis.parse_obj(data)
222
+ return analysis_result.Analysis.model_validate(data)
217
223
 
218
224
  @classmethod
219
225
  async def call_analyzer_app(
@@ -224,7 +230,7 @@ class ApiWrapper:
224
230
  url=routes.ANALYZER_DATA_FULL_PATH,
225
231
  model=params,
226
232
  )
227
- return analysis_result.DataID.parse_obj(data)
233
+ return analysis_result.DataID.model_validate(data)
228
234
 
229
235
  @classmethod
230
236
  async def get_generated_circuit_from_qasm(
@@ -235,7 +241,7 @@ class ApiWrapper:
235
241
  url=routes.IDE_QASM_FULL_PATH,
236
242
  model=params,
237
243
  )
238
- return generator_result.QuantumProgram.parse_obj(data)
244
+ return generator_result.QuantumProgram.model_validate(data)
239
245
 
240
246
  @classmethod
241
247
  async def get_analyzer_app_data(
@@ -245,7 +251,7 @@ class ApiWrapper:
245
251
  http_method=HTTPMethod.GET,
246
252
  url=f"{routes.ANALYZER_DATA_FULL_PATH}/{params.id}",
247
253
  )
248
- return generator_result.QuantumProgram.parse_obj(data)
254
+ return generator_result.QuantumProgram.model_validate(data)
249
255
 
250
256
  @classmethod
251
257
  async def call_rb_analysis_task(
@@ -254,10 +260,10 @@ class ApiWrapper:
254
260
  data = await cls._call_task(
255
261
  http_method=HTTPMethod.POST,
256
262
  url=routes.ANALYZER_RB_FULL_PATH,
257
- body=params.dict(),
263
+ body=params.model_dump(),
258
264
  )
259
265
 
260
- return analysis_result.RbResults.parse_obj(data)
266
+ return analysis_result.RbResults.model_validate(data)
261
267
 
262
268
  @classmethod
263
269
  async def call_hardware_connectivity_task(
@@ -268,7 +274,7 @@ class ApiWrapper:
268
274
  url=routes.ANALYZER_HC_GRAPH_FULL_PATH,
269
275
  model=params,
270
276
  )
271
- return analysis_result.GraphResult.parse_obj(data)
277
+ return analysis_result.GraphResult.model_validate(data)
272
278
 
273
279
  @classmethod
274
280
  async def call_table_graphs_task(
@@ -320,7 +326,7 @@ class ApiWrapper:
320
326
  )
321
327
  if not isinstance(data, list):
322
328
  raise ClassiqAPIError(f"Unexpected value: {data}")
323
- return [HardwareInformation.parse_obj(info) for info in data]
329
+ return [HardwareInformation.model_validate(info) for info in data]
324
330
 
325
331
  @classmethod
326
332
  async def call_generate_hamiltonian_task(
@@ -332,3 +338,23 @@ class ApiWrapper:
332
338
  )
333
339
  result = await poller.run_pydantic(problem, timeout_sec=None)
334
340
  return _parse_job_response(result, operator.PauliOperator)
341
+
342
+ @classmethod
343
+ async def call_iqcc_init_auth(cls, data: IQCCInitAuthData) -> IQCCInitAuthResponse:
344
+ response = await cls._call_task_pydantic(
345
+ http_method=HTTPMethod.GET,
346
+ url=f"{routes.IQCC_INIT_AUTH_FULL_PATH}",
347
+ model=data,
348
+ )
349
+ return IQCCInitAuthResponse.parse_obj(response)
350
+
351
+ @classmethod
352
+ async def call_iqcc_probe_auth(
353
+ cls, data: IQCCProbeAuthData
354
+ ) -> IQCCProbeAuthResponse:
355
+ response = await cls._call_task_pydantic(
356
+ http_method=HTTPMethod.GET,
357
+ url=f"{routes.IQCC_PROBE_AUTH_FULL_PATH}",
358
+ model=data,
359
+ )
360
+ return IQCCProbeAuthResponse.parse_obj(response)
@@ -3,18 +3,34 @@ from dataclasses import dataclass
3
3
  from typing import Any, Dict, Optional, Union
4
4
 
5
5
  from httpx import AsyncClient, Response, codes
6
- from pydantic import BaseSettings, Field
6
+ from pydantic import Field
7
+ from pydantic_settings import BaseSettings, SettingsConfigDict
7
8
 
8
9
  from classiq.interface.exceptions import ClassiqAuthenticationError
9
10
 
10
11
 
11
12
  class AuthSettings(BaseSettings):
12
- domain: str = Field(default="auth.classiq.io", env="CLASSIQ_AUTH_DOMAIN")
13
- audience: str = Field(default="https://cadmium-be", env="CLASSIQ_AUTH_AUDIENCE")
13
+ domain: str = Field(
14
+ default="auth.classiq.io", validation_alias="CLASSIQ_AUTH_DOMAIN"
15
+ )
16
+ audience: str = Field(
17
+ default="https://cadmium-be", validation_alias="CLASSIQ_AUTH_AUDIENCE"
18
+ )
14
19
  client_id: str = Field(
15
- default="f6721qMOVoDAOVkzrv8YaWassRKSFX6Y", env="CLASSIQ_AUTH_CLIENT_ID"
20
+ default="f6721qMOVoDAOVkzrv8YaWassRKSFX6Y",
21
+ validation_alias="CLASSIQ_AUTH_CLIENT_ID",
16
22
  )
17
23
 
24
+ model_config = SettingsConfigDict(extra="allow")
25
+
26
+ def __init__(self, **data: Any) -> None:
27
+ initial_data = {
28
+ field: data[field] for field in data if field in self.model_fields
29
+ }
30
+ super().__init__(**data)
31
+ for field, value in initial_data.items():
32
+ setattr(self, field, value)
33
+
18
34
 
19
35
  @dataclass
20
36
  class Tokens:
@@ -5,23 +5,35 @@ import os
5
5
  import pathlib
6
6
  import platform
7
7
  import stat
8
- from typing import Dict, Optional
8
+ from typing import Any, Dict, Optional
9
9
 
10
10
  import keyring
11
11
  from keyring.backends import fail
12
- from pydantic import BaseSettings, Field
12
+ from pydantic import Field
13
+ from pydantic_settings import BaseSettings, SettingsConfigDict
13
14
 
14
15
  _logger = logging.getLogger(__name__)
15
16
 
16
17
 
17
18
  class PasswordManagerSettings(BaseSettings):
18
19
  ACCESS_TOKEN_KEY: str = Field(
19
- default="classiqTokenAccount", env="CLASSIQ_ACCESS_TOKEN_ACCOUNT"
20
+ default="classiqTokenAccount", validation_alias="CLASSIQ_ACCESS_TOKEN_ACCOUNT"
20
21
  )
21
22
  REFRESH_TOKEN_KEY: str = Field(
22
- default="classiqRefershTokenAccount", env="CLASSIQ_REFRESH_TOKEN_ACCOUNT"
23
+ default="classiqRefershTokenAccount",
24
+ validation_alias="CLASSIQ_REFRESH_TOKEN_ACCOUNT",
23
25
  )
24
26
 
27
+ model_config = SettingsConfigDict(extra="allow")
28
+
29
+ def __init__(self, **data: Any) -> None:
30
+ initial_data = {
31
+ field: data[field] for field in data if field in self.model_fields
32
+ }
33
+ super().__init__(**data)
34
+ for field, value in initial_data.items():
35
+ setattr(self, field, value)
36
+
25
37
 
26
38
  class PasswordManager(abc.ABC):
27
39
  _SERVICE_NAME: str = "classiqTokenService"
@@ -207,7 +207,7 @@ class Client:
207
207
 
208
208
  def _make_client_args(self) -> Dict[str, Any]:
209
209
  return {
210
- "base_url": self._config.host,
210
+ "base_url": str(self._config.host),
211
211
  "timeout": self._HTTP_TIMEOUT_SECONDS,
212
212
  "headers": self.get_headers(),
213
213
  }
@@ -269,7 +269,7 @@ class Client:
269
269
  await self._token_manager.update_expired_access_token()
270
270
 
271
271
  def get_backend_uri(self) -> str:
272
- return self._config.host
272
+ return self._config.host.unicode_string()
273
273
 
274
274
  def check_host(self) -> None:
275
275
  # This function is NOT async (despite the fact that it can be) because it's called from a non-async context.
@@ -39,7 +39,7 @@ class HostChecker:
39
39
  self._interface_version = interface_version
40
40
 
41
41
  def _get_interface_version(self) -> Optional[str]:
42
- global_interfaces = GlobalVersions.parse_obj(
42
+ global_interfaces = GlobalVersions.model_validate(
43
43
  self._client.sync_call_api(
44
44
  "get", "/interface_versions", use_versioned_url=False
45
45
  )
@@ -47,11 +47,13 @@ class HostChecker:
47
47
  return global_interfaces.deployed.get(self._interface_version, None)
48
48
 
49
49
  def _get_host_version(self) -> str:
50
- host = HostVersions.parse_obj(self._client.sync_call_api("get", "/versions"))
50
+ host = HostVersions.model_validate(
51
+ self._client.sync_call_api("get", "/versions")
52
+ )
51
53
  return host.classiq_interface
52
54
 
53
55
  def _get_deprecation_info(self) -> Optional[DeprecationInfo]:
54
- global_versions = GlobalVersions.parse_obj(
56
+ global_versions = GlobalVersions.model_validate(
55
57
  self._client.sync_call_api("get", "/versions", use_versioned_url=False)
56
58
  )
57
59
  return global_versions.deprecated.get(self._client_version, None)
@@ -37,7 +37,7 @@ def _join_url_path(*parts: str) -> str:
37
37
  def _general_job_description_parser(
38
38
  json_response: JSONObject,
39
39
  ) -> Optional[GeneralJobDescription]:
40
- job_description = GeneralJobDescription.parse_obj(json_response)
40
+ job_description = GeneralJobDescription.model_validate(json_response)
41
41
  if job_description.status.is_final():
42
42
  return job_description
43
43
  return None
@@ -68,7 +68,7 @@ class JobPoller:
68
68
  self._mode = client_instance.config.mode
69
69
 
70
70
  def _parse_job_id_response(self, response: httpx.Response) -> JobID:
71
- return JobID.parse_obj(response.json())
71
+ return JobID.model_validate(response.json())
72
72
 
73
73
  def _make_poll_url(self, job_id: JobID) -> str:
74
74
  return _join_url_path(self._base_url, job_id.job_id)
@@ -171,5 +171,5 @@ class JobPoller:
171
171
  # TODO: we can't use model.dict() - it doesn't serialize complex class.
172
172
  # This was added because JSON serializer doesn't serialize complex and UUID,
173
173
  # while pydantic does. We should add support for smarter json serialization.
174
- body = json.loads(model.json())
174
+ body = json.loads(model.model_dump_json())
175
175
  return await self.run(body, timeout_sec)
@@ -41,7 +41,7 @@ class AnalyzerUtilities:
41
41
  qubit_count=self.circuit.data.width, providers=requested_providers
42
42
  )
43
43
  result = await ApiWrapper.call_available_devices_task(params=params)
44
- self.available_devices.update(result.devices.dict())
44
+ self.available_devices.update(result.devices.model_dump())
45
45
 
46
46
  async def request_hardware_connectivity_async(
47
47
  self, provider: ProviderNameEnum, device: DeviceName
@@ -33,7 +33,7 @@ async def update_problem_async(
33
33
  ) -> CHEMISTRY_PROBLEMS_TYPE:
34
34
  if num_qubits is None:
35
35
  num_qubits = await _get_num_qubits(problem)
36
- return problem.copy(update={"num_qubits": num_qubits})
36
+ return problem.model_copy(update={"num_qubits": num_qubits})
37
37
 
38
38
 
39
39
  ground_state_problem.GroundStateProblem.update_problem = async_utils.syncify_function( # type: ignore[attr-defined]
@@ -143,7 +143,9 @@ def convert_pyomo_to_global_presentation(
143
143
  pyo_model: pyo.ConcreteModel,
144
144
  ) -> pyo.ConcreteModel:
145
145
  pyo_model_str = pyomo2qmod("nativePyoModel", pyo_model)
146
- problem_struct = CombinatorialOptimizationStructDeclaration.parse_raw(pyo_model_str)
146
+ problem_struct = CombinatorialOptimizationStructDeclaration.model_validate_json(
147
+ pyo_model_str
148
+ )
147
149
 
148
150
  pyomo_model = pyo.ConcreteModel()
149
151
 
@@ -23,7 +23,7 @@ class QuantumGradient(abc.ABC):
23
23
  self._execute = execute
24
24
  self._post_process = post_process
25
25
 
26
- circuit = QuantumProgram.parse_raw(quantum_program)
26
+ circuit = QuantumProgram.model_validate_json(quantum_program)
27
27
  validate_circuit(circuit)
28
28
  self._quantum_program = quantum_program
29
29
  self._parameters_names = extract_parameters(circuit)
@@ -52,7 +52,7 @@ class QLayerFunction(torch.autograd.Function):
52
52
  and returning a `Tensor`
53
53
 
54
54
  """
55
- circuit = Circuit.parse_raw(quantum_program)
55
+ circuit = Circuit.model_validate_json(quantum_program)
56
56
  validate_circuit(circuit)
57
57
 
58
58
  # save for backward
@@ -144,7 +144,7 @@ class QLayer(nn.Module):
144
144
  # Experimental parameters:
145
145
  calc_num_out_features: CalcNumOutFeatures = calc_num_out_features_single_output,
146
146
  ) -> None:
147
- circuit = Circuit.parse_raw(quantum_program)
147
+ circuit = Circuit.model_validate_json(quantum_program)
148
148
  validate_circuit(circuit)
149
149
 
150
150
  super().__init__()
@@ -10,6 +10,7 @@ from ..interface.executor.iqae_result import IQAEResult
10
10
  from ..interface.executor.result import ExecutionDetails
11
11
  from ..interface.executor.vqe_result import VQESolverResult
12
12
  from .execution_session import ExecutionSession
13
+ from .iqcc import generate_iqcc_token, generate_iqcc_token_async
13
14
  from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
14
15
  from .qnn import execute_qnn
15
16
 
@@ -26,6 +27,8 @@ __all__ = (
26
27
  "get_execution_jobs_async",
27
28
  "ExecutionSession",
28
29
  "execute_qnn",
30
+ "generate_iqcc_token",
31
+ "generate_iqcc_token_async",
29
32
  ]
30
33
  )
31
34
 
@@ -48,7 +48,7 @@ def _deserialize_program(program: Program) -> QuantumProgram:
48
48
  return (
49
49
  program
50
50
  if isinstance(program, QuantumProgram)
51
- else QuantumProgram.parse_obj(json.loads(program))
51
+ else QuantumProgram.model_validate(json.loads(program))
52
52
  )
53
53
 
54
54
 
@@ -162,7 +162,7 @@ class ExecutionSession:
162
162
  Returns:
163
163
  SerializedQuantumProgram: The serialized quantum program (str). See `QuantumProgram`.
164
164
  """
165
- return SerializedQuantumProgram(self.program.json(indent=2))
165
+ return SerializedQuantumProgram(self.program.model_dump_json(indent=2))
166
166
 
167
167
  def update_execution_preferences(
168
168
  self, execution_preferences: Optional[ExecutionPreferences]
@@ -0,0 +1,63 @@
1
+ import time
2
+ import webbrowser
3
+
4
+ from classiq.interface.exceptions import ClassiqError
5
+ from classiq.interface.execution.iqcc import IQCCInitAuthData, IQCCProbeAuthData
6
+
7
+ from classiq._internals.api_wrapper import ApiWrapper
8
+ from classiq._internals.async_utils import syncify_function
9
+
10
+
11
+ async def generate_iqcc_token_async(
12
+ auth_scope_id: str,
13
+ auth_method_id: str,
14
+ timeout: float = 120,
15
+ probe_interval: float = 1,
16
+ print_auth_url: bool = True,
17
+ ) -> str:
18
+ """Interactively generate a token for use in IQCC backends.
19
+
20
+ Args:
21
+ auth_scope_id: The ID of the IQCC Boundary authentication scope.
22
+ auth_method_id: The ID of the IQCC Boundary authentication method.
23
+ timeout: Number of seconds to wait for the interactive authentication to complete.
24
+ probe_interval: Number of seconds to wait between probes of the authentication.
25
+ print_auth_url: Whether to print the authentication URL, useful for headless machines with no browser.
26
+
27
+ Returns:
28
+ The authentication token string to use directly in `IQCCBackendPreferences`.
29
+
30
+ Raises:
31
+ ClassiqError: In case timeout has reached before a successful authentication.
32
+ """
33
+ initiate_response = await ApiWrapper().call_iqcc_init_auth(
34
+ IQCCInitAuthData(auth_scope_id=auth_scope_id, auth_method_id=auth_method_id)
35
+ )
36
+
37
+ if print_auth_url:
38
+ print("Please proceed with authentication on your web browser.") # noqa: T201
39
+ print("If no window has opened, use this link to authenticate:") # noqa: T201
40
+ print(initiate_response.auth_url) # noqa: T201
41
+
42
+ webbrowser.open_new_tab(initiate_response.auth_url)
43
+
44
+ start_time = time.monotonic()
45
+ while True:
46
+ time.sleep(probe_interval)
47
+ probe_response = await ApiWrapper().call_iqcc_probe_auth(
48
+ IQCCProbeAuthData(
49
+ auth_scope_id=auth_scope_id,
50
+ auth_method_id=auth_method_id,
51
+ token_id=initiate_response.token_id,
52
+ )
53
+ )
54
+ if probe_response.auth_token is not None:
55
+ return probe_response.auth_token
56
+
57
+ if time.monotonic() - start_time > timeout:
58
+ raise ClassiqError(
59
+ f"Timeout has reached while probing IQCC authentication. Please try again and make sure to authenticate within {timeout} seconds, or increase the timeout."
60
+ )
61
+
62
+
63
+ generate_iqcc_token = syncify_function(generate_iqcc_token_async)
classiq/execution/jobs.py CHANGED
@@ -226,7 +226,7 @@ class ExecutionJob:
226
226
 
227
227
  async def _poll_job(self, timeout_sec: Optional[float] = None) -> None:
228
228
  def response_parser(json_response: JSONObject) -> Optional[bool]:
229
- self._details = ExecutionJobDetails.parse_obj(json_response)
229
+ self._details = ExecutionJobDetails.model_validate(json_response)
230
230
  if self.status.is_final():
231
231
  return True
232
232
  return None
@@ -262,7 +262,7 @@ class ExecutionJob:
262
262
 
263
263
  @property
264
264
  def ide_url(self) -> str:
265
- base_url = client().config.ide
265
+ base_url = client().config.ide.unicode_string()
266
266
  return urljoin(base_url, f"jobs/{self.id}")
267
267
 
268
268
  def open_in_ide(self) -> None:
classiq/executor.py CHANGED
@@ -27,7 +27,7 @@ BackendPreferencesAndResult: TypeAlias = Tuple[
27
27
  def _parse_serialized_qprog(
28
28
  quantum_program: SerializedQuantumProgram,
29
29
  ) -> QuantumProgram:
30
- return QuantumProgram.parse_raw(quantum_program)
30
+ return QuantumProgram.model_validate_json(quantum_program)
31
31
 
32
32
 
33
33
  async def execute_async(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
@@ -57,7 +57,7 @@ def set_quantum_program_execution_preferences(
57
57
  ) -> SerializedQuantumProgram:
58
58
  circuit = _parse_serialized_qprog(quantum_program)
59
59
  circuit.model.execution_preferences = preferences
60
- return SerializedQuantumProgram(circuit.json())
60
+ return SerializedQuantumProgram(circuit.model_dump_json())
61
61
 
62
62
 
63
63
  __all__ = [
@@ -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.51.1'
6
+ SEMVER_VERSION = '0.52.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -2,7 +2,7 @@ from typing import Dict, List, Optional
2
2
 
3
3
  import numpy
4
4
  import pydantic
5
- from pydantic import Field, conint, constr
5
+ from pydantic import ConfigDict, Field, StringConstraints
6
6
  from typing_extensions import Annotated
7
7
 
8
8
  from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
@@ -36,7 +36,8 @@ class HardwareListParams(pydantic.BaseModel):
36
36
  providers: List[Provider]
37
37
  from_ide: bool = Field(default=False)
38
38
 
39
- @pydantic.validator("providers", always=True)
39
+ @pydantic.field_validator("providers")
40
+ @classmethod
40
41
  def set_default_providers(
41
42
  cls, providers: Optional[List[AnalyzerProviderVendor]]
42
43
  ) -> List[AnalyzerProviderVendor]:
@@ -55,8 +56,12 @@ class AnalysisOptionalDevicesParams(HardwareListParams):
55
56
 
56
57
 
57
58
  class GateNamsMapping(pydantic.BaseModel):
58
- qasm_name: Annotated[str, constr(max_length=MAX_NAME_LENGTH)]
59
- display_name: Annotated[str, constr(max_length=MAX_NAME_LENGTH)]
59
+ qasm_name: Annotated[
60
+ str, Annotated[str, StringConstraints(max_length=MAX_NAME_LENGTH)]
61
+ ]
62
+ display_name: Annotated[
63
+ str, Annotated[str, StringConstraints(max_length=MAX_NAME_LENGTH)]
64
+ ]
60
65
 
61
66
 
62
67
  class LatexParams(AnalysisParams):
@@ -66,7 +71,7 @@ class LatexParams(AnalysisParams):
66
71
 
67
72
 
68
73
  class AnalysisHardwareTranspilationParams(pydantic.BaseModel):
69
- hardware_data: Optional[SynthesisHardwareData]
74
+ hardware_data: Optional[SynthesisHardwareData] = None
70
75
  random_seed: int
71
76
  transpilation_option: TranspilationOption
72
77
 
@@ -91,13 +96,18 @@ class CircuitAnalysisHardwareParams(AnalysisParams):
91
96
 
92
97
  class AnalysisRBParams(pydantic.BaseModel):
93
98
  hardware: str
94
- counts: List[Dict[str, Annotated[int, conint(strict=True, gt=0, le=MAX_COUNTS)]]]
95
- num_clifford: List[Annotated[int, conint(strict=True, gt=0, le=MAX_NUM_CLIFFORD)]]
99
+ counts: List[
100
+ Dict[
101
+ str, Annotated[int, Annotated[int, Field(strict=True, gt=0, le=MAX_COUNTS)]]
102
+ ]
103
+ ]
104
+ num_clifford: List[
105
+ Annotated[int, Annotated[int, Field(strict=True, gt=0, le=MAX_NUM_CLIFFORD)]]
106
+ ]
96
107
 
97
108
 
98
109
  class ChemistryGenerationParams(pydantic.BaseModel):
99
- class Config:
100
- title = "Chemistry"
110
+ model_config = ConfigDict(title="Chemistry")
101
111
 
102
112
  molecule: MoleculeProblem = pydantic.Field(
103
113
  title="Molecule",
@@ -17,16 +17,23 @@ class CytoScapePosition(pydantic.BaseModel):
17
17
 
18
18
  class CytoScapeEdgeData(pydantic.BaseModel):
19
19
  source: str = pydantic.Field(
20
- default=..., description="the Id of the Node that is the Source of the edge"
20
+ default=" ", description="the Id of the Node that is the Source of the edge"
21
21
  )
22
22
  target: str = pydantic.Field(
23
- default=..., description="the Id of the Node that is the Target the edge"
23
+ default=" ", description="the Id of the Node that is the Target the edge"
24
24
  )
25
25
 
26
+ @pydantic.model_validator(mode="before")
27
+ @classmethod
28
+ def _validate_values(cls, values: Dict[str, Any]) -> Dict[str, Any]:
29
+ values["source"] = str(values["source"]) or " "
30
+ values["target"] = str(values["target"]) or " "
31
+ return values
32
+
26
33
 
27
34
  class CytoScapeEdge(pydantic.BaseModel):
28
35
  data: CytoScapeEdgeData = pydantic.Field(
29
- default=..., description="Edge's Data, mainly the source and target of the Edge"
36
+ description="Edge's Data, mainly the source and target of the Edge"
30
37
  )
31
38
 
32
39
 
@@ -3,7 +3,7 @@ from uuid import UUID
3
3
 
4
4
  import pydantic
5
5
  from pydantic import Field
6
- from typing_extensions import Annotated
6
+ from typing_extensions import Annotated, Self
7
7
 
8
8
  from classiq.interface.analyzer.analysis_params import MAX_FILE_LENGTH
9
9
  from classiq.interface.enum_utils import StrEnum
@@ -74,12 +74,13 @@ class HardwareComparisonInformation(pydantic.BaseModel):
74
74
  default=..., description="Number of total gates."
75
75
  )
76
76
 
77
- @pydantic.root_validator
78
- def validate_equal_length(cls, values: Dict[str, list]) -> Dict[str, list]:
77
+ @pydantic.model_validator(mode="after")
78
+ def validate_equal_length(self) -> Self:
79
+ values = self.model_dump()
79
80
  lengths = list(map(len, values.values()))
80
81
  if len(set(lengths)) != 1:
81
82
  raise ClassiqValueError("All lists should have the same length")
82
- return values
83
+ return self
83
84
 
84
85
 
85
86
  # TODO: copy the types for `devices` & `providers` from `HardwareComparisonInformation`
@@ -112,7 +113,7 @@ HardwareComparisonGraphType = Annotated[
112
113
  ]
113
114
 
114
115
  _HARDWARE_COMPARISON_TABLE_COLUMNS_NAMES: Dict[str, str] = {
115
- s.upper(): s.capitalize() for s in SingleHardwareInformation.__fields__
116
+ s.upper(): s.capitalize() for s in SingleHardwareInformation.model_fields
116
117
  }
117
118
 
118
119