classiq 0.37.1__py3-none-any.whl → 0.65.3__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 (516) hide show
  1. classiq/__init__.py +49 -34
  2. classiq/_analyzer_extras/_ipywidgets_async_extension.py +3 -2
  3. classiq/_analyzer_extras/interactive_hardware.py +3 -3
  4. classiq/_internals/api_wrapper.py +241 -95
  5. classiq/_internals/async_utils.py +2 -77
  6. classiq/_internals/authentication/auth0.py +26 -10
  7. classiq/_internals/authentication/authentication.py +11 -0
  8. classiq/_internals/authentication/device.py +18 -8
  9. classiq/_internals/authentication/password_manager.py +40 -13
  10. classiq/_internals/authentication/token_manager.py +11 -6
  11. classiq/_internals/client.py +106 -37
  12. classiq/_internals/config.py +3 -4
  13. classiq/_internals/host_checker.py +38 -15
  14. classiq/_internals/jobs.py +56 -50
  15. classiq/_internals/type_validation.py +9 -9
  16. classiq/analyzer/__init__.py +1 -3
  17. classiq/analyzer/analyzer.py +50 -47
  18. classiq/analyzer/analyzer_utilities.py +15 -15
  19. classiq/analyzer/rb.py +19 -20
  20. classiq/analyzer/show_interactive_hack.py +30 -7
  21. classiq/analyzer/url_utils.py +2 -3
  22. classiq/applications/__init__.py +3 -12
  23. classiq/applications/chemistry/__init__.py +14 -10
  24. classiq/applications/chemistry/ansatz_parameters.py +4 -4
  25. classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +170 -170
  26. classiq/applications/chemistry/ground_state_problem.py +1 -1
  27. classiq/applications/combinatorial_helpers/allowed_constraints.py +23 -0
  28. classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
  29. classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
  30. classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +166 -0
  31. classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
  32. classiq/applications/combinatorial_helpers/encoding_utils.py +124 -0
  33. classiq/applications/combinatorial_helpers/memory.py +75 -0
  34. classiq/applications/combinatorial_helpers/optimization_model.py +193 -0
  35. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
  36. classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +46 -0
  37. classiq/applications/combinatorial_helpers/pyomo_utils.py +447 -0
  38. classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
  39. classiq/applications/combinatorial_helpers/transformations/encoding.py +189 -0
  40. classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +143 -0
  41. classiq/applications/combinatorial_helpers/transformations/ising_converter.py +120 -0
  42. classiq/applications/combinatorial_helpers/transformations/penalty.py +31 -0
  43. classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
  44. classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +74 -0
  45. classiq/applications/combinatorial_helpers/transformations/slack_variables.py +87 -0
  46. classiq/applications/combinatorial_optimization/__init__.py +24 -5
  47. classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py +2 -2
  48. classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +137 -0
  49. classiq/applications/combinatorial_optimization/combinatorial_problem.py +229 -0
  50. classiq/applications/combinatorial_optimization/examples/__init__.py +1 -3
  51. classiq/applications/finance/__init__.py +4 -5
  52. classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +50 -57
  53. classiq/applications/grover/__init__.py +9 -0
  54. classiq/applications/grover/grover_model_constructor.py +157 -0
  55. classiq/applications/hamiltonian/__init__.py +0 -0
  56. classiq/applications/hamiltonian/pauli_decomposition.py +113 -0
  57. classiq/applications/libraries/__init__.py +0 -0
  58. classiq/applications/libraries/qmci_library.py +22 -0
  59. classiq/applications/qnn/__init__.py +2 -4
  60. classiq/applications/qnn/circuit_utils.py +8 -8
  61. classiq/applications/qnn/datasets/__init__.py +9 -11
  62. classiq/applications/qnn/datasets/dataset_base_classes.py +7 -5
  63. classiq/applications/qnn/datasets/dataset_not.py +2 -1
  64. classiq/applications/qnn/datasets/dataset_parity.py +2 -2
  65. classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
  66. classiq/applications/qnn/gradients/simple_quantum_gradient.py +2 -1
  67. classiq/applications/qnn/qlayer.py +30 -10
  68. classiq/applications/qnn/torch_utils.py +4 -3
  69. classiq/applications/qnn/types.py +7 -7
  70. classiq/applications/qsvm/__init__.py +6 -4
  71. classiq/applications/qsvm/qsvm.py +4 -10
  72. classiq/applications/qsvm/qsvm_data_generation.py +5 -8
  73. classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +30 -28
  74. classiq/execution/__init__.py +8 -3
  75. classiq/execution/all_hardware_devices.py +11 -0
  76. classiq/execution/execution_session.py +400 -0
  77. classiq/execution/iqcc.py +63 -0
  78. classiq/execution/jobs.py +197 -25
  79. classiq/execution/qnn.py +79 -0
  80. classiq/executor.py +23 -117
  81. classiq/interface/_version.py +1 -1
  82. classiq/interface/analyzer/analysis_params.py +49 -16
  83. classiq/interface/analyzer/cytoscape_graph.py +15 -9
  84. classiq/interface/analyzer/result.py +36 -32
  85. classiq/interface/applications/qsvm.py +28 -25
  86. classiq/interface/ast_node.py +16 -0
  87. classiq/interface/backend/backend_preferences.py +390 -119
  88. classiq/interface/backend/ionq/ionq_quantum_program.py +15 -23
  89. classiq/interface/backend/pydantic_backend.py +27 -22
  90. classiq/interface/backend/quantum_backend_providers.py +70 -16
  91. classiq/interface/chemistry/fermionic_operator.py +43 -32
  92. classiq/interface/chemistry/ground_state_problem.py +42 -24
  93. classiq/interface/chemistry/molecule.py +20 -14
  94. classiq/interface/chemistry/operator.py +75 -236
  95. classiq/interface/combinatorial_optimization/encoding_types.py +1 -1
  96. classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +2 -4
  97. classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
  98. classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
  99. classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -4
  100. classiq/interface/combinatorial_optimization/examples/knapsack.py +3 -3
  101. classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
  102. classiq/interface/combinatorial_optimization/examples/mht.py +10 -6
  103. classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
  104. classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
  105. classiq/interface/combinatorial_optimization/examples/portfolio_variations.py +2 -2
  106. classiq/interface/combinatorial_optimization/examples/set_cover.py +3 -3
  107. classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
  108. classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
  109. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +14 -9
  110. classiq/interface/combinatorial_optimization/optimization_problem.py +2 -2
  111. classiq/interface/combinatorial_optimization/result.py +1 -3
  112. classiq/interface/combinatorial_optimization/solver_types.py +1 -1
  113. classiq/interface/debug_info/__init__.py +0 -0
  114. classiq/interface/debug_info/debug_info.py +86 -0
  115. classiq/interface/exceptions.py +201 -0
  116. classiq/interface/execution/iqcc.py +19 -0
  117. classiq/interface/execution/jobs.py +15 -12
  118. classiq/interface/execution/primitives.py +18 -0
  119. classiq/interface/executor/constants.py +1 -0
  120. classiq/interface/executor/estimation.py +2 -2
  121. classiq/interface/executor/execution_preferences.py +26 -143
  122. classiq/interface/executor/execution_request.py +36 -56
  123. classiq/interface/executor/execution_result.py +30 -8
  124. classiq/interface/executor/iqae_result.py +4 -6
  125. classiq/interface/executor/optimizer_preferences.py +34 -22
  126. classiq/interface/executor/{quantum_program.py → quantum_code.py} +44 -34
  127. classiq/interface/executor/quantum_instruction_set.py +3 -2
  128. classiq/interface/executor/register_initialization.py +12 -17
  129. classiq/interface/executor/result.py +122 -64
  130. classiq/interface/executor/vqe_result.py +11 -11
  131. classiq/interface/finance/function_input.py +42 -19
  132. classiq/interface/finance/gaussian_model_input.py +7 -5
  133. classiq/interface/finance/log_normal_model_input.py +6 -4
  134. classiq/interface/finance/model_input.py +6 -4
  135. classiq/interface/generator/adjacency.py +1 -3
  136. classiq/interface/generator/amplitude_loading.py +27 -14
  137. classiq/interface/generator/ansatz_library.py +5 -5
  138. classiq/interface/generator/application_apis/__init__.py +1 -0
  139. classiq/interface/generator/application_apis/arithmetic_declarations.py +17 -0
  140. classiq/interface/generator/application_apis/chemistry_declarations.py +27 -187
  141. classiq/interface/generator/application_apis/combinatorial_optimization_declarations.py +18 -21
  142. classiq/interface/generator/application_apis/entangler_declarations.py +11 -6
  143. classiq/interface/generator/application_apis/finance_declarations.py +48 -69
  144. classiq/interface/generator/application_apis/qsvm_declarations.py +0 -70
  145. classiq/interface/generator/arith/argument_utils.py +57 -6
  146. classiq/interface/generator/arith/arithmetic.py +37 -16
  147. classiq/interface/generator/arith/arithmetic_arg_type_validator.py +15 -17
  148. classiq/interface/generator/arith/arithmetic_expression_abc.py +70 -26
  149. classiq/interface/generator/arith/arithmetic_expression_parser.py +18 -12
  150. classiq/interface/generator/arith/arithmetic_expression_validator.py +61 -43
  151. classiq/interface/generator/arith/arithmetic_operations.py +19 -16
  152. classiq/interface/generator/arith/arithmetic_param_getters.py +7 -8
  153. classiq/interface/generator/arith/arithmetic_result_builder.py +21 -17
  154. classiq/interface/generator/arith/ast_node_rewrite.py +4 -3
  155. classiq/interface/generator/arith/binary_ops.py +375 -139
  156. classiq/interface/generator/arith/endianness.py +1 -1
  157. classiq/interface/generator/arith/extremum_operations.py +96 -23
  158. classiq/interface/generator/arith/logical_ops.py +16 -12
  159. classiq/interface/generator/arith/machine_precision.py +3 -0
  160. classiq/interface/generator/arith/number_utils.py +44 -48
  161. classiq/interface/generator/arith/register_user_input.py +70 -27
  162. classiq/interface/generator/arith/unary_ops.py +57 -46
  163. classiq/interface/generator/arith/uncomputation_methods.py +1 -1
  164. classiq/interface/generator/builtin_api_builder.py +2 -9
  165. classiq/interface/generator/chemistry_function_params.py +5 -5
  166. classiq/interface/generator/circuit_code/circuit_code.py +7 -7
  167. classiq/interface/generator/circuit_code/types_and_constants.py +4 -7
  168. classiq/interface/generator/commuting_pauli_exponentiation.py +8 -6
  169. classiq/interface/generator/compiler_keywords.py +8 -0
  170. classiq/interface/generator/complex_type.py +13 -25
  171. classiq/interface/generator/constant.py +3 -4
  172. classiq/interface/generator/control_state.py +35 -28
  173. classiq/interface/generator/copy.py +47 -0
  174. classiq/interface/generator/custom_ansatz.py +2 -5
  175. classiq/interface/generator/distance.py +3 -5
  176. classiq/interface/generator/excitations.py +3 -2
  177. classiq/interface/generator/expressions/atomic_expression_functions.py +26 -8
  178. classiq/interface/generator/expressions/enums/__init__.py +0 -10
  179. classiq/interface/generator/expressions/enums/finance_functions.py +12 -22
  180. classiq/interface/generator/expressions/evaluated_expression.py +21 -7
  181. classiq/interface/generator/expressions/expression.py +27 -15
  182. classiq/interface/generator/expressions/expression_constants.py +9 -3
  183. classiq/interface/generator/expressions/non_symbolic_expr.py +119 -0
  184. classiq/interface/generator/expressions/qmod_qarray_proxy.py +99 -0
  185. classiq/interface/generator/expressions/qmod_qscalar_proxy.py +59 -0
  186. classiq/interface/generator/expressions/qmod_qstruct_proxy.py +36 -0
  187. classiq/interface/generator/expressions/qmod_sized_proxy.py +30 -2
  188. classiq/interface/generator/expressions/qmod_struct_instance.py +14 -2
  189. classiq/interface/generator/expressions/sympy_supported_expressions.py +20 -11
  190. classiq/interface/generator/finance.py +3 -3
  191. classiq/interface/generator/function_param_library.py +6 -6
  192. classiq/interface/generator/function_param_list_without_self_reference.py +2 -10
  193. classiq/interface/generator/function_params.py +42 -69
  194. classiq/interface/generator/functions/__init__.py +0 -22
  195. classiq/interface/generator/functions/builtins/__init__.py +0 -0
  196. classiq/interface/generator/functions/builtins/internal_operators.py +16 -0
  197. classiq/interface/generator/functions/classical_function_declaration.py +18 -9
  198. classiq/interface/generator/functions/classical_type.py +47 -166
  199. classiq/interface/generator/functions/concrete_types.py +55 -0
  200. classiq/interface/generator/functions/function_declaration.py +13 -14
  201. classiq/interface/generator/functions/port_declaration.py +1 -13
  202. classiq/interface/generator/functions/qmod_python_interface.py +2 -1
  203. classiq/interface/generator/functions/type_name.py +90 -0
  204. classiq/interface/generator/generated_circuit_data.py +155 -22
  205. classiq/interface/generator/grover_diffuser.py +32 -25
  206. classiq/interface/generator/grover_operator.py +34 -23
  207. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +4 -6
  208. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  209. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +12 -8
  210. classiq/interface/generator/hardware/hardware_data.py +76 -36
  211. classiq/interface/generator/hardware_efficient_ansatz.py +38 -17
  212. classiq/interface/generator/hartree_fock.py +14 -4
  213. classiq/interface/generator/identity.py +10 -6
  214. classiq/interface/generator/linear_pauli_rotations.py +33 -19
  215. classiq/interface/generator/mcmt_method.py +1 -1
  216. classiq/interface/generator/mcu.py +20 -16
  217. classiq/interface/generator/mcx.py +29 -20
  218. classiq/interface/generator/model/__init__.py +2 -5
  219. classiq/interface/generator/model/constraints.py +27 -8
  220. classiq/interface/generator/model/model.py +32 -203
  221. classiq/interface/generator/model/preferences/preferences.py +118 -43
  222. classiq/{quantum_register.py → interface/generator/model/quantum_register.py} +27 -22
  223. classiq/interface/generator/oracles/arithmetic_oracle.py +2 -4
  224. classiq/interface/generator/oracles/custom_oracle.py +17 -13
  225. classiq/interface/generator/oracles/oracle_abc.py +9 -9
  226. classiq/interface/generator/partitioned_register.py +7 -7
  227. classiq/interface/generator/piecewise_linear_amplitude_loading.py +45 -29
  228. classiq/interface/generator/preferences/optimization.py +1 -2
  229. classiq/interface/generator/qpe.py +47 -34
  230. classiq/interface/generator/qsvm.py +13 -17
  231. classiq/interface/generator/quantum_function_call.py +107 -87
  232. classiq/interface/generator/{generated_circuit.py → quantum_program.py} +50 -37
  233. classiq/interface/generator/range_types.py +13 -12
  234. classiq/interface/generator/register_role.py +18 -6
  235. classiq/interface/generator/slice_parsing_utils.py +11 -6
  236. classiq/interface/generator/standard_gates/controlled_standard_gates.py +32 -39
  237. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  238. classiq/interface/generator/standard_gates/standard_gates.py +3 -3
  239. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  240. classiq/interface/generator/state_preparation/bell_state_preparation.py +3 -3
  241. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  242. classiq/interface/generator/state_preparation/distributions.py +16 -15
  243. classiq/interface/generator/state_preparation/metrics.py +5 -7
  244. classiq/interface/generator/state_preparation/state_preparation.py +30 -23
  245. classiq/interface/generator/synthesis_metadata/synthesis_duration.py +0 -4
  246. classiq/interface/generator/synthesis_metadata/synthesis_execution_data.py +20 -6
  247. classiq/interface/generator/transpiler_basis_gates.py +7 -3
  248. classiq/interface/generator/types/builtin_enum_declarations.py +178 -0
  249. classiq/interface/generator/types/compilation_metadata.py +6 -0
  250. classiq/interface/generator/types/enum_declaration.py +54 -0
  251. classiq/interface/generator/types/qstruct_declaration.py +18 -0
  252. classiq/interface/generator/types/struct_declaration.py +15 -14
  253. classiq/interface/generator/ucc.py +9 -6
  254. classiq/interface/generator/unitary_gate.py +10 -6
  255. classiq/interface/generator/user_defined_function_params.py +4 -1
  256. classiq/interface/generator/validations/flow_graph.py +11 -9
  257. classiq/interface/generator/validations/validator_functions.py +8 -6
  258. classiq/interface/generator/visitor.py +23 -16
  259. classiq/interface/hardware.py +31 -10
  260. classiq/interface/helpers/classproperty.py +8 -0
  261. classiq/interface/helpers/custom_encoders.py +3 -0
  262. classiq/interface/helpers/custom_pydantic_types.py +40 -50
  263. classiq/interface/helpers/datastructures.py +26 -0
  264. classiq/interface/helpers/hashable_mixin.py +3 -2
  265. classiq/interface/helpers/hashable_pydantic_base_model.py +2 -1
  266. classiq/interface/helpers/pydantic_model_helpers.py +7 -11
  267. classiq/interface/helpers/validation_helpers.py +4 -21
  268. classiq/interface/helpers/versioned_model.py +1 -1
  269. classiq/interface/ide/ide_data.py +16 -20
  270. classiq/interface/ide/visual_model.py +130 -0
  271. classiq/interface/interface_version.py +1 -0
  272. classiq/interface/jobs.py +35 -6
  273. classiq/interface/model/allocate.py +16 -0
  274. classiq/interface/model/bind_operation.py +44 -14
  275. classiq/interface/model/classical_if.py +15 -0
  276. classiq/interface/model/classical_parameter_declaration.py +33 -3
  277. classiq/interface/model/control.py +45 -0
  278. classiq/interface/model/handle_binding.py +298 -20
  279. classiq/interface/model/inplace_binary_operation.py +31 -26
  280. classiq/interface/model/invert.py +12 -0
  281. classiq/interface/model/model.py +87 -73
  282. classiq/interface/model/native_function_definition.py +16 -21
  283. classiq/interface/model/parameter.py +13 -0
  284. classiq/interface/model/phase_operation.py +11 -0
  285. classiq/interface/model/port_declaration.py +27 -9
  286. classiq/interface/model/power.py +14 -0
  287. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +38 -21
  288. classiq/interface/model/quantum_expressions/arithmetic_operation.py +51 -14
  289. classiq/interface/model/quantum_expressions/quantum_expression.py +12 -35
  290. classiq/interface/model/quantum_function_call.py +146 -462
  291. classiq/interface/model/quantum_function_declaration.py +193 -152
  292. classiq/interface/model/quantum_lambda_function.py +65 -0
  293. classiq/interface/model/quantum_statement.py +71 -12
  294. classiq/interface/model/quantum_type.py +205 -67
  295. classiq/interface/model/quantum_variable_declaration.py +4 -26
  296. classiq/interface/model/repeat.py +15 -0
  297. classiq/interface/model/statement_block.py +58 -0
  298. classiq/interface/model/validation_handle.py +13 -6
  299. classiq/interface/model/variable_declaration_statement.py +3 -1
  300. classiq/interface/model/within_apply_operation.py +13 -0
  301. classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
  302. classiq/interface/server/global_versions.py +6 -7
  303. classiq/interface/server/routes.py +22 -21
  304. classiq/interface/source_reference.py +59 -0
  305. classiq/model_expansions/__init__.py +0 -0
  306. classiq/model_expansions/atomic_expression_functions_defs.py +253 -0
  307. classiq/model_expansions/capturing/__init__.py +0 -0
  308. classiq/model_expansions/capturing/captured_vars.py +435 -0
  309. classiq/model_expansions/capturing/mangling_utils.py +56 -0
  310. classiq/model_expansions/closure.py +171 -0
  311. classiq/model_expansions/debug_flag.py +3 -0
  312. classiq/model_expansions/evaluators/__init__.py +0 -0
  313. classiq/model_expansions/evaluators/arg_type_match.py +158 -0
  314. classiq/model_expansions/evaluators/argument_types.py +42 -0
  315. classiq/model_expansions/evaluators/classical_expression.py +36 -0
  316. classiq/model_expansions/evaluators/control.py +144 -0
  317. classiq/model_expansions/evaluators/parameter_types.py +226 -0
  318. classiq/model_expansions/evaluators/quantum_type_utils.py +239 -0
  319. classiq/model_expansions/evaluators/type_type_match.py +90 -0
  320. classiq/model_expansions/expression_evaluator.py +135 -0
  321. classiq/model_expansions/expression_renamer.py +76 -0
  322. classiq/model_expansions/function_builder.py +247 -0
  323. classiq/model_expansions/generative_functions.py +158 -0
  324. classiq/model_expansions/interpreters/__init__.py +0 -0
  325. classiq/model_expansions/interpreters/base_interpreter.py +263 -0
  326. classiq/model_expansions/interpreters/frontend_generative_interpreter.py +28 -0
  327. classiq/model_expansions/interpreters/generative_interpreter.py +249 -0
  328. classiq/model_expansions/model_tables.py +18 -0
  329. classiq/model_expansions/quantum_operations/__init__.py +9 -0
  330. classiq/model_expansions/quantum_operations/bind.py +60 -0
  331. classiq/model_expansions/quantum_operations/call_emitter.py +266 -0
  332. classiq/model_expansions/quantum_operations/classicalif.py +53 -0
  333. classiq/model_expansions/quantum_operations/declarative_call_emitter.py +87 -0
  334. classiq/model_expansions/quantum_operations/emitter.py +181 -0
  335. classiq/model_expansions/quantum_operations/quantum_function_call.py +33 -0
  336. classiq/model_expansions/quantum_operations/repeat.py +56 -0
  337. classiq/model_expansions/quantum_operations/shallow_emitter.py +180 -0
  338. classiq/model_expansions/quantum_operations/variable_decleration.py +28 -0
  339. classiq/model_expansions/scope.py +240 -0
  340. classiq/model_expansions/scope_initialization.py +150 -0
  341. classiq/model_expansions/sympy_conversion/__init__.py +0 -0
  342. classiq/model_expansions/sympy_conversion/arithmetics.py +49 -0
  343. classiq/model_expansions/sympy_conversion/expression_to_sympy.py +179 -0
  344. classiq/model_expansions/sympy_conversion/sympy_to_python.py +123 -0
  345. classiq/model_expansions/transformers/__init__.py +0 -0
  346. classiq/model_expansions/transformers/ast_renamer.py +26 -0
  347. classiq/model_expansions/transformers/var_splitter.py +299 -0
  348. classiq/model_expansions/utils/__init__.py +0 -0
  349. classiq/model_expansions/utils/counted_name_allocator.py +11 -0
  350. classiq/model_expansions/utils/handles_collector.py +33 -0
  351. classiq/model_expansions/visitors/__init__.py +0 -0
  352. classiq/model_expansions/visitors/boolean_expression_transformers.py +214 -0
  353. classiq/model_expansions/visitors/variable_references.py +144 -0
  354. classiq/open_library/__init__.py +4 -0
  355. classiq/open_library/functions/__init__.py +130 -0
  356. classiq/open_library/functions/amplitude_estimation.py +30 -0
  357. classiq/open_library/functions/discrete_sine_cosine_transform.py +181 -0
  358. classiq/open_library/functions/grover.py +157 -0
  359. classiq/open_library/functions/hea.py +115 -0
  360. classiq/open_library/functions/linear_pauli_rotation.py +82 -0
  361. classiq/open_library/functions/modular_exponentiation.py +201 -0
  362. classiq/open_library/functions/qaoa_penalty.py +117 -0
  363. classiq/open_library/functions/qft_functions.py +54 -0
  364. classiq/open_library/functions/qpe.py +46 -0
  365. classiq/open_library/functions/qsvt.py +331 -0
  366. classiq/open_library/functions/state_preparation.py +301 -0
  367. classiq/open_library/functions/swap_test.py +27 -0
  368. classiq/open_library/functions/utility_functions.py +81 -0
  369. classiq/open_library/functions/variational.py +52 -0
  370. classiq/qmod/__init__.py +17 -10
  371. classiq/qmod/builtins/__init__.py +19 -2
  372. classiq/qmod/builtins/classical_execution_primitives.py +60 -47
  373. classiq/qmod/builtins/classical_functions.py +44 -38
  374. classiq/qmod/builtins/constants.py +10 -0
  375. classiq/qmod/builtins/enums.py +208 -0
  376. classiq/qmod/builtins/functions/__init__.py +137 -0
  377. classiq/qmod/builtins/functions/allocation.py +150 -0
  378. classiq/qmod/builtins/functions/arithmetic.py +55 -0
  379. classiq/qmod/builtins/functions/benchmarking.py +8 -0
  380. classiq/qmod/builtins/functions/chemistry.py +91 -0
  381. classiq/qmod/builtins/functions/exponentiation.py +105 -0
  382. classiq/qmod/builtins/functions/finance.py +34 -0
  383. classiq/qmod/builtins/functions/operators.py +16 -0
  384. classiq/qmod/builtins/functions/qsvm.py +24 -0
  385. classiq/qmod/builtins/functions/standard_gates.py +651 -0
  386. classiq/qmod/builtins/operations.py +379 -57
  387. classiq/qmod/builtins/structs.py +103 -80
  388. classiq/qmod/cfunc.py +42 -0
  389. classiq/qmod/classical_function.py +8 -20
  390. classiq/qmod/cparam.py +64 -0
  391. classiq/qmod/create_model_function.py +56 -0
  392. classiq/qmod/declaration_inferrer.py +145 -112
  393. classiq/qmod/expression_query.py +39 -0
  394. classiq/qmod/generative.py +42 -0
  395. classiq/qmod/model_state_container.py +19 -5
  396. classiq/qmod/native/__init__.py +7 -0
  397. classiq/qmod/native/expression_to_qmod.py +194 -0
  398. classiq/qmod/native/pretty_printer.py +401 -0
  399. classiq/qmod/pretty_print/__init__.py +7 -0
  400. classiq/qmod/pretty_print/expression_to_python.py +222 -0
  401. classiq/qmod/pretty_print/pretty_printer.py +572 -0
  402. classiq/qmod/python_classical_type.py +67 -0
  403. classiq/qmod/qfunc.py +79 -0
  404. classiq/qmod/qmod_constant.py +143 -0
  405. classiq/qmod/qmod_parameter.py +84 -53
  406. classiq/qmod/qmod_variable.py +497 -100
  407. classiq/qmod/quantum_callable.py +17 -7
  408. classiq/qmod/quantum_expandable.py +278 -105
  409. classiq/qmod/quantum_function.py +232 -48
  410. classiq/qmod/semantics/__init__.py +0 -0
  411. classiq/qmod/semantics/annotation/__init__.py +0 -0
  412. classiq/qmod/semantics/annotation/call_annotation.py +92 -0
  413. classiq/qmod/semantics/annotation/qstruct_annotator.py +23 -0
  414. classiq/qmod/semantics/error_manager.py +88 -0
  415. classiq/qmod/semantics/lambdas.py +25 -0
  416. classiq/qmod/semantics/static_semantics_visitor.py +384 -0
  417. classiq/qmod/semantics/validation/__init__.py +0 -0
  418. classiq/qmod/semantics/validation/constants_validation.py +16 -0
  419. classiq/qmod/semantics/validation/func_call_validation.py +99 -0
  420. classiq/qmod/semantics/validation/function_name_collisions_validation.py +23 -0
  421. classiq/qmod/semantics/validation/handle_validation.py +85 -0
  422. classiq/qmod/semantics/validation/main_validation.py +33 -0
  423. classiq/qmod/semantics/validation/types_validation.py +128 -0
  424. classiq/qmod/symbolic.py +178 -111
  425. classiq/qmod/symbolic_expr.py +36 -12
  426. classiq/qmod/symbolic_type.py +2 -5
  427. classiq/qmod/type_attribute_remover.py +32 -0
  428. classiq/qmod/utilities.py +108 -1
  429. classiq/qmod/write_qmod.py +53 -0
  430. classiq/synthesis.py +210 -22
  431. {classiq-0.37.1.dist-info → classiq-0.65.3.dist-info}/METADATA +16 -8
  432. classiq-0.65.3.dist-info/RECORD +521 -0
  433. {classiq-0.37.1.dist-info → classiq-0.65.3.dist-info}/WHEEL +1 -1
  434. classiq/_internals/_qfunc_ext.py +0 -6
  435. classiq/applications/benchmarking/__init__.py +0 -9
  436. classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
  437. classiq/applications/numpy_utils.py +0 -37
  438. classiq/applications_model_constructors/__init__.py +0 -17
  439. classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
  440. classiq/applications_model_constructors/grover_model_constructor.py +0 -227
  441. classiq/applications_model_constructors/libraries/ampltitude_estimation_library.py +0 -11
  442. classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
  443. classiq/builtin_functions/__init__.py +0 -43
  444. classiq/builtin_functions/amplitude_loading.py +0 -3
  445. classiq/builtin_functions/binary_ops.py +0 -1
  446. classiq/builtin_functions/exponentiation.py +0 -5
  447. classiq/builtin_functions/qpe.py +0 -4
  448. classiq/builtin_functions/qsvm.py +0 -7
  449. classiq/builtin_functions/range_types.py +0 -5
  450. classiq/builtin_functions/standard_gates.py +0 -1
  451. classiq/builtin_functions/state_preparation.py +0 -6
  452. classiq/builtin_functions/suzuki_trotter.py +0 -3
  453. classiq/exceptions.py +0 -131
  454. classiq/interface/executor/aws_execution_cost.py +0 -72
  455. classiq/interface/executor/error_mitigation.py +0 -6
  456. classiq/interface/generator/credit_risk_example/linear_gci.py +0 -115
  457. classiq/interface/generator/credit_risk_example/weighted_adder.py +0 -59
  458. classiq/interface/generator/expressions/enums/chemistry.py +0 -28
  459. classiq/interface/generator/expressions/enums/classical_enum.py +0 -5
  460. classiq/interface/generator/expressions/enums/ladder_operator.py +0 -16
  461. classiq/interface/generator/expressions/enums/optimizers.py +0 -9
  462. classiq/interface/generator/expressions/enums/pauli.py +0 -8
  463. classiq/interface/generator/expressions/enums/qsvm_feature_map_entanglement.py +0 -9
  464. classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
  465. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
  466. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +0 -641
  467. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/exponentiation_functions.py +0 -89
  468. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +0 -862
  469. classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
  470. classiq/interface/generator/functions/foreign_function_definition.py +0 -106
  471. classiq/interface/generator/functions/function_implementation.py +0 -103
  472. classiq/interface/generator/functions/native_function_definition.py +0 -153
  473. classiq/interface/generator/functions/quantum_function_declaration.py +0 -69
  474. classiq/interface/generator/functions/register.py +0 -42
  475. classiq/interface/generator/functions/register_mapping_data.py +0 -102
  476. classiq/interface/generator/inequality_mixer.py +0 -51
  477. classiq/interface/generator/model/classical_main_validator.py +0 -106
  478. classiq/interface/generator/range_mixer.py +0 -56
  479. classiq/interface/generator/state_propagator.py +0 -63
  480. classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -2
  481. classiq/interface/generator/types/builtin_struct_declarations/pauli_struct_declarations.py +0 -22
  482. classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
  483. classiq/interface/generator/types/combinatorial_problem.py +0 -26
  484. classiq/interface/ide/show.py +0 -34
  485. classiq/interface/model/common_model_types.py +0 -23
  486. classiq/interface/model/numeric_reinterpretation.py +0 -25
  487. classiq/interface/model/operator_synthesis_data.py +0 -48
  488. classiq/interface/model/quantum_expressions/control_state.py +0 -38
  489. classiq/interface/model/quantum_if_operation.py +0 -95
  490. classiq/interface/model/resolvers/function_call_resolver.py +0 -43
  491. classiq/interface/model/validations/handle_validation_base.py +0 -55
  492. classiq/interface/model/validations/handles_validator.py +0 -154
  493. classiq/interface/model/validations/port_to_wire_name_generator.py +0 -12
  494. classiq/model/__init__.py +0 -14
  495. classiq/model/composite_function_generator.py +0 -33
  496. classiq/model/function_handler.py +0 -466
  497. classiq/model/function_handler.pyi +0 -152
  498. classiq/model/logic_flow.py +0 -149
  499. classiq/model/logic_flow_change_handler.py +0 -71
  500. classiq/model/model.py +0 -246
  501. classiq/qmod/builtins/functions.py +0 -896
  502. classiq/qmod/qmod_struct.py +0 -37
  503. classiq/quantum_functions/__init__.py +0 -17
  504. classiq/quantum_functions/annotation_parser.py +0 -207
  505. classiq/quantum_functions/decorators.py +0 -22
  506. classiq/quantum_functions/function_library.py +0 -181
  507. classiq/quantum_functions/function_parser.py +0 -74
  508. classiq/quantum_functions/quantum_function.py +0 -236
  509. classiq-0.37.1.dist-info/RECORD +0 -418
  510. /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
  511. /classiq/{interface/generator/credit_risk_example → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
  512. /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/pauli_helpers}/__init__.py +0 -0
  513. /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/py.typed} +0 -0
  514. /classiq/{interface/model/resolvers → applications/combinatorial_helpers/solvers}/__init__.py +0 -0
  515. /classiq/{interface/model/validations → applications/combinatorial_helpers/transformations}/__init__.py +0 -0
  516. /classiq/{_internals → interface}/enum_utils.py +0 -0
