luna-quantum 0.0.29__py3-none-any.whl → 0.0.37__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.
Potentially problematic release.
This version of luna-quantum might be problematic. Click here for more details.
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/METADATA +1 -1
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/RECORD +35 -33
- luna_sdk/controllers/luna_http_client.py +27 -0
- luna_sdk/controllers/luna_platform_client.py +34 -16
- luna_sdk/controllers/luna_q.py +5 -7
- luna_sdk/controllers/luna_solve.py +9 -7
- luna_sdk/controllers/luna_transform.py +13 -7
- luna_sdk/error/http_error_utils.py +10 -3
- luna_sdk/exceptions/encryption_exception.py +0 -6
- luna_sdk/interfaces/circuit_repo_i.py +0 -6
- luna_sdk/interfaces/optimization_repo_i.py +5 -4
- luna_sdk/interfaces/qpu_token_repo_i.py +18 -18
- luna_sdk/interfaces/solutions_repo_i.py +0 -6
- luna_sdk/repositories/circuit_repo.py +0 -11
- luna_sdk/repositories/optimization_repo.py +11 -10
- luna_sdk/repositories/qpu_token_repo.py +36 -27
- luna_sdk/repositories/solutions_repo.py +0 -8
- luna_sdk/schemas/create/circuit.py +0 -3
- luna_sdk/schemas/create/qpu_token.py +0 -3
- luna_sdk/schemas/create/solution.py +0 -1
- luna_sdk/schemas/enums/optimization.py +8 -7
- luna_sdk/schemas/enums/qpu_token_type.py +1 -1
- luna_sdk/schemas/optimization.py +53 -15
- luna_sdk/schemas/optimization_formats/qubo.py +8 -0
- luna_sdk/schemas/qpu_token.py +1 -5
- luna_sdk/schemas/rest/qpu_token/qpu_token_source.py +18 -0
- luna_sdk/schemas/rest/qpu_token/token_provider.py +47 -15
- luna_sdk/schemas/solution.py +89 -35
- luna_sdk/schemas/solver_parameters/dwave/base.py +4 -1
- luna_sdk/schemas/solver_parameters/dwave/quantum_annealing.py +13 -0
- luna_sdk/schemas/solver_parameters/dwave/repeated_reverse_quantum_annealing.py +13 -1
- luna_sdk/schemas/solver_parameters/dwave/tabu_search.py +2 -4
- luna_sdk/utils/qpu_tokens.py +14 -13
- luna_sdk/controllers/custom_login_client.py +0 -66
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/LICENSE +0 -0
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.37.dist-info}/WHEEL +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Dict, Optional
|
|
3
3
|
|
|
4
|
-
from luna_sdk.exceptions.encryption_exception import EncryptionNotSetException
|
|
5
4
|
from luna_sdk.interfaces.circuit_repo_i import ICircuitRepo
|
|
6
5
|
from luna_sdk.schemas.circuit import CircuitJob, CircuitResult
|
|
7
6
|
from luna_sdk.schemas.create.circuit import CircuitIn
|
|
@@ -20,7 +19,6 @@ class CircuitRepo(ICircuitRepo):
|
|
|
20
19
|
provider: CircuitProviderEnum,
|
|
21
20
|
params: Dict[str, Any] = {},
|
|
22
21
|
qpu_tokens: Optional[TokenProvider] = None,
|
|
23
|
-
encryption_key: Optional[str] = None,
|
|
24
22
|
**kwargs,
|
|
25
23
|
) -> CircuitJob:
|
|
26
24
|
if qpu_tokens is not None:
|
|
@@ -34,15 +32,11 @@ class CircuitRepo(ICircuitRepo):
|
|
|
34
32
|
if rest_qpu_tokens is None:
|
|
35
33
|
rest_qpu_tokens = extract_qpu_tokens_from_env()
|
|
36
34
|
|
|
37
|
-
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
38
|
-
if encryption_key is None:
|
|
39
|
-
raise EncryptionNotSetException
|
|
40
35
|
circuit_in: CircuitIn = CircuitIn(
|
|
41
36
|
provider=provider,
|
|
42
37
|
circuit=circuit,
|
|
43
38
|
params=params,
|
|
44
39
|
qpu_tokens=rest_qpu_tokens,
|
|
45
|
-
encryption_key=encryption_key,
|
|
46
40
|
)
|
|
47
41
|
|
|
48
42
|
response = self._client.post(
|
|
@@ -55,16 +49,11 @@ class CircuitRepo(ICircuitRepo):
|
|
|
55
49
|
def get(
|
|
56
50
|
self,
|
|
57
51
|
job: CircuitJob,
|
|
58
|
-
encryption_key: Optional[str] = None,
|
|
59
52
|
**kwargs,
|
|
60
53
|
) -> CircuitResult:
|
|
61
54
|
url = f"{self._endpoint}/{job.id}/{job.provider.value}"
|
|
62
|
-
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
63
|
-
if encryption_key is None:
|
|
64
|
-
raise EncryptionNotSetException
|
|
65
55
|
if job.params is None:
|
|
66
56
|
job.params = {}
|
|
67
|
-
job.params["encryption_key"] = encryption_key
|
|
68
57
|
response = self._client.get(url, params=job.params, **kwargs)
|
|
69
58
|
|
|
70
59
|
response.raise_for_status()
|
|
@@ -9,7 +9,7 @@ from luna_sdk.interfaces.optimization_repo_i import IOptimizationRepo
|
|
|
9
9
|
from luna_sdk.schemas import UseCase
|
|
10
10
|
from luna_sdk.schemas.create import QUBOIn
|
|
11
11
|
from luna_sdk.schemas.create.optimization import OptimizationUseCaseIn
|
|
12
|
-
from luna_sdk.schemas.enums.optimization import
|
|
12
|
+
from luna_sdk.schemas.enums.optimization import OptFormat
|
|
13
13
|
from luna_sdk.schemas.enums.timeframe import TimeframeEnum
|
|
14
14
|
from luna_sdk.schemas.optimization import (
|
|
15
15
|
Optimization,
|
|
@@ -17,6 +17,7 @@ from luna_sdk.schemas.optimization import (
|
|
|
17
17
|
OptimizationCQM,
|
|
18
18
|
OptimizationLP,
|
|
19
19
|
OptimizationUseCase,
|
|
20
|
+
OptimizationQubo,
|
|
20
21
|
)
|
|
21
22
|
from luna_sdk.schemas.optimization_formats.bqm import BQMSchema
|
|
22
23
|
from luna_sdk.schemas.optimization_formats.cqm import CQMSchema
|
|
@@ -30,7 +31,7 @@ class OptimizationRepo(IOptimizationRepo):
|
|
|
30
31
|
def get_all(
|
|
31
32
|
self,
|
|
32
33
|
timeframe: Optional[TimeframeEnum] = None,
|
|
33
|
-
input_type: Optional[
|
|
34
|
+
input_type: Optional[OptFormat] = None,
|
|
34
35
|
limit: int = 50,
|
|
35
36
|
offset: int = 0,
|
|
36
37
|
**kwargs,
|
|
@@ -40,7 +41,7 @@ class OptimizationRepo(IOptimizationRepo):
|
|
|
40
41
|
params["timeframe"] = timeframe.value
|
|
41
42
|
|
|
42
43
|
if input_type:
|
|
43
|
-
params["
|
|
44
|
+
params["original_format"] = input_type.value
|
|
44
45
|
|
|
45
46
|
if limit < 1:
|
|
46
47
|
# set the minimum limit to 1
|
|
@@ -63,21 +64,21 @@ class OptimizationRepo(IOptimizationRepo):
|
|
|
63
64
|
|
|
64
65
|
optimization_data = response_data.pop("optimization_data", None)
|
|
65
66
|
if optimization_data:
|
|
66
|
-
|
|
67
|
+
original_format = response_data["original_format"]
|
|
67
68
|
|
|
68
|
-
if
|
|
69
|
+
if original_format == OptFormat.BQM:
|
|
69
70
|
model = OptimizationBQM
|
|
70
|
-
elif
|
|
71
|
+
elif original_format == OptFormat.CQM:
|
|
71
72
|
model = OptimizationCQM
|
|
72
|
-
elif
|
|
73
|
+
elif original_format == OptFormat.LP:
|
|
73
74
|
model = OptimizationLP
|
|
74
|
-
elif
|
|
75
|
+
elif original_format == OptFormat.QUBO:
|
|
75
76
|
if response_data.get("use_case_name"):
|
|
76
77
|
model = OptimizationUseCase
|
|
77
78
|
else:
|
|
78
|
-
model =
|
|
79
|
+
model = OptimizationQubo
|
|
79
80
|
else:
|
|
80
|
-
|
|
81
|
+
raise ValueError("Unknown optimization format")
|
|
81
82
|
|
|
82
83
|
response_data.update(optimization_data)
|
|
83
84
|
|
|
@@ -3,14 +3,18 @@ import os
|
|
|
3
3
|
from typing import Dict, List, Optional
|
|
4
4
|
|
|
5
5
|
from httpx import Response
|
|
6
|
+
from pydantic import TypeAdapter
|
|
6
7
|
|
|
7
|
-
from luna_sdk.exceptions.encryption_exception import EncryptionNotSetException
|
|
8
8
|
from luna_sdk.interfaces.qpu_token_repo_i import IQpuTokenRepo
|
|
9
9
|
from luna_sdk.schemas import QpuTokenOut
|
|
10
10
|
from luna_sdk.schemas.create import QpuTokenIn
|
|
11
11
|
from luna_sdk.schemas.enums.qpu_token_type import QpuTokenTypeEnum
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
_ORGANIZATION_QPU_TOKENS_BACKEND = "shared"
|
|
15
|
+
_PERSONAL_QPU_TOKENS_BACKEND = "private"
|
|
16
|
+
|
|
17
|
+
|
|
14
18
|
class QpuTokenRepo(IQpuTokenRepo):
|
|
15
19
|
@property
|
|
16
20
|
def _endpoint(self) -> str:
|
|
@@ -22,15 +26,15 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
22
26
|
if token_type is None:
|
|
23
27
|
return f"{self._endpoint}"
|
|
24
28
|
elif token_type == QpuTokenTypeEnum.PERSONAL:
|
|
25
|
-
return f"{self._endpoint}/
|
|
29
|
+
return f"{self._endpoint}/{_PERSONAL_QPU_TOKENS_BACKEND}"
|
|
26
30
|
else:
|
|
27
|
-
return f"{self._endpoint}/
|
|
31
|
+
return f"{self._endpoint}/{_ORGANIZATION_QPU_TOKENS_BACKEND}"
|
|
28
32
|
|
|
29
33
|
def _get_by_name(
|
|
30
34
|
self, name: str, token_type: QpuTokenTypeEnum, **kwargs
|
|
31
35
|
) -> QpuTokenOut:
|
|
32
36
|
response: Response = self._client.get(
|
|
33
|
-
f"{self._get_endpoint_by_type(token_type)}/
|
|
37
|
+
f"{self._get_endpoint_by_type(token_type)}/{name}", **kwargs
|
|
34
38
|
)
|
|
35
39
|
response.raise_for_status()
|
|
36
40
|
|
|
@@ -44,17 +48,12 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
44
48
|
provider: str,
|
|
45
49
|
token: str,
|
|
46
50
|
token_type: QpuTokenTypeEnum,
|
|
47
|
-
encryption_key: Optional[str] = None,
|
|
48
51
|
**kwargs,
|
|
49
52
|
) -> QpuTokenOut:
|
|
50
|
-
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
51
|
-
if encryption_key is None:
|
|
52
|
-
raise EncryptionNotSetException
|
|
53
53
|
qpu_token = QpuTokenIn(
|
|
54
54
|
name=name,
|
|
55
55
|
provider=provider,
|
|
56
56
|
token=token,
|
|
57
|
-
encryption_key=encryption_key,
|
|
58
57
|
)
|
|
59
58
|
|
|
60
59
|
response: Response = self._client.post(
|
|
@@ -70,30 +69,42 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
70
69
|
def get_all(
|
|
71
70
|
self,
|
|
72
71
|
filter_provider: Optional[str] = None,
|
|
73
|
-
name: Optional[str] = None,
|
|
74
72
|
token_type: Optional[QpuTokenTypeEnum] = None,
|
|
73
|
+
limit: Optional[int] = None,
|
|
74
|
+
offset: Optional[int] = None,
|
|
75
75
|
**kwargs,
|
|
76
76
|
) -> Dict[QpuTokenTypeEnum, List[QpuTokenOut]]:
|
|
77
77
|
params = {}
|
|
78
78
|
if filter_provider:
|
|
79
79
|
params["filter_provider"] = filter_provider
|
|
80
80
|
|
|
81
|
-
if
|
|
82
|
-
params["
|
|
81
|
+
if limit is not None:
|
|
82
|
+
params["limit"] = str(limit)
|
|
83
|
+
if offset is not None:
|
|
84
|
+
params["offset"] = str(offset)
|
|
85
|
+
if token_type == QpuTokenTypeEnum.PERSONAL:
|
|
86
|
+
params["token_type"] = _PERSONAL_QPU_TOKENS_BACKEND
|
|
87
|
+
if token_type == QpuTokenTypeEnum.GROUP:
|
|
88
|
+
params["token_type"] = _ORGANIZATION_QPU_TOKENS_BACKEND
|
|
83
89
|
|
|
84
90
|
response = self._client.get(
|
|
85
|
-
self.
|
|
91
|
+
self._endpoint,
|
|
92
|
+
params=params,
|
|
93
|
+
**kwargs,
|
|
86
94
|
)
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
ta = TypeAdapter(List[QpuTokenOut])
|
|
89
96
|
to_return: Dict[QpuTokenTypeEnum, List[QpuTokenOut]] = {}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
resp = response.json()
|
|
98
|
+
|
|
99
|
+
shared_tokens = resp.get(_ORGANIZATION_QPU_TOKENS_BACKEND, [])
|
|
100
|
+
for qpu_token in shared_tokens:
|
|
101
|
+
qpu_token["token_type"] = QpuTokenTypeEnum.GROUP
|
|
102
|
+
to_return[QpuTokenTypeEnum.GROUP] = ta.validate_python(shared_tokens)
|
|
103
|
+
|
|
104
|
+
personal_tokens = resp.get(_PERSONAL_QPU_TOKENS_BACKEND, [])
|
|
105
|
+
for qpu_token in personal_tokens:
|
|
106
|
+
qpu_token["token_type"] = QpuTokenTypeEnum.PERSONAL
|
|
107
|
+
to_return[QpuTokenTypeEnum.PERSONAL] = ta.validate_python(personal_tokens)
|
|
97
108
|
|
|
98
109
|
return to_return
|
|
99
110
|
|
|
@@ -114,8 +125,8 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
114
125
|
|
|
115
126
|
token: QpuTokenOut = self.get(name, token_type)
|
|
116
127
|
|
|
117
|
-
response = self._client.
|
|
118
|
-
f"{self._get_endpoint_by_type(token_type)}/{token.
|
|
128
|
+
response = self._client.patch(
|
|
129
|
+
f"{self._get_endpoint_by_type(token_type)}/{token.name}",
|
|
119
130
|
content=json.dumps(qpu_token_update_data),
|
|
120
131
|
**kwargs,
|
|
121
132
|
)
|
|
@@ -126,9 +137,7 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
126
137
|
return QpuTokenOut.model_validate(qpu_token_data)
|
|
127
138
|
|
|
128
139
|
def delete(self, name: str, token_type: QpuTokenTypeEnum, **kwargs) -> None:
|
|
129
|
-
token: QpuTokenOut = self.get(name, token_type)
|
|
130
|
-
|
|
131
140
|
response = self._client.delete(
|
|
132
|
-
f"{self._get_endpoint_by_type(token_type)}/{
|
|
141
|
+
f"{self._get_endpoint_by_type(token_type)}/{name}", **kwargs
|
|
133
142
|
)
|
|
134
143
|
response.raise_for_status()
|
|
@@ -5,7 +5,6 @@ from typing import Any, Dict, List, Optional, Type, Union
|
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, ValidationError
|
|
7
7
|
|
|
8
|
-
from luna_sdk.exceptions.encryption_exception import EncryptionNotSetException
|
|
9
8
|
from luna_sdk.interfaces.solutions_repo_i import ISolutionsRepo
|
|
10
9
|
from luna_sdk.schemas.create.solution import SolutionIn
|
|
11
10
|
from luna_sdk.schemas.enums.solution import SenseEnum
|
|
@@ -70,7 +69,6 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
70
69
|
provider: str,
|
|
71
70
|
qpu_tokens: Optional[TokenProvider] = None,
|
|
72
71
|
solver_parameters: Optional[Union[Dict[str, Any], BaseModel]] = None,
|
|
73
|
-
encryption_key: Optional[str] = None,
|
|
74
72
|
name: Optional[str] = None,
|
|
75
73
|
fail_on_invalid_params: bool = True,
|
|
76
74
|
**kwargs,
|
|
@@ -85,9 +83,6 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
85
83
|
if rest_qpu_tokens is None:
|
|
86
84
|
rest_qpu_tokens = extract_qpu_tokens_from_env()
|
|
87
85
|
|
|
88
|
-
encryption_key = encryption_key or os.environ.get("LUNA_ENCRYPTION_KEY")
|
|
89
|
-
if encryption_key is None:
|
|
90
|
-
raise EncryptionNotSetException
|
|
91
86
|
params = SolutionsRepo.validate_solver_params(
|
|
92
87
|
solver_name, provider, solver_parameters, fail_on_invalid_params
|
|
93
88
|
)
|
|
@@ -98,7 +93,6 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
98
93
|
provider=provider,
|
|
99
94
|
parameters=params,
|
|
100
95
|
qpu_tokens=rest_qpu_tokens,
|
|
101
|
-
encryption_key=encryption_key,
|
|
102
96
|
name=name,
|
|
103
97
|
)
|
|
104
98
|
response = self._client.post(
|
|
@@ -118,7 +112,6 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
118
112
|
sleep_time_max: float = 60.0,
|
|
119
113
|
sleep_time_increment: float = 5.0,
|
|
120
114
|
sleep_time_initial: float = 5.0,
|
|
121
|
-
encryption_key: Optional[str] = None,
|
|
122
115
|
name: Optional[str] = None,
|
|
123
116
|
fail_on_invalid_params: bool = True,
|
|
124
117
|
**kwargs,
|
|
@@ -134,7 +127,6 @@ class SolutionsRepo(ISolutionsRepo):
|
|
|
134
127
|
provider=provider,
|
|
135
128
|
solver_parameters=params,
|
|
136
129
|
qpu_tokens=qpu_tokens,
|
|
137
|
-
encryption_key=encryption_key,
|
|
138
130
|
name=name,
|
|
139
131
|
**kwargs,
|
|
140
132
|
)
|
|
@@ -18,12 +18,9 @@ class CircuitIn(BaseModel):
|
|
|
18
18
|
The QASM circuit
|
|
19
19
|
params: Dict[str, Any]
|
|
20
20
|
Additional parameters
|
|
21
|
-
encryption_key: str
|
|
22
|
-
Encryption key to be used for encryption of QPU tokens.
|
|
23
21
|
"""
|
|
24
22
|
|
|
25
23
|
provider: CircuitProviderEnum
|
|
26
24
|
circuit: str
|
|
27
25
|
params: Dict[str, Any] = {}
|
|
28
26
|
qpu_tokens: Optional[RestAPITokenProvider] = None
|
|
29
|
-
encryption_key: str
|
|
@@ -13,14 +13,11 @@ class QpuTokenIn(BaseModel):
|
|
|
13
13
|
Name of provider
|
|
14
14
|
token: str
|
|
15
15
|
Token
|
|
16
|
-
encryption_key: str
|
|
17
|
-
Encryption key to be used for encryption of QPU tokens.
|
|
18
16
|
"""
|
|
19
17
|
|
|
20
18
|
name: str
|
|
21
19
|
provider: str
|
|
22
20
|
token: str
|
|
23
|
-
encryption_key: str
|
|
24
21
|
|
|
25
22
|
class Config:
|
|
26
23
|
extra = Extra.forbid
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
class OptFormat(str, Enum):
|
|
5
|
+
"""Enumeration of all supported formats."""
|
|
6
|
+
|
|
7
|
+
AQ_MODEL = "AQ_MODEL"
|
|
8
|
+
LP = "LP"
|
|
9
|
+
QUBO = "QUBO_MATRIX"
|
|
10
|
+
CQM = "CQM"
|
|
11
|
+
BQM = "BQM"
|
luna_sdk/schemas/optimization.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
from typing import Any, Dict, Generic,
|
|
1
|
+
from typing import Any, Dict, Generic, Optional, TypeVar
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, ConfigDict
|
|
4
4
|
|
|
5
|
-
from luna_sdk.schemas.enums.optimization import
|
|
5
|
+
from luna_sdk.schemas.enums.optimization import OptFormat
|
|
6
6
|
from luna_sdk.schemas.optimization_formats.bqm import BQMSchema
|
|
7
7
|
from luna_sdk.schemas.optimization_formats.cqm import CQMSchema
|
|
8
8
|
from luna_sdk.schemas.optimization_formats.lp import LPSchema
|
|
9
|
+
from luna_sdk.schemas.optimization_formats.qubo import QuboSchema
|
|
9
10
|
from luna_sdk.schemas.pretty_base import PrettyBase
|
|
10
11
|
from luna_sdk.schemas.wrappers import PydanticDatetimeWrapper
|
|
11
12
|
|
|
@@ -33,22 +34,56 @@ class Optimization(PrettyBase):
|
|
|
33
34
|
created_by: str
|
|
34
35
|
modified_date: Optional[PydanticDatetimeWrapper] = None
|
|
35
36
|
modified_by: Optional[str] = None
|
|
36
|
-
|
|
37
|
+
original_format: Optional[OptFormat] = None
|
|
37
38
|
use_case_name: Optional[str] = None
|
|
38
39
|
params: Optional[Dict[str, Any]] = None
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
verbose: bool = False
|
|
42
|
+
|
|
43
|
+
def __str__(self):
|
|
44
|
+
if self.verbose:
|
|
45
|
+
return self.details()
|
|
46
|
+
return self.subset()
|
|
47
|
+
|
|
48
|
+
def details(self):
|
|
49
|
+
trimmed_keys = [
|
|
50
|
+
"verbose",
|
|
51
|
+
]
|
|
52
|
+
data = self.model_dump()
|
|
53
|
+
output = ""
|
|
54
|
+
data_subset = {key: data[key] for key in data if key not in trimmed_keys}
|
|
55
|
+
ordered_subset = {
|
|
56
|
+
"id": data_subset.pop("id"),
|
|
57
|
+
"name": data_subset.pop("name"),
|
|
58
|
+
"original_format": data_subset.pop("original_format"),
|
|
59
|
+
**data_subset,
|
|
60
|
+
}
|
|
61
|
+
output += self._pretty_print(ordered_subset)
|
|
62
|
+
return output
|
|
63
|
+
|
|
64
|
+
def subset(self):
|
|
65
|
+
trimmed_keys = [
|
|
66
|
+
"created_by",
|
|
67
|
+
"modified_date",
|
|
68
|
+
"modified_by",
|
|
69
|
+
"use_case_name",
|
|
70
|
+
"params",
|
|
71
|
+
"verbose",
|
|
72
|
+
]
|
|
73
|
+
data = self.model_dump()
|
|
74
|
+
output = ""
|
|
75
|
+
data_subset = {key: data[key] for key in data if key not in trimmed_keys}
|
|
76
|
+
|
|
77
|
+
ordered_subset = {
|
|
78
|
+
"id": data_subset.pop("id"),
|
|
79
|
+
"name": data_subset.pop("name"),
|
|
80
|
+
"original_format": data_subset.pop("original_format"),
|
|
81
|
+
**data_subset,
|
|
82
|
+
}
|
|
83
|
+
output += self._pretty_print(ordered_subset)
|
|
84
|
+
return output
|
|
50
85
|
|
|
51
|
-
|
|
86
|
+
model_config = ConfigDict(extra="ignore", from_attributes=False)
|
|
52
87
|
|
|
53
88
|
|
|
54
89
|
class OptimizationBQM(Optimization, BQMSchema): ...
|
|
@@ -60,10 +95,13 @@ class OptimizationCQM(Optimization, CQMSchema): ...
|
|
|
60
95
|
class OptimizationLP(Optimization, LPSchema): ...
|
|
61
96
|
|
|
62
97
|
|
|
63
|
-
class OptimizationUseCase(Optimization,
|
|
98
|
+
class OptimizationUseCase(Optimization, QuboSchema):
|
|
64
99
|
use_case: Dict[str, Any]
|
|
65
100
|
|
|
66
101
|
|
|
102
|
+
class OptimizationQubo(Optimization, QuboSchema): ...
|
|
103
|
+
|
|
104
|
+
|
|
67
105
|
T = TypeVar("T")
|
|
68
106
|
|
|
69
107
|
|
luna_sdk/schemas/qpu_token.py
CHANGED
|
@@ -12,7 +12,7 @@ class QpuTokenSource(str, Enum):
|
|
|
12
12
|
# stored token in user account
|
|
13
13
|
PERSONAL = "personal"
|
|
14
14
|
# stored token in group account
|
|
15
|
-
|
|
15
|
+
GROUP = "group"
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class QpuToken(BaseModel):
|
|
@@ -44,16 +44,12 @@ class QpuTokenOut(BaseModel):
|
|
|
44
44
|
|
|
45
45
|
Attributes
|
|
46
46
|
----------
|
|
47
|
-
id: str
|
|
48
|
-
Id of the QPU token
|
|
49
47
|
name: Optional[str]
|
|
50
48
|
Name of the QPU token
|
|
51
49
|
provider: ProviderEnum
|
|
52
50
|
Name of provider: dwave | ibm
|
|
53
51
|
"""
|
|
54
52
|
|
|
55
|
-
id: str
|
|
56
|
-
|
|
57
53
|
name: str
|
|
58
54
|
provider: str
|
|
59
55
|
token_type: QpuTokenTypeEnum
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class _RESTQpuTokenSource(str, Enum):
|
|
5
|
+
"""
|
|
6
|
+
This schema allow us not to change entire backend,
|
|
7
|
+
but just sync SDK and everything else in terms of qpu token source.
|
|
8
|
+
Currently, the difference is that
|
|
9
|
+
SDK has group qpu token source
|
|
10
|
+
and backend has organization qpu token source which are mapped to each other.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# token currently passed in from the API call (not stored by us)
|
|
14
|
+
INLINE = "inline"
|
|
15
|
+
# stored token in user account
|
|
16
|
+
PERSONAL = "personal"
|
|
17
|
+
# stored token in group account
|
|
18
|
+
ORGANIZATION = "organization"
|
|
@@ -1,20 +1,48 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Optional, Union
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, Extra
|
|
4
4
|
|
|
5
|
-
from luna_sdk.schemas import QpuToken, TokenProvider
|
|
5
|
+
from luna_sdk.schemas import QpuToken, TokenProvider, QpuTokenSource
|
|
6
|
+
from luna_sdk.schemas.rest.qpu_token.qpu_token_source import _RESTQpuTokenSource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class _RestQpuToken(BaseModel):
|
|
10
|
+
source: _RESTQpuTokenSource
|
|
11
|
+
# A unique name for a stored token
|
|
12
|
+
name: Optional[str] = None
|
|
13
|
+
# This could be a QPU token, an API key or any token key for a QPU provider.
|
|
14
|
+
# If the token is not passed from this API call, one stored in the user's
|
|
15
|
+
# account will be used.
|
|
16
|
+
token: Optional[str] = None
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_qpu_token(cls, qpu_token: Optional[QpuToken]) -> Optional["_RestQpuToken"]:
|
|
20
|
+
if qpu_token is None:
|
|
21
|
+
return None
|
|
22
|
+
# Organizational tokens were renamed to group in #1851
|
|
23
|
+
# For smoother transition we only change naming in the SDK,
|
|
24
|
+
# and therefore we need a mapping between Group and Organization here.
|
|
25
|
+
# However, in backend for now QPU tokens still has source organization
|
|
26
|
+
# TODO: Remove it when backend I/O schema is changed
|
|
27
|
+
if qpu_token.source == QpuTokenSource.GROUP:
|
|
28
|
+
return cls(
|
|
29
|
+
source=_RESTQpuTokenSource.ORGANIZATION,
|
|
30
|
+
name=qpu_token.name,
|
|
31
|
+
token=qpu_token.token,
|
|
32
|
+
)
|
|
33
|
+
return cls.model_validate(qpu_token, from_attributes=True)
|
|
6
34
|
|
|
7
35
|
|
|
8
36
|
class AWSQpuTokens(BaseModel):
|
|
9
|
-
aws_access_key:
|
|
10
|
-
aws_secret_access_key:
|
|
37
|
+
aws_access_key: _RestQpuToken
|
|
38
|
+
aws_secret_access_key: _RestQpuToken
|
|
11
39
|
|
|
12
40
|
|
|
13
41
|
class RestAPITokenProvider(BaseModel):
|
|
14
|
-
dwave: Optional[
|
|
15
|
-
ibm: Optional[
|
|
16
|
-
fujitsu: Optional[
|
|
17
|
-
qctrl: Optional[
|
|
42
|
+
dwave: Optional[_RestQpuToken] = None
|
|
43
|
+
ibm: Optional[_RestQpuToken] = None
|
|
44
|
+
fujitsu: Optional[_RestQpuToken] = None
|
|
45
|
+
qctrl: Optional[_RestQpuToken] = None
|
|
18
46
|
aws: Optional[AWSQpuTokens] = None
|
|
19
47
|
|
|
20
48
|
@classmethod
|
|
@@ -28,16 +56,20 @@ class RestAPITokenProvider(BaseModel):
|
|
|
28
56
|
):
|
|
29
57
|
# Ignoring mypy here to receive validation error, because we always need 2 tokens for aws
|
|
30
58
|
aws = AWSQpuTokens(
|
|
31
|
-
aws_access_key=
|
|
32
|
-
|
|
33
|
-
|
|
59
|
+
aws_access_key=_RestQpuToken.from_qpu_token(
|
|
60
|
+
getattr(token_provider, "aws_access_key", None)
|
|
61
|
+
), # type: ignore[arg-type]
|
|
62
|
+
aws_secret_access_key=_RestQpuToken.from_qpu_token(
|
|
63
|
+
getattr( # type: ignore[arg-type]
|
|
64
|
+
token_provider, "aws_secret_access_key", None
|
|
65
|
+
)
|
|
34
66
|
),
|
|
35
67
|
)
|
|
36
68
|
return cls(
|
|
37
|
-
dwave=token_provider.dwave,
|
|
38
|
-
ibm=token_provider.ibm,
|
|
39
|
-
fujitsu=token_provider.fujitsu,
|
|
40
|
-
qctrl=token_provider.qctrl,
|
|
69
|
+
dwave=_RestQpuToken.from_qpu_token(token_provider.dwave),
|
|
70
|
+
ibm=_RestQpuToken.from_qpu_token(token_provider.ibm),
|
|
71
|
+
fujitsu=_RestQpuToken.from_qpu_token(token_provider.fujitsu),
|
|
72
|
+
qctrl=_RestQpuToken.from_qpu_token(token_provider.qctrl),
|
|
41
73
|
aws=aws,
|
|
42
74
|
)
|
|
43
75
|
|