classiq 0.37.1__py3-none-any.whl → 0.39.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.
- classiq/__init__.py +23 -24
- classiq/_analyzer_extras/_ipywidgets_async_extension.py +1 -1
- classiq/_analyzer_extras/interactive_hardware.py +3 -3
- classiq/_internals/api_wrapper.py +37 -17
- classiq/_internals/async_utils.py +1 -74
- classiq/_internals/authentication/device.py +9 -4
- classiq/_internals/authentication/password_manager.py +25 -10
- classiq/_internals/authentication/token_manager.py +2 -2
- classiq/_internals/client.py +24 -6
- classiq/_internals/jobs.py +10 -7
- classiq/analyzer/analyzer.py +29 -29
- classiq/analyzer/analyzer_utilities.py +5 -5
- classiq/analyzer/rb.py +4 -5
- classiq/analyzer/show_interactive_hack.py +6 -6
- classiq/applications/__init__.py +1 -8
- classiq/applications/chemistry/__init__.py +6 -0
- classiq/{applications_model_constructors → applications/chemistry}/chemistry_model_constructor.py +9 -16
- classiq/applications/combinatorial_helpers/allowed_constraints.py +20 -0
- classiq/applications/combinatorial_helpers/arithmetic/arithmetic_expression.py +35 -0
- classiq/applications/combinatorial_helpers/arithmetic/isolation.py +42 -0
- classiq/applications/combinatorial_helpers/combinatorial_problem_utils.py +150 -0
- classiq/applications/combinatorial_helpers/encoding_mapping.py +107 -0
- classiq/applications/combinatorial_helpers/encoding_utils.py +122 -0
- classiq/applications/combinatorial_helpers/memory.py +77 -0
- classiq/applications/combinatorial_helpers/optimization_model.py +162 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py +31 -0
- classiq/applications/combinatorial_helpers/pauli_helpers/pauli_utils.py +75 -0
- classiq/applications/combinatorial_helpers/py.typed +0 -0
- classiq/applications/combinatorial_helpers/pyomo_utils.py +245 -0
- classiq/applications/combinatorial_helpers/solvers/__init__.py +0 -0
- classiq/applications/combinatorial_helpers/sympy_utils.py +22 -0
- classiq/applications/combinatorial_helpers/transformations/__init__.py +0 -0
- classiq/applications/combinatorial_helpers/transformations/encoding.py +187 -0
- classiq/applications/combinatorial_helpers/transformations/fixed_variables.py +142 -0
- classiq/applications/combinatorial_helpers/transformations/ising_converter.py +122 -0
- classiq/applications/combinatorial_helpers/transformations/penalty.py +32 -0
- classiq/applications/combinatorial_helpers/transformations/penalty_support.py +37 -0
- classiq/applications/combinatorial_helpers/transformations/sign_seperation.py +75 -0
- classiq/applications/combinatorial_helpers/transformations/slack_variables.py +88 -0
- classiq/applications/combinatorial_optimization/__init__.py +13 -2
- classiq/applications/combinatorial_optimization/combinatorial_optimization_model_constructor.py +134 -0
- classiq/applications/finance/__init__.py +3 -2
- classiq/{applications_model_constructors → applications/finance}/finance_model_constructor.py +27 -30
- classiq/applications/grover/__init__.py +11 -0
- classiq/{applications_model_constructors → applications/grover}/grover_model_constructor.py +20 -91
- classiq/applications/libraries/__init__.py +0 -0
- classiq/applications/libraries/qmci_library.py +35 -0
- classiq/applications/qnn/circuit_utils.py +2 -2
- classiq/applications/qnn/gradients/quantum_gradient.py +2 -2
- classiq/applications/qnn/types.py +2 -2
- classiq/applications/qsvm/__init__.py +5 -1
- classiq/applications/qsvm/qsvm.py +4 -7
- classiq/applications/qsvm/qsvm_data_generation.py +2 -5
- classiq/exceptions.py +43 -1
- classiq/execution/all_hardware_devices.py +13 -0
- classiq/executor.py +12 -10
- classiq/interface/_version.py +1 -1
- classiq/interface/analyzer/analysis_params.py +6 -3
- classiq/interface/analyzer/result.py +12 -8
- classiq/interface/applications/qsvm.py +17 -3
- classiq/interface/ast_node.py +23 -0
- classiq/interface/backend/backend_preferences.py +4 -2
- classiq/interface/backend/pydantic_backend.py +3 -1
- classiq/interface/backend/quantum_backend_providers.py +1 -0
- classiq/interface/chemistry/fermionic_operator.py +15 -13
- classiq/interface/chemistry/ground_state_problem.py +18 -3
- classiq/interface/chemistry/molecule.py +8 -6
- classiq/interface/chemistry/operator.py +20 -14
- classiq/interface/combinatorial_optimization/examples/ascending_sequence.py +1 -1
- classiq/interface/combinatorial_optimization/examples/greater_than_ilp.py +1 -1
- classiq/interface/combinatorial_optimization/examples/ilp.py +2 -1
- classiq/interface/combinatorial_optimization/examples/integer_portfolio_optimization.py +2 -2
- classiq/interface/combinatorial_optimization/examples/mds.py +2 -1
- classiq/interface/combinatorial_optimization/examples/mht.py +8 -3
- classiq/interface/combinatorial_optimization/examples/mis.py +4 -1
- classiq/interface/combinatorial_optimization/examples/mvc.py +2 -1
- classiq/interface/combinatorial_optimization/examples/set_cover.py +2 -1
- classiq/interface/combinatorial_optimization/examples/tsp.py +4 -3
- classiq/interface/combinatorial_optimization/examples/tsp_digraph.py +6 -2
- classiq/interface/combinatorial_optimization/mht_qaoa_input.py +9 -3
- classiq/interface/executor/aws_execution_cost.py +4 -3
- classiq/interface/executor/estimation.py +2 -2
- classiq/interface/executor/execution_preferences.py +5 -34
- classiq/interface/executor/execution_request.py +15 -48
- classiq/interface/executor/optimizer_preferences.py +22 -13
- classiq/interface/executor/{quantum_program.py → quantum_code.py} +21 -15
- classiq/interface/executor/quantum_instruction_set.py +2 -1
- classiq/interface/executor/register_initialization.py +1 -3
- classiq/interface/executor/result.py +41 -10
- classiq/interface/executor/vqe_result.py +2 -2
- classiq/interface/finance/function_input.py +17 -4
- classiq/interface/finance/gaussian_model_input.py +3 -1
- classiq/interface/finance/log_normal_model_input.py +3 -1
- classiq/interface/finance/model_input.py +2 -0
- classiq/interface/generator/amplitude_loading.py +6 -3
- classiq/interface/generator/application_apis/__init__.py +1 -0
- classiq/interface/generator/application_apis/arithmetic_declarations.py +14 -0
- classiq/interface/generator/arith/argument_utils.py +14 -4
- classiq/interface/generator/arith/arithmetic.py +3 -1
- classiq/interface/generator/arith/arithmetic_arg_type_validator.py +12 -13
- classiq/interface/generator/arith/arithmetic_expression_abc.py +4 -1
- classiq/interface/generator/arith/arithmetic_expression_parser.py +8 -2
- classiq/interface/generator/arith/arithmetic_expression_validator.py +16 -2
- classiq/interface/generator/arith/arithmetic_operations.py +5 -10
- classiq/interface/generator/arith/ast_node_rewrite.py +1 -1
- classiq/interface/generator/arith/binary_ops.py +202 -54
- classiq/interface/generator/arith/extremum_operations.py +5 -3
- classiq/interface/generator/arith/logical_ops.py +4 -2
- classiq/interface/generator/arith/machine_precision.py +3 -0
- classiq/interface/generator/arith/number_utils.py +34 -44
- classiq/interface/generator/arith/register_user_input.py +21 -1
- classiq/interface/generator/arith/unary_ops.py +16 -25
- classiq/interface/generator/builtin_api_builder.py +0 -5
- classiq/interface/generator/chemistry_function_params.py +4 -4
- classiq/interface/generator/commuting_pauli_exponentiation.py +3 -1
- classiq/interface/generator/compiler_keywords.py +4 -0
- classiq/interface/generator/complex_type.py +3 -10
- classiq/interface/generator/constant.py +2 -3
- classiq/interface/generator/control_state.py +5 -3
- classiq/interface/generator/credit_risk_example/linear_gci.py +10 -3
- classiq/interface/generator/credit_risk_example/weighted_adder.py +14 -4
- classiq/interface/generator/expressions/atomic_expression_functions.py +5 -3
- classiq/interface/generator/expressions/evaluated_expression.py +18 -4
- classiq/interface/generator/expressions/expression.py +3 -5
- classiq/interface/generator/expressions/qmod_qscalar_proxy.py +33 -0
- classiq/interface/generator/expressions/sympy_supported_expressions.py +2 -1
- classiq/interface/generator/finance.py +1 -1
- classiq/interface/generator/function_params.py +7 -6
- classiq/interface/generator/functions/__init__.py +2 -2
- classiq/interface/generator/functions/builtins/__init__.py +15 -0
- classiq/interface/generator/functions/builtins/core_library/__init__.py +14 -0
- classiq/interface/generator/functions/builtins/core_library/chemistry_functions.py +0 -0
- classiq/interface/generator/functions/builtins/internal_operators.py +62 -0
- classiq/interface/generator/functions/{core_lib_declarations/quantum_functions/std_lib_functions.py → builtins/open_lib_functions.py} +612 -219
- classiq/interface/generator/functions/builtins/quantum_operators.py +37 -0
- classiq/interface/generator/functions/classical_type.py +2 -4
- classiq/interface/generator/functions/foreign_function_definition.py +12 -4
- classiq/interface/generator/functions/function_declaration.py +2 -2
- classiq/interface/generator/functions/function_implementation.py +8 -4
- classiq/interface/generator/functions/native_function_definition.py +4 -2
- classiq/interface/generator/functions/register.py +4 -2
- classiq/interface/generator/functions/register_mapping_data.py +14 -10
- classiq/interface/generator/generated_circuit_data.py +2 -2
- classiq/interface/generator/grover_operator.py +5 -3
- classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +5 -1
- classiq/interface/generator/hardware/hardware_data.py +6 -4
- classiq/interface/generator/hardware_efficient_ansatz.py +25 -8
- classiq/interface/generator/hartree_fock.py +13 -3
- classiq/interface/generator/linear_pauli_rotations.py +3 -1
- classiq/interface/generator/mcu.py +5 -3
- classiq/interface/generator/mcx.py +7 -5
- classiq/interface/generator/model/classical_main_validator.py +1 -1
- classiq/interface/generator/model/constraints.py +2 -1
- classiq/interface/generator/model/model.py +12 -20
- classiq/interface/generator/model/preferences/preferences.py +4 -3
- classiq/interface/generator/oracles/custom_oracle.py +4 -2
- classiq/interface/generator/oracles/oracle_abc.py +2 -2
- classiq/interface/generator/qpe.py +6 -4
- classiq/interface/generator/qsvm.py +5 -8
- classiq/interface/generator/quantum_function_call.py +21 -16
- classiq/interface/generator/{generated_circuit.py → quantum_program.py} +10 -14
- classiq/interface/generator/range_types.py +3 -1
- classiq/interface/generator/slice_parsing_utils.py +8 -3
- classiq/interface/generator/standard_gates/controlled_standard_gates.py +4 -2
- classiq/interface/generator/state_preparation/metrics.py +2 -1
- classiq/interface/generator/state_preparation/state_preparation.py +7 -5
- classiq/interface/generator/state_propagator.py +16 -5
- classiq/interface/generator/types/builtin_struct_declarations/__init__.py +0 -1
- classiq/interface/generator/types/struct_declaration.py +10 -7
- classiq/interface/generator/ucc.py +6 -4
- classiq/interface/generator/unitary_gate.py +7 -3
- classiq/interface/generator/validations/flow_graph.py +6 -4
- classiq/interface/generator/validations/validator_functions.py +6 -4
- classiq/interface/hardware.py +2 -2
- classiq/interface/helpers/custom_encoders.py +3 -0
- classiq/interface/helpers/pydantic_model_helpers.py +0 -6
- classiq/interface/helpers/validation_helpers.py +1 -1
- classiq/interface/helpers/versioned_model.py +4 -1
- classiq/interface/ide/show.py +2 -2
- classiq/interface/jobs.py +72 -3
- classiq/interface/model/bind_operation.py +18 -11
- classiq/interface/model/call_synthesis_data.py +68 -0
- classiq/interface/model/classical_if.py +13 -0
- classiq/interface/model/classical_parameter_declaration.py +2 -3
- classiq/interface/model/control.py +16 -0
- classiq/interface/model/handle_binding.py +3 -2
- classiq/interface/model/inplace_binary_operation.py +2 -2
- classiq/interface/model/invert.py +10 -0
- classiq/interface/model/model.py +29 -22
- classiq/interface/model/native_function_definition.py +3 -5
- classiq/interface/model/power.py +12 -0
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +9 -4
- classiq/interface/model/quantum_expressions/control_state.py +2 -2
- classiq/interface/model/quantum_function_call.py +33 -142
- classiq/interface/model/quantum_function_declaration.py +8 -0
- classiq/interface/model/quantum_if_operation.py +4 -5
- classiq/interface/model/quantum_lambda_function.py +58 -0
- classiq/{quantum_register.py → interface/model/quantum_register.py} +17 -9
- classiq/interface/model/quantum_statement.py +3 -2
- classiq/interface/model/quantum_type.py +58 -59
- classiq/interface/model/quantum_variable_declaration.py +3 -3
- classiq/interface/model/repeat.py +13 -0
- classiq/interface/model/resolvers/function_call_resolver.py +26 -0
- classiq/interface/model/statement_block.py +49 -0
- classiq/interface/model/validations/handles_validator.py +16 -18
- classiq/interface/model/within_apply_operation.py +11 -0
- classiq/interface/pyomo_extension/pyomo_sympy_bimap.py +4 -1
- classiq/interface/server/routes.py +5 -4
- classiq/qmod/__init__.py +13 -6
- classiq/qmod/builtins/classical_execution_primitives.py +27 -36
- classiq/qmod/builtins/classical_functions.py +22 -12
- classiq/qmod/builtins/functions.py +272 -328
- classiq/qmod/builtins/operations.py +171 -35
- classiq/qmod/builtins/structs.py +15 -15
- classiq/qmod/cfunc.py +42 -0
- classiq/qmod/classical_function.py +6 -14
- classiq/qmod/declaration_inferrer.py +12 -21
- classiq/qmod/expression_query.py +23 -0
- classiq/qmod/model_state_container.py +2 -0
- classiq/qmod/native/__init__.py +0 -0
- classiq/qmod/native/expression_to_qmod.py +189 -0
- classiq/qmod/native/pretty_printer.py +340 -0
- classiq/qmod/qfunc.py +27 -0
- classiq/qmod/qmod_constant.py +100 -0
- classiq/qmod/qmod_parameter.py +36 -13
- classiq/qmod/qmod_struct.py +3 -3
- classiq/qmod/qmod_variable.py +148 -31
- classiq/qmod/quantum_callable.py +1 -0
- classiq/qmod/quantum_expandable.py +18 -19
- classiq/qmod/quantum_function.py +41 -8
- classiq/qmod/symbolic.py +48 -5
- classiq/qmod/symbolic_expr.py +9 -0
- classiq/qmod/utilities.py +13 -0
- classiq/qmod/write_qmod.py +39 -0
- {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/METADATA +2 -1
- {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/RECORD +244 -225
- {classiq-0.37.1.dist-info → classiq-0.39.0.dist-info}/WHEEL +1 -1
- classiq/applications/benchmarking/__init__.py +0 -9
- classiq/applications/benchmarking/mirror_benchmarking.py +0 -67
- classiq/applications/numpy_utils.py +0 -37
- classiq/applications_model_constructors/__init__.py +0 -17
- classiq/applications_model_constructors/combinatorial_optimization_model_constructor.py +0 -178
- classiq/applications_model_constructors/libraries/qmci_library.py +0 -109
- classiq/builtin_functions/__init__.py +0 -43
- classiq/builtin_functions/amplitude_loading.py +0 -3
- classiq/builtin_functions/binary_ops.py +0 -1
- classiq/builtin_functions/exponentiation.py +0 -5
- classiq/builtin_functions/qpe.py +0 -4
- classiq/builtin_functions/qsvm.py +0 -7
- classiq/builtin_functions/range_types.py +0 -5
- classiq/builtin_functions/standard_gates.py +0 -1
- classiq/builtin_functions/state_preparation.py +0 -6
- classiq/builtin_functions/suzuki_trotter.py +0 -3
- classiq/interface/generator/expressions/qmod_qnum_proxy.py +0 -22
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/__init__.py +0 -18
- classiq/interface/generator/functions/core_lib_declarations/quantum_operators.py +0 -169
- classiq/interface/generator/types/builtin_struct_declarations/qaoa_declarations.py +0 -23
- classiq/interface/generator/types/combinatorial_problem.py +0 -26
- classiq/interface/model/numeric_reinterpretation.py +0 -25
- classiq/interface/model/operator_synthesis_data.py +0 -48
- classiq/model/__init__.py +0 -14
- classiq/model/composite_function_generator.py +0 -33
- classiq/model/function_handler.py +0 -466
- classiq/model/function_handler.pyi +0 -152
- classiq/model/logic_flow.py +0 -149
- classiq/model/logic_flow_change_handler.py +0 -71
- classiq/model/model.py +0 -246
- classiq/quantum_functions/__init__.py +0 -17
- classiq/quantum_functions/annotation_parser.py +0 -207
- classiq/quantum_functions/decorators.py +0 -22
- classiq/quantum_functions/function_library.py +0 -181
- classiq/quantum_functions/function_parser.py +0 -74
- classiq/quantum_functions/quantum_function.py +0 -236
- /classiq/{applications_model_constructors/libraries → applications/combinatorial_helpers}/__init__.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations → applications/combinatorial_helpers/arithmetic}/__init__.py +0 -0
- /classiq/{interface/generator/functions/core_lib_declarations/quantum_functions/chemistry_functions.py → applications/combinatorial_helpers/pauli_helpers/__init__.py} +0 -0
- /classiq/{applications_model_constructors → applications}/libraries/ampltitude_estimation_library.py +0 -0
- /classiq/{applications_model_constructors → applications/qsvm}/qsvm_model_constructor.py +0 -0
- /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/atomic_quantum_functions.py +0 -0
- /classiq/interface/generator/functions/{core_lib_declarations/quantum_functions → builtins/core_library}/exponentiation_functions.py +0 -0
classiq/__init__.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
"""Classiq SDK."""
|
2
2
|
|
3
|
-
import sys
|
4
3
|
from typing import List
|
5
4
|
|
6
5
|
from classiq.interface._version import VERSION as _VERSION
|
@@ -13,17 +12,12 @@ from classiq.interface.generator.control_state import ControlState
|
|
13
12
|
from classiq.interface.generator.expressions.enums.pauli import Pauli
|
14
13
|
from classiq.interface.generator.functions import * # noqa: F403
|
15
14
|
from classiq.interface.generator.functions import __all__ as _ifunc_all
|
16
|
-
from classiq.interface.generator.
|
15
|
+
from classiq.interface.generator.model import * # noqa: F403
|
16
|
+
from classiq.interface.generator.model import __all__ as _md_all
|
17
|
+
from classiq.interface.generator.quantum_program import QuantumProgram
|
17
18
|
from classiq.interface.ide.show import show
|
18
19
|
|
19
|
-
from classiq import
|
20
|
-
applications,
|
21
|
-
builtin_functions,
|
22
|
-
exceptions,
|
23
|
-
execution,
|
24
|
-
model,
|
25
|
-
synthesis,
|
26
|
-
)
|
20
|
+
from classiq import applications, exceptions, execution, synthesis
|
27
21
|
from classiq._internals import _qfunc_ext, logger
|
28
22
|
from classiq._internals.async_utils import (
|
29
23
|
enable_jupyter_notebook,
|
@@ -34,23 +28,23 @@ from classiq._internals.client import configure
|
|
34
28
|
from classiq._internals.config import Configuration
|
35
29
|
from classiq._internals.help import open_help
|
36
30
|
from classiq.analyzer import Analyzer
|
37
|
-
from classiq.
|
38
|
-
|
39
|
-
|
31
|
+
from classiq.applications.chemistry import (
|
32
|
+
construct_chemistry_model,
|
33
|
+
molecule_problem_to_qmod,
|
34
|
+
)
|
35
|
+
from classiq.applications.combinatorial_optimization import (
|
36
|
+
construct_combinatorial_optimization_model,
|
40
37
|
)
|
38
|
+
from classiq.applications.finance import construct_finance_model
|
39
|
+
from classiq.applications.grover import construct_grover_model
|
40
|
+
from classiq.applications.qsvm import construct_qsvm_model
|
41
41
|
from classiq.executor import (
|
42
42
|
execute,
|
43
43
|
execute_async,
|
44
44
|
set_quantum_program_execution_preferences,
|
45
45
|
)
|
46
|
-
from classiq.model import * # noqa: F403
|
47
|
-
from classiq.model import __all__ as _md_all
|
48
46
|
from classiq.qmod import * # noqa: F403
|
49
47
|
from classiq.qmod import __all__ as _qmod_all
|
50
|
-
from classiq.quantum_functions import * # noqa: F403
|
51
|
-
from classiq.quantum_functions import __all__ as _qfuncs_all
|
52
|
-
from classiq.quantum_register import * # noqa: F403
|
53
|
-
from classiq.quantum_register import __all__ as _qregs_all
|
54
48
|
from classiq.synthesis import (
|
55
49
|
set_constraints,
|
56
50
|
set_execution_preferences,
|
@@ -59,6 +53,15 @@ from classiq.synthesis import (
|
|
59
53
|
synthesize_async,
|
60
54
|
)
|
61
55
|
|
56
|
+
_application_constructors_all = [
|
57
|
+
"construct_qsvm_model",
|
58
|
+
"construct_combinatorial_optimization_model",
|
59
|
+
"construct_chemistry_model",
|
60
|
+
"construct_finance_model",
|
61
|
+
"construct_grover_model",
|
62
|
+
"molecule_problem_to_qmod",
|
63
|
+
]
|
64
|
+
|
62
65
|
__version__ = _VERSION
|
63
66
|
|
64
67
|
if _is_notebook():
|
@@ -67,10 +70,8 @@ if _is_notebook():
|
|
67
70
|
_sub_modules = [
|
68
71
|
"analyzer",
|
69
72
|
"applications",
|
70
|
-
"builtin_functions",
|
71
73
|
"exceptions",
|
72
74
|
"execution",
|
73
|
-
"model",
|
74
75
|
"open_help",
|
75
76
|
"qmod",
|
76
77
|
"synthesis",
|
@@ -82,7 +83,7 @@ __all__ = (
|
|
82
83
|
"RegisterArithmeticInfo",
|
83
84
|
"ControlState",
|
84
85
|
"Analyzer",
|
85
|
-
"
|
86
|
+
"QuantumProgram",
|
86
87
|
"authenticate",
|
87
88
|
"synthesize",
|
88
89
|
"synthesize_async",
|
@@ -95,8 +96,6 @@ __all__ = (
|
|
95
96
|
"show",
|
96
97
|
"Pauli",
|
97
98
|
]
|
98
|
-
+ _qregs_all
|
99
|
-
+ _qfuncs_all
|
100
99
|
+ _md_all
|
101
100
|
+ _ifunc_all
|
102
101
|
+ _sub_modules
|
@@ -33,7 +33,7 @@ def widget_callback(widget_name: WidgetName) -> Callable[[WidgetFunc], Callable]
|
|
33
33
|
interactive_loop = _create_interactive_loop_async(
|
34
34
|
function=function, self=self, widget=widget
|
35
35
|
)
|
36
|
-
asyncio.ensure_future(interactive_loop)
|
36
|
+
asyncio.ensure_future(interactive_loop) # noqa: RUF006
|
37
37
|
await asyncio.sleep(SleepTime)
|
38
38
|
|
39
39
|
return wrapper
|
@@ -6,7 +6,7 @@ from ipywidgets import Combobox, HBox, VBox # type: ignore[import]
|
|
6
6
|
|
7
7
|
from classiq.interface.analyzer import analysis_params
|
8
8
|
from classiq.interface.backend.quantum_backend_providers import AnalyzerProviderVendor
|
9
|
-
from classiq.interface.generator.
|
9
|
+
from classiq.interface.generator.quantum_program import QuantumProgram
|
10
10
|
|
11
11
|
from classiq._analyzer_extras._ipywidgets_async_extension import widget_callback
|
12
12
|
from classiq.analyzer.analyzer_utilities import (
|
@@ -22,7 +22,7 @@ class InteractiveHardware(AnalyzerUtilities):
|
|
22
22
|
def __init__(
|
23
23
|
self,
|
24
24
|
params: analysis_params.AnalysisParams,
|
25
|
-
circuit:
|
25
|
+
circuit: QuantumProgram,
|
26
26
|
available_devices: ProviderAvailableDevices,
|
27
27
|
hardware_graphs: HardwareGraphs,
|
28
28
|
) -> None:
|
@@ -70,7 +70,7 @@ class InteractiveHardware(AnalyzerUtilities):
|
|
70
70
|
) -> None:
|
71
71
|
if not provider:
|
72
72
|
return
|
73
|
-
await self.
|
73
|
+
await self._request_available_devices_async(providers=[provider])
|
74
74
|
self.devices_combobox.options = self._filter_devices_by_qubits_count(provider)
|
75
75
|
self.devices_combobox.disabled = False
|
76
76
|
self.devices_combobox.placeholder = "Choose device"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import json
|
2
|
-
from typing import Dict, Optional, Protocol, Type, TypeVar
|
2
|
+
from typing import Dict, List, Optional, Protocol, Type, TypeVar
|
3
3
|
|
4
4
|
import pydantic
|
5
5
|
|
@@ -13,8 +13,15 @@ from classiq.interface.execution.jobs import (
|
|
13
13
|
ExecutionJobsQueryResultsV1,
|
14
14
|
)
|
15
15
|
from classiq.interface.executor import execution_request, result as execute_result
|
16
|
-
from classiq.interface.generator import
|
17
|
-
from classiq.interface.
|
16
|
+
from classiq.interface.generator import quantum_program as generator_result
|
17
|
+
from classiq.interface.hardware import HardwareInformation
|
18
|
+
from classiq.interface.jobs import (
|
19
|
+
JobDescriptionBase,
|
20
|
+
JobDescriptionFailure,
|
21
|
+
JobDescriptionSuccess,
|
22
|
+
JobID,
|
23
|
+
JSONObject,
|
24
|
+
)
|
18
25
|
from classiq.interface.model.common_model_types import ModelInput
|
19
26
|
from classiq.interface.server import routes
|
20
27
|
|
@@ -42,13 +49,15 @@ class StatusType(Protocol):
|
|
42
49
|
|
43
50
|
|
44
51
|
def _parse_job_response(
|
45
|
-
job_result:
|
52
|
+
job_result: JobDescriptionBase[JSONObject],
|
46
53
|
output_type: Type[ResultType],
|
47
54
|
) -> ResultType:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
55
|
+
if isinstance(job_result, JobDescriptionSuccess):
|
56
|
+
return output_type.parse_obj(job_result.description)
|
57
|
+
if isinstance(job_result, JobDescriptionFailure):
|
58
|
+
raise ClassiqAPIError(job_result.description.details)
|
59
|
+
|
60
|
+
raise ClassiqAPIError("Unexpected response from server")
|
52
61
|
|
53
62
|
|
54
63
|
class ApiWrapper:
|
@@ -93,14 +102,14 @@ class ApiWrapper:
|
|
93
102
|
@classmethod
|
94
103
|
async def call_generation_task(
|
95
104
|
cls, model: ModelInput
|
96
|
-
) -> generator_result.
|
105
|
+
) -> generator_result.QuantumProgram:
|
97
106
|
poller = JobPoller(base_url=routes.TASKS_GENERATE_FULL_PATH)
|
98
107
|
result = await poller.run_pydantic(model, timeout_sec=None)
|
99
|
-
return _parse_job_response(result, generator_result.
|
108
|
+
return _parse_job_response(result, generator_result.QuantumProgram)
|
100
109
|
|
101
110
|
@classmethod
|
102
111
|
async def call_execute_generated_circuit(
|
103
|
-
cls, circuit: generator_result.
|
112
|
+
cls, circuit: generator_result.QuantumProgram
|
104
113
|
) -> execution_request.ExecutionJobDetails:
|
105
114
|
execution_input = await cls._call_task_pydantic(
|
106
115
|
http_method=HTTPMethod.POST,
|
@@ -125,7 +134,7 @@ class ApiWrapper:
|
|
125
134
|
cls,
|
126
135
|
job_id: JobID,
|
127
136
|
) -> execution_request.ExecutionJobDetails:
|
128
|
-
headers = {
|
137
|
+
headers = {_ACCEPT_HEADER: "v1"}
|
129
138
|
data = await cls._call_task(
|
130
139
|
http_method=HTTPMethod.GET,
|
131
140
|
headers=headers,
|
@@ -215,7 +224,7 @@ class ApiWrapper:
|
|
215
224
|
|
216
225
|
@classmethod
|
217
226
|
async def call_analyzer_app(
|
218
|
-
cls, params: generator_result.
|
227
|
+
cls, params: generator_result.QuantumProgram
|
219
228
|
) -> analysis_result.DataID:
|
220
229
|
data = await cls._call_task_pydantic(
|
221
230
|
http_method=HTTPMethod.POST,
|
@@ -227,23 +236,23 @@ class ApiWrapper:
|
|
227
236
|
@classmethod
|
228
237
|
async def get_generated_circuit_from_qasm(
|
229
238
|
cls, params: analysis_result.QasmCode
|
230
|
-
) -> generator_result.
|
239
|
+
) -> generator_result.QuantumProgram:
|
231
240
|
data = await cls._call_task_pydantic(
|
232
241
|
http_method=HTTPMethod.POST,
|
233
242
|
url=routes.IDE_QASM_FULL_PATH,
|
234
243
|
model=params,
|
235
244
|
)
|
236
|
-
return generator_result.
|
245
|
+
return generator_result.QuantumProgram.parse_obj(data)
|
237
246
|
|
238
247
|
@classmethod
|
239
248
|
async def get_analyzer_app_data(
|
240
249
|
cls, params: analysis_result.DataID
|
241
|
-
) -> generator_result.
|
250
|
+
) -> generator_result.QuantumProgram:
|
242
251
|
data = await cls._call_task(
|
243
252
|
http_method=HTTPMethod.GET,
|
244
253
|
url=f"{routes.ANALYZER_DATA_FULL_PATH}/{params.id}",
|
245
254
|
)
|
246
|
-
return generator_result.
|
255
|
+
return generator_result.QuantumProgram.parse_obj(data)
|
247
256
|
|
248
257
|
@classmethod
|
249
258
|
async def call_rb_analysis_task(
|
@@ -289,6 +298,17 @@ class ApiWrapper:
|
|
289
298
|
)
|
290
299
|
return analysis_result.DevicesResult.parse_obj(data)
|
291
300
|
|
301
|
+
@classmethod
|
302
|
+
async def call_get_all_hardware_devices(cls) -> List[HardwareInformation]:
|
303
|
+
data = await client().call_api(
|
304
|
+
http_method=HTTPMethod.GET,
|
305
|
+
url="/hardware-catalog/v1/hardwares",
|
306
|
+
use_versioned_url=False,
|
307
|
+
)
|
308
|
+
if not isinstance(data, list):
|
309
|
+
raise ClassiqAPIError(f"Unexpected value: {data}")
|
310
|
+
return [HardwareInformation.parse_obj(info) for info in data]
|
311
|
+
|
292
312
|
@classmethod
|
293
313
|
async def call_generate_hamiltonian_task(
|
294
314
|
cls, problem: ground_state_problem.CHEMISTRY_PROBLEMS_TYPE
|
@@ -1,11 +1,8 @@
|
|
1
|
-
import abc
|
2
1
|
import asyncio
|
3
2
|
import functools
|
4
|
-
import inspect
|
5
3
|
import itertools
|
6
4
|
import logging
|
7
5
|
import time
|
8
|
-
import types
|
9
6
|
from typing import (
|
10
7
|
Any,
|
11
8
|
AsyncGenerator,
|
@@ -18,8 +15,6 @@ from typing import (
|
|
18
15
|
Union,
|
19
16
|
)
|
20
17
|
|
21
|
-
from classiq.exceptions import ClassiqValueError
|
22
|
-
|
23
18
|
T = TypeVar("T")
|
24
19
|
ASYNC_SUFFIX = "_async"
|
25
20
|
|
@@ -58,74 +53,6 @@ def syncify_function(async_func: Callable[..., Awaitable[T]]) -> Callable[..., T
|
|
58
53
|
return async_wrapper
|
59
54
|
|
60
55
|
|
61
|
-
def maybe_syncify_property_function(obj: Any) -> Any:
|
62
|
-
"""
|
63
|
-
The object is the input to `property` (or to `property.setter`)
|
64
|
-
Thus, we expect it to be either a function, or a function-that-returns-a-coroutine, or None
|
65
|
-
The only thing that should be syncified is a function-that-returns-a-coroutine
|
66
|
-
"""
|
67
|
-
if inspect.iscoroutinefunction(obj):
|
68
|
-
return syncify_function(obj)
|
69
|
-
elif isinstance(obj, types.FunctionType):
|
70
|
-
return obj
|
71
|
-
elif obj is None:
|
72
|
-
return obj
|
73
|
-
else:
|
74
|
-
raise ClassiqValueError(f"Invalid type: {obj.__class__.__name__}")
|
75
|
-
|
76
|
-
|
77
|
-
def syncify_property(async_prop: property) -> property:
|
78
|
-
if inspect.iscoroutinefunction(async_prop.fset):
|
79
|
-
raise ClassiqValueError(f"Setter cannot be `async def` (in {async_prop}")
|
80
|
-
if inspect.iscoroutinefunction(async_prop.fdel):
|
81
|
-
raise ClassiqValueError(f"Deleter cannot be `async def` (in {async_prop}")
|
82
|
-
|
83
|
-
return property(
|
84
|
-
maybe_syncify_property_function(async_prop.fget),
|
85
|
-
async_prop.fset,
|
86
|
-
async_prop.fdel,
|
87
|
-
async_prop.__doc__,
|
88
|
-
)
|
89
|
-
|
90
|
-
|
91
|
-
# Explanation about metaclasses
|
92
|
-
# https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
|
93
|
-
|
94
|
-
|
95
|
-
class Asyncify(type):
|
96
|
-
def __new__(
|
97
|
-
mcls, name: str, bases: tuple, class_dict: dict # noqa: N804
|
98
|
-
) -> "Asyncify":
|
99
|
-
new_attrs = {}
|
100
|
-
|
101
|
-
for attr_name, attr_value in class_dict.items():
|
102
|
-
if attr_name.endswith(ASYNC_SUFFIX):
|
103
|
-
new_attr_name = attr_name[: -len(ASYNC_SUFFIX)]
|
104
|
-
if new_attr_name in class_dict:
|
105
|
-
raise ClassiqValueError(f"Method name collision: {new_attr_name}")
|
106
|
-
else:
|
107
|
-
new_attrs[new_attr_name] = attr_value
|
108
|
-
|
109
|
-
new_class = super().__new__(mcls, name, bases, class_dict)
|
110
|
-
|
111
|
-
for attr_name, attr_value in new_attrs.items():
|
112
|
-
if isinstance(attr_value, property):
|
113
|
-
setattr(new_class, attr_name, syncify_property(attr_value))
|
114
|
-
elif isinstance(attr_value, types.FunctionType):
|
115
|
-
setattr(new_class, attr_name, syncify_function(attr_value))
|
116
|
-
else:
|
117
|
-
raise ClassiqValueError(
|
118
|
-
f"Invalid async type: {attr_value.__class__.__name__}"
|
119
|
-
)
|
120
|
-
|
121
|
-
return new_class
|
122
|
-
|
123
|
-
|
124
|
-
# Used for resolving metaclass collision
|
125
|
-
class AsyncifyABC(Asyncify, abc.ABCMeta):
|
126
|
-
pass
|
127
|
-
|
128
|
-
|
129
56
|
def enable_jupyter_notebook() -> None:
|
130
57
|
import nest_asyncio # type: ignore[import]
|
131
58
|
|
@@ -172,7 +99,7 @@ def is_notebook() -> bool:
|
|
172
99
|
return True # Jupyter notebook or qtconsole
|
173
100
|
elif shell == "TerminalInteractiveShell":
|
174
101
|
return False # Terminal running IPython
|
175
|
-
elif "google.colab" in str(local_ipython):
|
102
|
+
elif "google.colab" in str(local_ipython): # noqa: SIM103
|
176
103
|
return True
|
177
104
|
else:
|
178
105
|
return False # Other type (?)
|
@@ -26,9 +26,9 @@ class DeviceRegistrar:
|
|
26
26
|
get_refresh_token=get_refresh_token
|
27
27
|
)
|
28
28
|
|
29
|
-
print(f"Your user code: {data['user_code']}")
|
29
|
+
print(f"Your user code: {data['user_code']}") # noqa: T201
|
30
30
|
verification_url = data["verification_uri_complete"]
|
31
|
-
print(
|
31
|
+
print( # noqa: T201
|
32
32
|
f"If a browser doesn't automatically open, please visit this URL from any trusted device: {verification_url}"
|
33
33
|
)
|
34
34
|
if not text_only:
|
@@ -68,7 +68,7 @@ class DeviceRegistrar:
|
|
68
68
|
timeout: float,
|
69
69
|
get_refresh_token: bool = True,
|
70
70
|
) -> Tokens:
|
71
|
-
async def poller():
|
71
|
+
async def poller() -> Dict[str, Any]:
|
72
72
|
nonlocal device_code
|
73
73
|
return await auth0_client.poll_tokens(device_code=device_code)
|
74
74
|
|
@@ -92,7 +92,12 @@ class DeviceRegistrar:
|
|
92
92
|
elif error_code == "expired_token":
|
93
93
|
raise ClassiqExpiredTokenError(cls._TIMEOUT_ERROR)
|
94
94
|
elif error_code == "access_denied":
|
95
|
-
error_description
|
95
|
+
error_description = data.get("error_description")
|
96
|
+
if error_description is None:
|
97
|
+
raise ClassiqAuthenticationError(
|
98
|
+
"Failed authenticating to Classiq, missing error description"
|
99
|
+
)
|
100
|
+
|
96
101
|
raise ClassiqAuthenticationError(error_description)
|
97
102
|
else:
|
98
103
|
raise ClassiqAuthenticationError(
|
@@ -9,30 +9,41 @@ from typing import Dict, Optional
|
|
9
9
|
|
10
10
|
import keyring
|
11
11
|
from keyring.backends import fail
|
12
|
+
from pydantic import BaseSettings, Field
|
12
13
|
|
13
14
|
_logger = logging.getLogger(__name__)
|
14
15
|
|
15
16
|
|
17
|
+
class PasswordManagerSettings(BaseSettings):
|
18
|
+
ACCESS_TOKEN_KEY: str = Field(
|
19
|
+
default="classiqTokenAccount", env="CLASSIQ_ACCESS_TOKEN_ACCOUNT"
|
20
|
+
)
|
21
|
+
REFRESH_TOKEN_KEY: str = Field(
|
22
|
+
default="classiqRefershTokenAccount", env="CLASSIQ_REFRESH_TOKEN_ACCOUNT"
|
23
|
+
)
|
24
|
+
|
25
|
+
|
16
26
|
class PasswordManager(abc.ABC):
|
17
27
|
_SERVICE_NAME: str = "classiqTokenService"
|
18
|
-
|
19
|
-
|
28
|
+
|
29
|
+
def __init__(self) -> None:
|
30
|
+
self._settings = PasswordManagerSettings()
|
20
31
|
|
21
32
|
@property
|
22
33
|
def access_token(self) -> Optional[str]:
|
23
|
-
return self._get(key=self.
|
34
|
+
return self._get(key=self._settings.ACCESS_TOKEN_KEY)
|
24
35
|
|
25
36
|
@access_token.setter
|
26
37
|
def access_token(self, access_token: Optional[str]) -> None:
|
27
|
-
self._set(key=self.
|
38
|
+
self._set(key=self._settings.ACCESS_TOKEN_KEY, value=access_token)
|
28
39
|
|
29
40
|
@property
|
30
41
|
def refresh_token(self) -> Optional[str]:
|
31
|
-
return self._get(key=self.
|
42
|
+
return self._get(key=self._settings.REFRESH_TOKEN_KEY)
|
32
43
|
|
33
44
|
@refresh_token.setter
|
34
45
|
def refresh_token(self, refresh_token: Optional[str]) -> None:
|
35
|
-
self._set(key=self.
|
46
|
+
self._set(key=self._settings.REFRESH_TOKEN_KEY, value=refresh_token)
|
36
47
|
|
37
48
|
@abc.abstractmethod
|
38
49
|
def _get(self, key: str) -> Optional[str]:
|
@@ -46,8 +57,9 @@ class PasswordManager(abc.ABC):
|
|
46
57
|
def _clear(self, key: str) -> None:
|
47
58
|
pass
|
48
59
|
|
60
|
+
@staticmethod
|
49
61
|
@abc.abstractmethod
|
50
|
-
def is_supported(
|
62
|
+
def is_supported() -> bool:
|
51
63
|
pass
|
52
64
|
|
53
65
|
|
@@ -71,7 +83,8 @@ class KeyringPasswordManager(PasswordManager):
|
|
71
83
|
username=key,
|
72
84
|
)
|
73
85
|
|
74
|
-
|
86
|
+
@staticmethod
|
87
|
+
def is_supported() -> bool:
|
75
88
|
return not isinstance(keyring.get_keyring(), fail.Keyring)
|
76
89
|
|
77
90
|
|
@@ -85,7 +98,8 @@ class DummyPasswordManager(PasswordManager):
|
|
85
98
|
def _clear(self, key: str) -> None:
|
86
99
|
return
|
87
100
|
|
88
|
-
|
101
|
+
@staticmethod
|
102
|
+
def is_supported() -> bool:
|
89
103
|
return True
|
90
104
|
|
91
105
|
|
@@ -125,5 +139,6 @@ class FilePasswordManager(PasswordManager):
|
|
125
139
|
token_dict.pop(key)
|
126
140
|
self._update_file(token_dict)
|
127
141
|
|
128
|
-
|
142
|
+
@staticmethod
|
143
|
+
def is_supported() -> bool:
|
129
144
|
return "windows" not in platform.platform().lower()
|
@@ -13,7 +13,7 @@ from classiq.exceptions import (
|
|
13
13
|
ClassiqPasswordManagerSelectionError,
|
14
14
|
)
|
15
15
|
|
16
|
-
PASSWORD_MANAGERS = [pm.KeyringPasswordManager
|
16
|
+
PASSWORD_MANAGERS = [pm.KeyringPasswordManager, pm.FilePasswordManager]
|
17
17
|
_logger = logging.getLogger(__name__)
|
18
18
|
|
19
19
|
|
@@ -57,7 +57,7 @@ class TokenManager:
|
|
57
57
|
return pm.FilePasswordManager()
|
58
58
|
for password_manager in PASSWORD_MANAGERS:
|
59
59
|
if password_manager.is_supported():
|
60
|
-
return password_manager
|
60
|
+
return password_manager()
|
61
61
|
raise ClassiqPasswordManagerSelectionError(
|
62
62
|
"Password Manager not found, we could not store your credentials securely. Please contact support@classiq.io"
|
63
63
|
)
|
classiq/_internals/client.py
CHANGED
@@ -6,10 +6,21 @@ import os
|
|
6
6
|
import platform
|
7
7
|
import ssl
|
8
8
|
import sys
|
9
|
-
from typing import
|
9
|
+
from typing import (
|
10
|
+
Any,
|
11
|
+
Awaitable,
|
12
|
+
Callable,
|
13
|
+
Dict,
|
14
|
+
List,
|
15
|
+
NoReturn,
|
16
|
+
Optional,
|
17
|
+
TypeVar,
|
18
|
+
Union,
|
19
|
+
)
|
10
20
|
|
11
21
|
import httpx
|
12
22
|
from packaging.version import Version
|
23
|
+
from typing_extensions import ParamSpec
|
13
24
|
|
14
25
|
from classiq.interface._version import VERSION as _VERSION
|
15
26
|
|
@@ -80,9 +91,13 @@ def _get_user_agent_header() -> Headers:
|
|
80
91
|
}
|
81
92
|
|
82
93
|
|
94
|
+
Ret = TypeVar("Ret")
|
95
|
+
P = ParamSpec("P")
|
96
|
+
|
97
|
+
|
83
98
|
def try_again_on_failure(
|
84
|
-
func: Callable[
|
85
|
-
) -> Callable[
|
99
|
+
func: Callable[P, Awaitable[Ret]]
|
100
|
+
) -> Callable[P, Awaitable[Ret]]:
|
86
101
|
def check_approved_api_error(error_message: str) -> bool:
|
87
102
|
for approved_api_error in APPROVED_API_ERROR_MESSAGES_FOR_RESTART:
|
88
103
|
if approved_api_error in error_message:
|
@@ -93,7 +108,7 @@ def try_again_on_failure(
|
|
93
108
|
raise TypeError("Must decorate a coroutine function")
|
94
109
|
|
95
110
|
@functools.wraps(func)
|
96
|
-
async def wrapper(*args, **kwargs):
|
111
|
+
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> Ret:
|
97
112
|
for i in range(_RETRY_COUNT):
|
98
113
|
try:
|
99
114
|
return await func(*args, **kwargs)
|
@@ -123,6 +138,9 @@ def try_again_on_failure(
|
|
123
138
|
"There is problem with the connection to Classiq's server. Trying again"
|
124
139
|
)
|
125
140
|
await asyncio.sleep(API_ERROR_SLEEP_TIME)
|
141
|
+
raise ClassiqAPIError(
|
142
|
+
"Reached max retries when trying to connect to Classiq's server"
|
143
|
+
)
|
126
144
|
|
127
145
|
return wrapper
|
128
146
|
|
@@ -186,7 +204,7 @@ class Client:
|
|
186
204
|
try:
|
187
205
|
detail = response.json()["detail"]
|
188
206
|
message += f": {detail}"
|
189
|
-
except Exception: #
|
207
|
+
except Exception: # noqa: S110
|
190
208
|
pass
|
191
209
|
raise ClassiqAPIError(message)
|
192
210
|
|
@@ -206,7 +224,7 @@ class Client:
|
|
206
224
|
params: Optional[Dict] = None,
|
207
225
|
use_versioned_url: bool = True,
|
208
226
|
headers: Optional[Dict[str, str]] = None,
|
209
|
-
) -> Union[Dict, str]:
|
227
|
+
) -> Union[Dict, List, str]:
|
210
228
|
if use_versioned_url:
|
211
229
|
url = self.make_versioned_url(url)
|
212
230
|
async with self.async_client() as async_client:
|
classiq/_internals/jobs.py
CHANGED
@@ -5,7 +5,12 @@ from typing import Callable, Dict, Iterable, Optional, Set, TypeVar
|
|
5
5
|
import httpx
|
6
6
|
import pydantic
|
7
7
|
|
8
|
-
from classiq.interface.jobs import
|
8
|
+
from classiq.interface.jobs import (
|
9
|
+
JobDescriptionBase,
|
10
|
+
JobDescriptionUnion,
|
11
|
+
JobID,
|
12
|
+
JSONObject,
|
13
|
+
)
|
9
14
|
|
10
15
|
from classiq._internals.async_utils import poll_for
|
11
16
|
from classiq._internals.client import client, try_again_on_failure
|
@@ -13,7 +18,7 @@ from classiq._internals.config import SDKMode
|
|
13
18
|
from classiq.exceptions import ClassiqAPIError
|
14
19
|
|
15
20
|
_URL_PATH_SEP = "/"
|
16
|
-
GeneralJobDescription =
|
21
|
+
GeneralJobDescription = JobDescriptionBase[JSONObject]
|
17
22
|
_logger = logging.getLogger(__name__)
|
18
23
|
T = TypeVar("T")
|
19
24
|
|
@@ -37,11 +42,9 @@ def _join_url_path(*parts: str) -> str:
|
|
37
42
|
def _general_job_description_parser(
|
38
43
|
json_response: JSONObject,
|
39
44
|
) -> Optional[GeneralJobDescription]:
|
40
|
-
job_description
|
41
|
-
|
42
|
-
|
43
|
-
if job_description.status.is_final():
|
44
|
-
return job_description
|
45
|
+
job_description = JobDescriptionUnion[JSONObject].parse_obj(json_response)
|
46
|
+
if job_description.__root__.status.is_final():
|
47
|
+
return job_description.__root__
|
45
48
|
return None
|
46
49
|
|
47
50
|
|