@@ -1,20 +1,36 @@
1
1
  import urllib.parse
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, Optional, Union
3
+ from typing import Any, 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
- from classiq.exceptions import ClassiqAuthenticationError
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:
@@ -40,9 +56,9 @@ class Auth0:
40
56
  async def _make_request(
41
57
  self,
42
58
  url: str,
43
- payload: Dict[str, str],
59
+ payload: dict[str, str],
44
60
  allow_error: Union[bool, int] = False,
45
- ) -> Dict[str, Any]:
61
+ ) -> dict[str, Any]:
46
62
  encoded_payload = urllib.parse.urlencode(payload)
47
63
  client: AsyncClient
48
64
  async with AsyncClient(
@@ -60,7 +76,7 @@ class Auth0:
60
76
  f"Request to Auth0 failed with error code {code}: {data.get('error')}"
61
77
  )
62
78
 
63
- async def get_device_data(self, get_refresh_token: bool = True) -> Dict[str, Any]:
79
+ async def get_device_data(self, get_refresh_token: bool = True) -> dict[str, Any]:
64
80
  payload = {
65
81
  "client_id": self._auth_settings.client_id,
66
82
  "audience": self._auth_settings.audience,
@@ -73,7 +89,7 @@ class Auth0:
73
89
  payload=payload,
74
90
  )
75
91
 
76
- async def poll_tokens(self, device_code: str) -> Dict[str, Any]:
92
+ async def poll_tokens(self, device_code: str) -> dict[str, Any]:
77
93
  payload = {
78
94
  "client_id": self._client_id,
79
95
  "device_code": device_code,
@@ -3,6 +3,17 @@ from classiq._internals.client import client
3
3
 
4
4
 
5
5
  def authenticate(overwrite: bool = False) -> None:
6
+ """
7
+
8
+ Authenticate to access the Classiq platform.
9
+
10
+ Args:
11
+ overwrite: A flag indicating whether to overwrite the existing
12
+ authentication tokens. Defaults to `False`.
13
+
14
+ If you are not registered, please visit the Classiq platform
15
+ to complete registration: https://platform.classiq.io/
16
+ """
6
17
  async_utils.run(authenticate_async(overwrite))
7
18
 
8
19
 
@@ -1,11 +1,16 @@
1
1
  import asyncio
2
2
  import webbrowser
3
+ from collections.abc import Iterable
3
4
  from datetime import timedelta
4
- from typing import Any, Dict, Iterable, Optional, TypeVar
5
+ from typing import Any, Optional, TypeVar
6
+
7
+ from classiq.interface.exceptions import (
8
+ ClassiqAuthenticationError,
9
+ ClassiqExpiredTokenError,
10
+ )
5
11
 
6
12
  from classiq._internals.async_utils import poll_for
7
13
  from classiq._internals.authentication.auth0 import Auth0, Tokens
8
- from classiq.exceptions import ClassiqAuthenticationError, ClassiqExpiredTokenError
9
14
 
10
15
  T = TypeVar("T")
11
16
 
@@ -22,13 +27,13 @@ class DeviceRegistrar:
22
27
  cls, get_refresh_token: bool = True, text_only: bool = False
23
28
  ) -> Tokens:
24
29
  auth0_client = Auth0()
25
- data: Dict[str, Any] = await auth0_client.get_device_data(
30
+ data: dict[str, Any] = await auth0_client.get_device_data(
26
31
  get_refresh_token=get_refresh_token
27
32
  )
28
33
 
29
- print(f"Your user code: {data['user_code']}")
34
+ print(f"Your user code: {data['user_code']}") # noqa: T201
30
35
  verification_url = data["verification_uri_complete"]
31
- print(
36
+ print( # noqa: T201
32
37
  f"If a browser doesn't automatically open, please visit this URL from any trusted device: {verification_url}"
33
38
  )
34
39
  if not text_only:
@@ -44,7 +49,7 @@ class DeviceRegistrar:
44
49
 
45
50
  @classmethod
46
51
  def _handle_ready_data(
47
- cls, data: Dict[str, Any], get_refresh_token: bool
52
+ cls, data: dict[str, Any], get_refresh_token: bool
48
53
  ) -> Tokens:
49
54
  access_token: Optional[str] = data.get("access_token")
50
55
  # If refresh token was not requested, this would be None
@@ -68,7 +73,7 @@ class DeviceRegistrar:
68
73
  timeout: float,
69
74
  get_refresh_token: bool = True,
70
75
  ) -> Tokens:
71
- async def poller():
76
+ async def poller() -> dict[str, Any]:
72
77
  nonlocal device_code
73
78
  return await auth0_client.poll_tokens(device_code=device_code)
74
79
 
@@ -92,7 +97,12 @@ class DeviceRegistrar:
92
97
  elif error_code == "expired_token":
93
98
  raise ClassiqExpiredTokenError(cls._TIMEOUT_ERROR)
94
99
  elif error_code == "access_denied":
95
- error_description: str = data.get("error_description")
100
+ error_description = data.get("error_description")
101
+ if error_description is None:
102
+ raise ClassiqAuthenticationError(
103
+ "Failed authenticating to Classiq, missing error description"
104
+ )
105
+
96
106
  raise ClassiqAuthenticationError(error_description)
97
107
  else:
98
108
  raise ClassiqAuthenticationError(
@@ -5,34 +5,57 @@ 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, Optional
9
9
 
10
10
  import keyring
11
11
  from keyring.backends import fail
12
+ from pydantic import Field
13
+ from pydantic_settings import BaseSettings, SettingsConfigDict
12
14
 
13
15
  _logger = logging.getLogger(__name__)
14
16
 
15
17
 
18
+ class PasswordManagerSettings(BaseSettings):
19
+ ACCESS_TOKEN_KEY: str = Field(
20
+ default="classiqTokenAccount", validation_alias="CLASSIQ_ACCESS_TOKEN_ACCOUNT"
21
+ )
22
+ REFRESH_TOKEN_KEY: str = Field(
23
+ default="classiqRefershTokenAccount",
24
+ validation_alias="CLASSIQ_REFRESH_TOKEN_ACCOUNT",
25
+ )
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
+
37
+
16
38
  class PasswordManager(abc.ABC):
17
39
  _SERVICE_NAME: str = "classiqTokenService"
18
- _ACCESS_TOKEN_KEY: str = "classiqTokenAccount"
19
- _REFRESH_TOKEN_KEY: str = "classiqRefershTokenAccount"
40
+
41
+ def __init__(self) -> None:
42
+ self._settings = PasswordManagerSettings()
20
43
 
21
44
  @property
22
45
  def access_token(self) -> Optional[str]:
23
- return self._get(key=self._ACCESS_TOKEN_KEY)
46
+ return self._get(key=self._settings.ACCESS_TOKEN_KEY)
24
47
 
25
48
  @access_token.setter
26
49
  def access_token(self, access_token: Optional[str]) -> None:
27
- self._set(key=self._ACCESS_TOKEN_KEY, value=access_token)
50
+ self._set(key=self._settings.ACCESS_TOKEN_KEY, value=access_token)
28
51
 
29
52
  @property
30
53
  def refresh_token(self) -> Optional[str]:
31
- return self._get(key=self._REFRESH_TOKEN_KEY)
54
+ return self._get(key=self._settings.REFRESH_TOKEN_KEY)
32
55
 
33
56
  @refresh_token.setter
34
57
  def refresh_token(self, refresh_token: Optional[str]) -> None:
35
- self._set(key=self._REFRESH_TOKEN_KEY, value=refresh_token)
58
+ self._set(key=self._settings.REFRESH_TOKEN_KEY, value=refresh_token)
36
59
 
37
60
  @abc.abstractmethod
38
61
  def _get(self, key: str) -> Optional[str]:
@@ -46,8 +69,9 @@ class PasswordManager(abc.ABC):
46
69
  def _clear(self, key: str) -> None:
47
70
  pass
48
71
 
72
+ @staticmethod
49
73
  @abc.abstractmethod
50
- def is_supported(self) -> bool:
74
+ def is_supported() -> bool:
51
75
  pass
52
76
 
53
77
 
@@ -71,7 +95,8 @@ class KeyringPasswordManager(PasswordManager):
71
95
  username=key,
72
96
  )
73
97
 
74
- def is_supported(self) -> bool:
98
+ @staticmethod
99
+ def is_supported() -> bool:
75
100
  return not isinstance(keyring.get_keyring(), fail.Keyring)
76
101
 
77
102
 
@@ -85,7 +110,8 @@ class DummyPasswordManager(PasswordManager):
85
110
  def _clear(self, key: str) -> None:
86
111
  return
87
112
 
88
- def is_supported(self) -> bool:
113
+ @staticmethod
114
+ def is_supported() -> bool:
89
115
  return True
90
116
 
91
117
 
@@ -98,12 +124,12 @@ class FilePasswordManager(PasswordManager):
98
124
  super().__init__()
99
125
  self.credentials_file = pathlib.Path(self._CLASSIQ_CREDENTIALS_FILE_PATH)
100
126
 
101
- def _update_file(self, token_dict: Dict) -> None:
127
+ def _update_file(self, token_dict: dict) -> None:
102
128
  self.credentials_file.touch()
103
129
  self.credentials_file.chmod(stat.S_IRUSR | stat.S_IWUSR)
104
130
  self.credentials_file.write_text(json.dumps(token_dict))
105
131
 
106
- def _get_token_dict(self) -> Dict:
132
+ def _get_token_dict(self) -> dict:
107
133
  if self.credentials_file.exists():
108
134
  return json.loads(self.credentials_file.read_text())
109
135
  return {}
@@ -125,5 +151,6 @@ class FilePasswordManager(PasswordManager):
125
151
  token_dict.pop(key)
126
152
  self._update_file(token_dict)
127
153
 
128
- def is_supported(self) -> bool:
154
+ @staticmethod
155
+ def is_supported() -> bool:
129
156
  return "windows" not in platform.platform().lower()
@@ -2,18 +2,23 @@ import argparse
2
2
  import logging
3
3
  import threading
4
4
  import warnings
5
+ from collections.abc import Sequence
5
6
  from typing import Optional
6
7
 
8
+ from classiq.interface.exceptions import (
9
+ ClassiqAuthenticationError,
10
+ ClassiqPasswordManagerSelectionError,
11
+ )
12
+
7
13
  from classiq._internals.authentication import password_manager as pm
8
14
  from classiq._internals.authentication.auth0 import Auth0
9
15
  from classiq._internals.authentication.device import DeviceRegistrar, Tokens
10
16
  from classiq._internals.config import Configuration
11
- from classiq.exceptions import (
12
- ClassiqAuthenticationError,
13
- ClassiqPasswordManagerSelectionError,
14
- )
15
17
 
16
- PASSWORD_MANAGERS = [pm.KeyringPasswordManager(), pm.FilePasswordManager()]
18
+ PASSWORD_MANAGERS: Sequence[type[pm.PasswordManager]] = [
19
+ pm.KeyringPasswordManager,
20
+ pm.FilePasswordManager,
21
+ ]
17
22
  _logger = logging.getLogger(__name__)
18
23
 
19
24
 
@@ -57,7 +62,7 @@ class TokenManager:
57
62
  return pm.FilePasswordManager()
58
63
  for password_manager in PASSWORD_MANAGERS:
59
64
  if password_manager.is_supported():
60
- return password_manager
65
+ return password_manager()
61
66
  raise ClassiqPasswordManagerSelectionError(
62
67
  "Password Manager not found, we could not store your credentials securely. Please contact support@classiq.io"
63
68
  )
@@ -1,22 +1,26 @@
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
- from typing import Any, Awaitable, Callable, Dict, NoReturn, Optional, Union
9
+ import time
10
+ from collections.abc import Awaitable
11
+ from types import TracebackType
12
+ from typing import Any, Callable, NoReturn, Optional, TypeVar, Union
10
13
 
11
14
  import httpx
12
- from packaging.version import Version
15
+ from typing_extensions import ParamSpec
13
16
 
14
17
  from classiq.interface._version import VERSION as _VERSION
18
+ from classiq.interface.exceptions import ClassiqAPIError, ClassiqExpiredTokenError
19
+ from classiq.interface.interface_version import INTERFACE_VERSION
15
20
 
16
21
  from classiq._internals import config
17
22
  from classiq._internals.authentication import token_manager
18
23
  from classiq._internals.host_checker import HostChecker
19
- from classiq.exceptions import ClassiqAPIError, ClassiqExpiredTokenError
20
24
 
21
25
  _FRONTEND_VARIANT: str = "classiq-sdk"
22
26
  _INTERFACE_VARIANT: str = "classiq-interface-sdk"
@@ -26,7 +30,7 @@ _logger = logging.getLogger(__name__)
26
30
 
27
31
  _RETRY_COUNT = 2
28
32
 
29
- Headers = Dict[str, str]
33
+ Headers = dict[str, str]
30
34
 
31
35
  APPROVED_API_ERROR_MESSAGES_FOR_RESTART = [
32
36
  "Call to API failed with code 502",
@@ -80,9 +84,13 @@ def _get_user_agent_header() -> Headers:
80
84
  }
81
85
 
82
86
 
87
+ Ret = TypeVar("Ret")
88
+ P = ParamSpec("P")
89
+
90
+
83
91
  def try_again_on_failure(
84
- func: Callable[..., Awaitable[Any]]
85
- ) -> Callable[..., Awaitable[Any]]:
92
+ func: Callable[P, Awaitable[Ret]]
93
+ ) -> Callable[P, Awaitable[Ret]]:
86
94
  def check_approved_api_error(error_message: str) -> bool:
87
95
  for approved_api_error in APPROVED_API_ERROR_MESSAGES_FOR_RESTART:
88
96
  if approved_api_error in error_message:
@@ -93,7 +101,7 @@ def try_again_on_failure(
93
101
  raise TypeError("Must decorate a coroutine function")
94
102
 
95
103
  @functools.wraps(func)
96
- async def wrapper(*args, **kwargs):
104
+ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> Ret:
97
105
  for i in range(_RETRY_COUNT):
98
106
  try:
99
107
  return await func(*args, **kwargs)
@@ -123,32 +131,49 @@ def try_again_on_failure(
123
131
  "There is problem with the connection to Classiq's server. Trying again"
124
132
  )
125
133
  await asyncio.sleep(API_ERROR_SLEEP_TIME)
134
+ raise ClassiqAPIError(
135
+ "Reached max retries when trying to connect to Classiq's server"
136
+ )
126
137
 
127
138
  return wrapper
128
139
 
129
140
 
141
+ class _AsyncNullContext(contextlib.AbstractAsyncContextManager):
142
+ """
143
+ This class is meant to replace `contextlib.nullcontext`, which hadn't supported
144
+ async context manager until python 3.10.
145
+ """
146
+
147
+ def __init__(self, enter_result: Any = None) -> None:
148
+ self._enter_result = enter_result
149
+
150
+ async def __aenter__(self) -> Any:
151
+ return self._enter_result
152
+
153
+ async def __aexit__(
154
+ self,
155
+ exc_type: Optional[type[BaseException]],
156
+ exc_val: Optional[BaseException],
157
+ exc_tb: Optional[TracebackType],
158
+ ) -> None:
159
+ pass
160
+
161
+
130
162
  class Client:
131
163
  _UNKNOWN_VERSION = HostChecker._UNKNOWN_VERSION
132
164
  _SESSION_HEADER = "Classiq-Session"
133
165
  _WARNINGS_HEADER = "X-Classiq-Warnings"
134
- _LATEST_VERSION_API_PREFIX = "/api/v1"
166
+ _HTTP_TIMEOUT_SECONDS = 3600 # Needs to be synced with load-balancer timeout
135
167
 
136
168
  def __init__(self, conf: config.Configuration) -> None:
137
169
  self._config = conf
138
170
  self._token_manager = token_manager.TokenManager(config=self._config)
139
- self._ssl_context = ssl.create_default_context()
140
- self._HTTP_TIMEOUT_SECONDS = (
141
- 3600 # Needs to be synced with load-balancer timeout
142
- )
143
171
  self._api_prefix = self._make_api_prefix()
144
172
  self._session_id: Optional[str] = None
145
173
 
146
- @classmethod
147
- def _make_api_prefix(cls) -> str:
148
- if _VERSION == cls._UNKNOWN_VERSION:
149
- return cls._LATEST_VERSION_API_PREFIX
150
- parsed_version = Version(_VERSION)
151
- return f"/api/v{parsed_version.major}-{parsed_version.minor}"
174
+ @staticmethod
175
+ def _make_api_prefix() -> str:
176
+ return f"/api/v{INTERFACE_VERSION}"
152
177
 
153
178
  def make_versioned_url(self, url_postfix: str) -> str:
154
179
  return self._api_prefix + url_postfix
@@ -186,48 +211,92 @@ class Client:
186
211
  try:
187
212
  detail = response.json()["detail"]
188
213
  message += f": {detail}"
189
- except Exception: # nosec B110
214
+ except Exception: # noqa: S110
190
215
  pass
191
- raise ClassiqAPIError(message)
216
+ raise ClassiqAPIError(message, response.status_code)
192
217
 
193
- def _make_client_args(self) -> Dict[str, Any]:
218
+ @try_again_on_failure
219
+ async def request(
220
+ self,
221
+ http_client: httpx.AsyncClient,
222
+ method: str,
223
+ url: str,
224
+ json: Optional[dict] = None,
225
+ params: Optional[dict] = None,
226
+ headers: Optional[dict[str, str]] = None,
227
+ ) -> httpx.Response:
228
+ http_client.headers.update(self._get_headers())
229
+
230
+ _logger.debug("HTTP request: %s %s", method.upper(), url)
231
+ start_time = time.monotonic()
232
+ response = await http_client.request(
233
+ method=method,
234
+ url=url,
235
+ json=json,
236
+ params=params,
237
+ headers=headers,
238
+ )
239
+ _logger.debug(
240
+ "HTTP response: %s %s %d (%.0fms)",
241
+ method.upper(),
242
+ url,
243
+ response.status_code,
244
+ (time.monotonic() - start_time) * 1000,
245
+ )
246
+ self.handle_response(response)
247
+ return response
248
+
249
+ def _make_client_args(self) -> dict[str, Any]:
194
250
  return {
195
- "base_url": self._config.host,
251
+ "base_url": str(self._config.host),
196
252
  "timeout": self._HTTP_TIMEOUT_SECONDS,
197
- "headers": self.get_headers(),
253
+ "headers": self._get_headers(),
198
254
  }
199
255
 
200
- @try_again_on_failure
201
256
  async def call_api(
202
257
  self,
203
258
  http_method: str,
204
259
  url: str,
205
- body: Optional[Dict] = None,
206
- params: Optional[Dict] = None,
260
+ body: Optional[dict] = None,
261
+ params: Optional[dict] = None,
207
262
  use_versioned_url: bool = True,
208
- headers: Optional[Dict[str, str]] = None,
209
- ) -> Union[Dict, str]:
263
+ headers: Optional[dict[str, str]] = None,
264
+ http_client: Optional[httpx.AsyncClient] = None,
265
+ ) -> Union[dict, list, str]:
210
266
  if use_versioned_url:
211
267
  url = self.make_versioned_url(url)
212
- async with self.async_client() as async_client:
213
- response = await async_client.request(
268
+ async with self.use_client_or_create(http_client) as async_client:
269
+ response = await self.request(
270
+ http_client=async_client,
214
271
  method=http_method,
215
272
  url=url,
216
273
  json=body,
217
274
  params=params,
218
275
  headers=headers,
219
276
  )
220
- self.handle_response(response)
221
277
  return response.json()
222
278
 
279
+ def use_client_or_create(
280
+ self, http_client: Optional[httpx.AsyncClient]
281
+ ) -> contextlib.AbstractAsyncContextManager[httpx.AsyncClient]:
282
+ if http_client is None:
283
+ return self.async_client()
284
+ else:
285
+ if sys.version_info[0:2] < (3, 10):
286
+ # remove this `if` and the `_AsyncNullContext` class when we stop
287
+ # supporting python 3.9
288
+ return _AsyncNullContext(enter_result=http_client)
289
+ else:
290
+ return contextlib.nullcontext(enter_result=http_client)
291
+
223
292
  def sync_call_api(
224
293
  self,
225
294
  http_method: str,
226
295
  url: str,
227
- body: Optional[Dict] = None,
228
- headers: Optional[Dict] = None,
296
+ body: Optional[dict] = None,
297
+ headers: Optional[dict] = None,
229
298
  use_versioned_url: bool = True,
230
- ) -> Union[Dict, str]:
299
+ ) -> Union[dict, str]:
231
300
  if use_versioned_url:
232
301
  url = self.make_versioned_url(url)
233
302
  with httpx.Client(**self._make_client_args()) as sync_client:
@@ -240,7 +309,7 @@ class Client:
240
309
  def async_client(self) -> httpx.AsyncClient:
241
310
  return httpx.AsyncClient(**self._make_client_args())
242
311
 
243
- def get_headers(self) -> Headers:
312
+ def _get_headers(self) -> Headers:
244
313
  headers = dict()
245
314
  access_token = self._token_manager.get_access_token()
246
315
  if access_token is not None:
@@ -254,7 +323,7 @@ class Client:
254
323
  await self._token_manager.update_expired_access_token()
255
324
 
256
325
  def get_backend_uri(self) -> str:
257
- return self._config.host
326
+ return self._config.host.unicode_string()
258
327
 
259
328
  def check_host(self) -> None:
260
329
  # This function is NOT async (despite the fact that it can be) because it's called from a non-async context.
@@ -2,16 +2,15 @@
2
2
 
3
3
  import os
4
4
  import pathlib
5
- from typing import List, Optional, Union
5
+ from typing import Optional, Union
6
6
 
7
7
  import configargparse # type: ignore[import]
8
8
  import pydantic
9
9
  from pydantic import BaseModel
10
10
 
11
+ from classiq.interface.enum_utils import StrEnum
11
12
  from classiq.interface.server.routes import DEFAULT_IDE_FE_APP
12
13
 
13
- from classiq._internals.enum_utils import StrEnum
14
-
15
14
  DEFAULT_HOST = "https://api.classiq.io"
16
15
 
17
16
 
@@ -54,7 +53,7 @@ if os.name == "posix":
54
53
  ] + _DEFAULT_CONFIG_FILES
55
54
 
56
55
 
57
- def init(args: Optional[Union[str, List[str]]] = None) -> Configuration:
56
+ def init(args: Optional[Union[str, list[str]]] = None) -> Configuration:
58
57
  """Initialize the configuration object.
59
58
 
60
59
  Args: