luna-quantum 0.0.29__py3-none-any.whl → 0.0.33__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.33.dist-info}/METADATA +1 -1
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.33.dist-info}/RECORD +22 -20
- 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/interfaces/optimization_repo_i.py +5 -4
- luna_sdk/interfaces/qpu_token_repo_i.py +18 -12
- luna_sdk/repositories/optimization_repo.py +11 -10
- luna_sdk/repositories/qpu_token_repo.py +36 -20
- luna_sdk/schemas/enums/optimization.py +8 -7
- luna_sdk/schemas/enums/qpu_token_type.py +1 -1
- luna_sdk/schemas/optimization.py +8 -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/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.33.dist-info}/LICENSE +0 -0
- {luna_quantum-0.0.29.dist-info → luna_quantum-0.0.33.dist-info}/WHEEL +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
luna_sdk/__init__.py,sha256=9s6JkcSeRF4WtFo80TelzXXHFhX8w7fXiaJr59V9ScM,100
|
|
2
2
|
luna_sdk/controllers/__init__.py,sha256=ivTapH8np5mQeVEevxwsWawCtVSG4Wep72rNp7nEZXw,60
|
|
3
|
-
luna_sdk/controllers/
|
|
4
|
-
luna_sdk/controllers/luna_platform_client.py,sha256=
|
|
5
|
-
luna_sdk/controllers/luna_q.py,sha256=
|
|
6
|
-
luna_sdk/controllers/luna_solve.py,sha256=
|
|
7
|
-
luna_sdk/controllers/luna_transform.py,sha256=
|
|
3
|
+
luna_sdk/controllers/luna_http_client.py,sha256=_q3_o-bjC61uQMnNTfbbGei0eNR_AoIv-2R1cYRfEgU,819
|
|
4
|
+
luna_sdk/controllers/luna_platform_client.py,sha256=EH1jxruuRKwaJ1Vos79PGT4-hwp7jdoSaRFKqjUMbZA,2406
|
|
5
|
+
luna_sdk/controllers/luna_q.py,sha256=cv28o2fYDSaI8iAsfMYWtR68mfuUDxY3jmBWY2KnkRk,1199
|
|
6
|
+
luna_sdk/controllers/luna_solve.py,sha256=ioMdB7Rlx-1-XB5WE5OT8oVlO_T1l5T64R-ccaNUCAA,1797
|
|
7
|
+
luna_sdk/controllers/luna_transform.py,sha256=7kdIp5oRMG1NQZ1hBSkcNrj-z6g_2dWvQZ4j8BK3M0A,1337
|
|
8
8
|
luna_sdk/error/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
luna_sdk/error/http_error_utils.py,sha256=
|
|
9
|
+
luna_sdk/error/http_error_utils.py,sha256=qZ4a43GVR35-bn3QTVmGZBJzEjieo43r36M2G5rfIyw,3509
|
|
10
10
|
luna_sdk/exceptions/__init__.py,sha256=DSKaPN374rR2zccmpLvlqntxDsjFwgSexXtva795ae0,52
|
|
11
11
|
luna_sdk/exceptions/encryption_exception.py,sha256=qe38EPRen4c63ti6bbA3jXl4PK48Ommi_cb2Lvhn8tg,264
|
|
12
12
|
luna_sdk/exceptions/luna_exception.py,sha256=m7U3qFpP9Sc77Z3RG9I4bQXsJSQuVeBLvfHQWziC9sQ,114
|
|
@@ -23,8 +23,8 @@ luna_sdk/interfaces/clients/luna_transform_i.py,sha256=xpS2ODs83rICbA3oAKzf80rpB
|
|
|
23
23
|
luna_sdk/interfaces/cplex_repo_i.py,sha256=a2CWG1m4YmQAlcM022Xfk09BHVmcd3y2H-GMr1N4vx8,3786
|
|
24
24
|
luna_sdk/interfaces/info_repo_i.py,sha256=hCUYNoqjAKwz6l-61XtymX-UboosDX1RaTTiX64EXXc,1345
|
|
25
25
|
luna_sdk/interfaces/lp_repo_i.py,sha256=hixIKvJ8jz9VOUi33B3K2VvFLcR7eKfeooJwktquyhc,3052
|
|
26
|
-
luna_sdk/interfaces/optimization_repo_i.py,sha256=
|
|
27
|
-
luna_sdk/interfaces/qpu_token_repo_i.py,sha256=
|
|
26
|
+
luna_sdk/interfaces/optimization_repo_i.py,sha256=4JZikxWTJZTX4tG85ydSP711WROQ5B8RtbvOp1EDvxE,6202
|
|
27
|
+
luna_sdk/interfaces/qpu_token_repo_i.py,sha256=q5aWiGxFnuRSasgHcceRAjQ0NvMPRoBfkeJHCByBy_0,4626
|
|
28
28
|
luna_sdk/interfaces/repository_i.py,sha256=vJz8pbggkuLLC333qzjepj3TMPh49LUnyh3pJDlcGi0,287
|
|
29
29
|
luna_sdk/interfaces/solutions_repo_i.py,sha256=YmQxgDGSLZNQ-P7jzlw1zTnut5Q1KVeRbcJEuocB3VQ,7767
|
|
30
30
|
luna_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -33,8 +33,8 @@ luna_sdk/repositories/circuit_repo.py,sha256=h3Moypl-pba8J-sNTBsOxnbKtu6RCmmX5c_
|
|
|
33
33
|
luna_sdk/repositories/cplex_repo.py,sha256=6vlx6YTJoDSWFSZDDNrPk3E7pa5WWGqG25bhTwQdqHQ,5098
|
|
34
34
|
luna_sdk/repositories/info_repo.py,sha256=GzRW5RwhRJrNjujw8Y7vJY8vV_tHzbfwXo0viHuxqUM,1270
|
|
35
35
|
luna_sdk/repositories/lp_repo.py,sha256=T44XMbdbW7k9a4z6JgIj1kb0bBZxepn-93vxdZOQa80,4370
|
|
36
|
-
luna_sdk/repositories/optimization_repo.py,sha256=
|
|
37
|
-
luna_sdk/repositories/qpu_token_repo.py,sha256=
|
|
36
|
+
luna_sdk/repositories/optimization_repo.py,sha256=xHjMdXhzdwt9DtZG7AvGtUgOqWH142veOpAzaNe-nxk,6078
|
|
37
|
+
luna_sdk/repositories/qpu_token_repo.py,sha256=6V3PH2YLMoWx6Dv6hxDoe2ohXH2mRN37nfvzVS6bHDA,5063
|
|
38
38
|
luna_sdk/repositories/solutions_repo.py,sha256=Q5Q30oRyUnayXkp4z_jPcjDpxYRoPjzWBWUqg2EAFWQ,9242
|
|
39
39
|
luna_sdk/schemas/__init__.py,sha256=lTix3zUl2Z8ZLA2BTF4pls5S-kqlVZ3cIdAZwGxPSUI,248
|
|
40
40
|
luna_sdk/schemas/circuit.py,sha256=r3Bv0lyhrvFoI3Gf8eq-PS3kyivTWY3IJmRH0X2LoCk,1067
|
|
@@ -46,25 +46,27 @@ luna_sdk/schemas/create/qubo.py,sha256=5Y_jWicEnoV82Ubc-f0a_qy9hCuPBumhsGWY8wzMI
|
|
|
46
46
|
luna_sdk/schemas/create/solution.py,sha256=K97JHH-p5z0P_niTVX6YBPoDc0rgIpJG5O4uaUhcs48,410
|
|
47
47
|
luna_sdk/schemas/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
luna_sdk/schemas/enums/circuit.py,sha256=smz_DouDo_K8rs4N5aIOj2PS9w6DX1CFYX0bv6f6JFw,252
|
|
49
|
-
luna_sdk/schemas/enums/optimization.py,sha256=
|
|
49
|
+
luna_sdk/schemas/enums/optimization.py,sha256=XtFdcfLxGe-MAL64itjxszhRkTcUzUf83tO-5DBVLeY,198
|
|
50
50
|
luna_sdk/schemas/enums/problem.py,sha256=HWL6Lc1pqPtJ0J-rXkUTL6WHe2fiBY1ctuZvDnx1hmM,754
|
|
51
|
-
luna_sdk/schemas/enums/qpu_token_type.py,sha256=
|
|
51
|
+
luna_sdk/schemas/enums/qpu_token_type.py,sha256=KBRrB8ExuTTmpp48obxdJGWwWEHb7xgq9Ajjwptl1VY,105
|
|
52
52
|
luna_sdk/schemas/enums/solution.py,sha256=Vax6MX62UDwApbwzf1nrhuFWw1Iiq77gUch7_1roCYo,114
|
|
53
53
|
luna_sdk/schemas/enums/status.py,sha256=KHaOgePqB3GNhFYLo2Sp-JAEXBPN_ZVDmj2WobrT5N4,204
|
|
54
54
|
luna_sdk/schemas/enums/timeframe.py,sha256=vwoZsgAYGvqF67qdcXMEnHkqbiRcVY5uK-4-ZTFcurI,238
|
|
55
55
|
luna_sdk/schemas/error_message.py,sha256=svCs-mWQsp3BMEhzZFqskbyP6iS78eVUOPaiWFc4sEQ,307
|
|
56
|
-
luna_sdk/schemas/optimization.py,sha256=
|
|
56
|
+
luna_sdk/schemas/optimization.py,sha256=pCbDL93PFGf7IOGz-0PHFrrpOwQdszm78WnS0oo2xqU,1884
|
|
57
57
|
luna_sdk/schemas/optimization_formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
58
|
luna_sdk/schemas/optimization_formats/bqm.py,sha256=rrmiZYe_iEdgBFusJeJfY8PVSxgf1Wv79FgMQUm2YVs,910
|
|
59
59
|
luna_sdk/schemas/optimization_formats/cqm.py,sha256=VZiNJy4yc-8o3gHoH0E-uaNOHj7UfAGCqznTzKBv0NQ,4257
|
|
60
60
|
luna_sdk/schemas/optimization_formats/lp.py,sha256=iXFDBmHktHsYc79ngSraylCpa-EVMFwN01788fnjFzY,175
|
|
61
61
|
luna_sdk/schemas/optimization_formats/qm.py,sha256=yUEZF7FOvXv1Mb5FMiX1q0Rk5w2ltrh7HInfFEiVSXU,912
|
|
62
|
+
luna_sdk/schemas/optimization_formats/qubo.py,sha256=YN-VbPGTgqOKJuJ7t_TT8H_WIWr1ifU974K98W9Blao,135
|
|
62
63
|
luna_sdk/schemas/pretty_base.py,sha256=ZyVdwdY5JfmNlfqZDm6MdTs5roNGtv0Pe805r4N25Z4,1845
|
|
63
|
-
luna_sdk/schemas/qpu_token.py,sha256=
|
|
64
|
+
luna_sdk/schemas/qpu_token.py,sha256=CFKbAhFgo0G-LO_lameHH4-iOFUJWx9hmMWi3xQwURw,1508
|
|
64
65
|
luna_sdk/schemas/representation.py,sha256=0RKVV0XxHOJZ1o9grxTq5ri3cGLziyCFObDwQuXIOEY,364
|
|
65
66
|
luna_sdk/schemas/rest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
67
|
luna_sdk/schemas/rest/qpu_token/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
|
-
luna_sdk/schemas/rest/qpu_token/
|
|
68
|
+
luna_sdk/schemas/rest/qpu_token/qpu_token_source.py,sha256=EPMXHpgxqsQ4uJ1hlwe5gPdSsjuHEuKKAIMtBFgPJ1A,583
|
|
69
|
+
luna_sdk/schemas/rest/qpu_token/token_provider.py,sha256=3Gecn2AmN7E_wAPUac_c55Fg-LwdDKsgbwAN2-0msJU,2985
|
|
68
70
|
luna_sdk/schemas/solution.py,sha256=IRtZneNRN5IbSEMHKHc0NYJ7lf74RxZTHoYJI7z2QoY,6871
|
|
69
71
|
luna_sdk/schemas/solver_info.py,sha256=ZUCdTI8zpPZ8EquLYyrLU35pZ4VkzcPUSYeQWkdijHM,799
|
|
70
72
|
luna_sdk/schemas/solver_parameters/aws/__init__.py,sha256=CXjKWzgnP_d1_RvQUfWyaaWvsZ1FxLJN5K61QmRa-uw,33
|
|
@@ -157,8 +159,8 @@ luna_sdk/schemas/wrappers/__init__.py,sha256=1zq5BWRjDidbRJ346JOCSbP6Q9rhf4NiLhZ
|
|
|
157
159
|
luna_sdk/schemas/wrappers/datetime_wrapper.py,sha256=6usmPJNRYA4Fe_-0NGwe7RYams46CCAXpJs8YULu_yc,794
|
|
158
160
|
luna_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
159
161
|
luna_sdk/utils/parameter_finder.py,sha256=LKkd1upH3Djd6eqkcSQ2feNwPUiKi8soYkx6JT1_VSg,2937
|
|
160
|
-
luna_sdk/utils/qpu_tokens.py,sha256=
|
|
161
|
-
luna_quantum-0.0.
|
|
162
|
-
luna_quantum-0.0.
|
|
163
|
-
luna_quantum-0.0.
|
|
164
|
-
luna_quantum-0.0.
|
|
162
|
+
luna_sdk/utils/qpu_tokens.py,sha256=xrh5KSoWzbul-6eRa0ELH9iwEENanE7PIms7jlCt3NY,1641
|
|
163
|
+
luna_quantum-0.0.33.dist-info/LICENSE,sha256=rwwuFPLz36oRvjWu2oEeX42Qtn9gmbh7zRC2OqCFNaI,11342
|
|
164
|
+
luna_quantum-0.0.33.dist-info/METADATA,sha256=5ojTfod6BKHtIKnRn_utUm3CVd9OifvhK8Lk2xqhD8o,2311
|
|
165
|
+
luna_quantum-0.0.33.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
166
|
+
luna_quantum-0.0.33.dist-info/RECORD,,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
from httpx import Client, Response
|
|
5
|
+
|
|
6
|
+
from luna_sdk.error.http_error_utils import HttpErrorUtils
|
|
7
|
+
from luna_sdk.exceptions.timeout_exception import TimeoutException
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LunaHTTPClient(Client):
|
|
11
|
+
_version: str = version("luna-quantum")
|
|
12
|
+
|
|
13
|
+
_user_agent: str = f"LunaSDK/{_version}"
|
|
14
|
+
|
|
15
|
+
def __init__(self, *args, **kwargs):
|
|
16
|
+
super().__init__(*args, **kwargs)
|
|
17
|
+
|
|
18
|
+
self.headers["User-Agent"] = self._user_agent
|
|
19
|
+
|
|
20
|
+
def request(self, *args, **kwargs) -> Response:
|
|
21
|
+
try:
|
|
22
|
+
response: Response = super().request(*args, **kwargs)
|
|
23
|
+
except httpx.TimeoutException:
|
|
24
|
+
# Handle all possible in httpx timeout exceptions
|
|
25
|
+
raise TimeoutException()
|
|
26
|
+
HttpErrorUtils.check_for_error(response)
|
|
27
|
+
return response
|
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional, Literal
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
import httpx
|
|
5
6
|
|
|
6
|
-
from luna_sdk.controllers.
|
|
7
|
+
from luna_sdk.controllers.luna_http_client import LunaHTTPClient
|
|
8
|
+
from luna_sdk.error.http_error_utils import HttpErrorUtils
|
|
7
9
|
from luna_sdk.interfaces.clients.client_i import IClient
|
|
8
10
|
|
|
9
11
|
|
|
12
|
+
class LunaPrefixEnum(str, Enum):
|
|
13
|
+
LUNA_SOLVE = "luna-solve"
|
|
14
|
+
LUNA_Q = "luna-q"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def check_httpx_exceptions(response):
|
|
18
|
+
HttpErrorUtils.check_for_error(response)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class APIKeyAuth(httpx.Auth):
|
|
22
|
+
def __init__(self, token):
|
|
23
|
+
self.token = token
|
|
24
|
+
|
|
25
|
+
def auth_flow(self, request):
|
|
26
|
+
request.headers["Luna-API-Key"] = self.token
|
|
27
|
+
yield request
|
|
28
|
+
|
|
29
|
+
|
|
10
30
|
class LunaPlatformClient(IClient):
|
|
11
31
|
_base_url: str = ""
|
|
12
32
|
|
|
13
|
-
_client: Client = None # type: ignore
|
|
33
|
+
_client: httpx.Client = None # type: ignore
|
|
14
34
|
|
|
15
35
|
def __init__(
|
|
16
36
|
self,
|
|
17
|
-
|
|
18
|
-
|
|
37
|
+
api_key: str,
|
|
38
|
+
api: LunaPrefixEnum,
|
|
19
39
|
base_url: str = os.getenv("LUNA_BASE_URL", "https://api.aqarios.com"),
|
|
20
40
|
timeout: Optional[float] = 240.0,
|
|
21
41
|
):
|
|
@@ -26,10 +46,10 @@ class LunaPlatformClient(IClient):
|
|
|
26
46
|
|
|
27
47
|
Parameters
|
|
28
48
|
----------
|
|
29
|
-
|
|
30
|
-
User's
|
|
31
|
-
|
|
32
|
-
|
|
49
|
+
api_key:
|
|
50
|
+
User's API key
|
|
51
|
+
api: str
|
|
52
|
+
Current API with which luna client is working. Can be luna-solve or luna-q.
|
|
33
53
|
base_url:
|
|
34
54
|
Base API URL.
|
|
35
55
|
If you want to use API not on your local PC then change it.
|
|
@@ -41,17 +61,15 @@ class LunaPlatformClient(IClient):
|
|
|
41
61
|
itself will time out after 240 seconds.
|
|
42
62
|
Default: 240.0
|
|
43
63
|
"""
|
|
44
|
-
self._base_url = f"{base_url}/api"
|
|
64
|
+
self._base_url = f"{base_url}/{api.value}/api/v1"
|
|
45
65
|
|
|
46
66
|
# setup client
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
email=email,
|
|
50
|
-
password=password,
|
|
51
|
-
login_url=f"{base_url}/accessToken",
|
|
67
|
+
self._client = LunaHTTPClient(
|
|
68
|
+
auth=APIKeyAuth(api_key),
|
|
52
69
|
base_url=self._base_url,
|
|
53
70
|
follow_redirects=True,
|
|
54
71
|
timeout=timeout,
|
|
72
|
+
event_hooks={"response": [check_httpx_exceptions]},
|
|
55
73
|
)
|
|
56
74
|
|
|
57
75
|
def __del__(self):
|
luna_sdk/controllers/luna_q.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from luna_sdk.controllers.luna_platform_client import LunaPlatformClient
|
|
3
|
+
from luna_sdk.controllers.luna_platform_client import LunaPlatformClient, LunaPrefixEnum
|
|
4
4
|
from luna_sdk.interfaces import ICircuitRepo
|
|
5
5
|
from luna_sdk.interfaces.clients.luna_q_i import ILunaQ
|
|
6
6
|
from luna_sdk.interfaces.qpu_token_repo_i import IQpuTokenRepo
|
|
@@ -11,23 +11,21 @@ class LunaQ(LunaPlatformClient, ILunaQ):
|
|
|
11
11
|
qpu_token: IQpuTokenRepo = None # type: ignore
|
|
12
12
|
circuit: ICircuitRepo = None # type: ignore
|
|
13
13
|
|
|
14
|
-
def __init__(self,
|
|
14
|
+
def __init__(self, api_key: str, timeout: Optional[float] = 240.0):
|
|
15
15
|
"""
|
|
16
16
|
LunaQ is the main entrypoint for all LunaQ related tasks.
|
|
17
17
|
|
|
18
18
|
Parameters
|
|
19
19
|
----------
|
|
20
|
-
|
|
21
|
-
User's
|
|
22
|
-
password: str
|
|
23
|
-
User's password
|
|
20
|
+
api_key: str
|
|
21
|
+
User's API key
|
|
24
22
|
timeout: float
|
|
25
23
|
Default timeout in seconds for the requests via the LunaQ client. `None`
|
|
26
24
|
means that the SDK uses no timeouts. Note that either way the Luna platform
|
|
27
25
|
itself will time out after 240 seconds.
|
|
28
26
|
Default: 240.0
|
|
29
27
|
"""
|
|
30
|
-
super().__init__(
|
|
28
|
+
super().__init__(api_key=api_key, api=LunaPrefixEnum.LUNA_Q, timeout=timeout)
|
|
31
29
|
|
|
32
30
|
self.circuit = CircuitRepo(self._client)
|
|
33
31
|
self.qpu_token = QpuTokenRepo(self._client)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from luna_sdk.controllers.luna_platform_client import LunaPlatformClient
|
|
3
|
+
from luna_sdk.controllers.luna_platform_client import LunaPlatformClient, LunaPrefixEnum
|
|
4
4
|
from luna_sdk.interfaces import ISolutionsRepo
|
|
5
5
|
from luna_sdk.interfaces.clients.luna_solve_i import ILunaSolve
|
|
6
6
|
from luna_sdk.interfaces.info_repo_i import IInfoRepo
|
|
@@ -18,23 +18,25 @@ class LunaSolve(LunaPlatformClient, ILunaSolve):
|
|
|
18
18
|
qpu_token: IQpuTokenRepo = None # type: ignore
|
|
19
19
|
info: IInfoRepo = None # type: ignore
|
|
20
20
|
|
|
21
|
-
def __init__(self,
|
|
21
|
+
def __init__(self, api_key: str, timeout: Optional[float] = 240.0):
|
|
22
22
|
"""
|
|
23
23
|
LunaSolve is the main entrypoint for all LunaSolve related tasks.
|
|
24
24
|
|
|
25
25
|
Parameters
|
|
26
26
|
----------
|
|
27
|
-
|
|
28
|
-
User's
|
|
29
|
-
password: str
|
|
30
|
-
User's password
|
|
27
|
+
api_key: str
|
|
28
|
+
User's API key
|
|
31
29
|
timeout: float
|
|
32
30
|
Default timeout in seconds for the requests via the LunaQ client. `None`
|
|
33
31
|
means that the SDK uses no timeouts. Note that either way the Luna platform
|
|
34
32
|
itself will time out after 240 seconds.
|
|
35
33
|
Default: 240.0
|
|
36
34
|
"""
|
|
37
|
-
super().__init__(
|
|
35
|
+
super().__init__(
|
|
36
|
+
api_key=api_key,
|
|
37
|
+
api=LunaPrefixEnum.LUNA_SOLVE,
|
|
38
|
+
timeout=timeout,
|
|
39
|
+
)
|
|
38
40
|
|
|
39
41
|
self.optimization = OptimizationRepo(self._client)
|
|
40
42
|
self.solution = SolutionsRepo(self._client)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from luna_sdk.controllers.luna_platform_client import LunaPlatformClient
|
|
3
|
+
from luna_sdk.controllers.luna_platform_client import LunaPlatformClient, LunaPrefixEnum
|
|
4
4
|
from luna_sdk.interfaces.clients.luna_transform_i import ILunaTransform
|
|
5
5
|
from luna_sdk.interfaces.cplex_repo_i import ICplexRepo
|
|
6
6
|
from luna_sdk.interfaces.lp_repo_i import ILPRepo
|
|
@@ -12,23 +12,29 @@ class LunaTransform(LunaPlatformClient, ILunaTransform):
|
|
|
12
12
|
cplex: ICplexRepo = None # type: ignore
|
|
13
13
|
lp: ILPRepo = None # type: ignore
|
|
14
14
|
|
|
15
|
-
def __init__(
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
api_key: str,
|
|
18
|
+
timeout: Optional[float] = 240.0,
|
|
19
|
+
):
|
|
16
20
|
"""
|
|
17
21
|
LunaTransform is the main entrypoint for all LunaTransform related tasks.
|
|
18
22
|
|
|
19
23
|
Parameters
|
|
20
24
|
----------
|
|
21
|
-
|
|
22
|
-
User's
|
|
23
|
-
password: str
|
|
24
|
-
User's password
|
|
25
|
+
api_key: str
|
|
26
|
+
User's API key
|
|
25
27
|
timeout: float
|
|
26
28
|
Default timeout in seconds for the requests via the LunaQ client. `None`
|
|
27
29
|
means that the SDK uses no timeouts. Note that either way the Luna platform
|
|
28
30
|
itself will time out after 240 seconds.
|
|
29
31
|
Default: 240.0
|
|
30
32
|
"""
|
|
31
|
-
super().__init__(
|
|
33
|
+
super().__init__(
|
|
34
|
+
api_key=api_key,
|
|
35
|
+
api=LunaPrefixEnum.LUNA_SOLVE,
|
|
36
|
+
timeout=timeout,
|
|
37
|
+
)
|
|
32
38
|
|
|
33
39
|
self.cplex = CplexRepo(self._client)
|
|
34
40
|
self.lp = LPRepo(self._client)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import httpx
|
|
5
|
+
from httpx import RequestError, Response
|
|
5
6
|
|
|
6
7
|
from luna_sdk.exceptions.luna_server_exception import LunaServerException
|
|
7
8
|
from luna_sdk.schemas.error_message import ErrorMessage
|
|
@@ -50,6 +51,12 @@ class HttpErrorUtils:
|
|
|
50
51
|
" leading to a timeout. Try reducing the size of the optimization.",
|
|
51
52
|
)
|
|
52
53
|
|
|
54
|
+
elif response.status_code == 403:
|
|
55
|
+
exception = create_error_message(
|
|
56
|
+
"FORBIDDEN",
|
|
57
|
+
response.text,
|
|
58
|
+
)
|
|
59
|
+
|
|
53
60
|
return exception
|
|
54
61
|
|
|
55
62
|
@staticmethod
|
|
@@ -70,15 +77,15 @@ class HttpErrorUtils:
|
|
|
70
77
|
If an error occurred with the request outside the http status codes 4xx and 5xx.
|
|
71
78
|
"""
|
|
72
79
|
try:
|
|
80
|
+
response.read()
|
|
73
81
|
response.raise_for_status()
|
|
74
|
-
except HTTPStatusError as e:
|
|
82
|
+
except httpx.HTTPStatusError as e:
|
|
75
83
|
exception: Optional[LunaServerException]
|
|
76
84
|
|
|
77
85
|
try:
|
|
78
86
|
error_msg: ErrorMessage = ErrorMessage.model_validate_json(
|
|
79
87
|
response.text
|
|
80
88
|
)
|
|
81
|
-
|
|
82
89
|
# Convert the error message to the correct exception
|
|
83
90
|
exception = LunaServerException(response.status_code, error_msg)
|
|
84
91
|
|
|
@@ -5,9 +5,10 @@ from typing import List, Optional
|
|
|
5
5
|
from dimod import BinaryQuadraticModel, ConstrainedQuadraticModel
|
|
6
6
|
|
|
7
7
|
from luna_sdk.interfaces.repository_i import IRepository
|
|
8
|
-
from luna_sdk.schemas.enums.optimization import
|
|
8
|
+
from luna_sdk.schemas.enums.optimization import OptFormat
|
|
9
9
|
from luna_sdk.schemas.enums.timeframe import TimeframeEnum
|
|
10
10
|
from luna_sdk.schemas.optimization import Optimization
|
|
11
|
+
from luna_sdk.schemas.solution import Numeric
|
|
11
12
|
from luna_sdk.schemas.use_cases import UseCase
|
|
12
13
|
|
|
13
14
|
|
|
@@ -35,7 +36,7 @@ class IOptimizationRepo(IRepository, ABC):
|
|
|
35
36
|
def get_all(
|
|
36
37
|
self,
|
|
37
38
|
timeframe: Optional[TimeframeEnum] = None,
|
|
38
|
-
input_type: Optional[
|
|
39
|
+
input_type: Optional[OptFormat] = None,
|
|
39
40
|
limit: int = 50,
|
|
40
41
|
offset: int = 0,
|
|
41
42
|
**kwargs,
|
|
@@ -48,7 +49,7 @@ class IOptimizationRepo(IRepository, ABC):
|
|
|
48
49
|
timeframe: Optional[TimeframeEnum]
|
|
49
50
|
Only return optimizations created within a specified timeframe.
|
|
50
51
|
Default None.
|
|
51
|
-
input_type: Optional[
|
|
52
|
+
input_type: Optional[OptFormat]
|
|
52
53
|
Only return optimizations of a specified input type. Default None.
|
|
53
54
|
limit:
|
|
54
55
|
Limit the number of optimizations to be returned. Default value 50.
|
|
@@ -66,7 +67,7 @@ class IOptimizationRepo(IRepository, ABC):
|
|
|
66
67
|
|
|
67
68
|
@abstractmethod
|
|
68
69
|
def create_from_qubo(
|
|
69
|
-
self, name: str, matrix: List[List[
|
|
70
|
+
self, name: str, matrix: List[List[Numeric]], **kwargs
|
|
70
71
|
) -> Optimization:
|
|
71
72
|
"""
|
|
72
73
|
Create an optimization from a QUBO matrix.
|
|
@@ -18,7 +18,7 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
18
18
|
**kwargs,
|
|
19
19
|
) -> QpuTokenOut:
|
|
20
20
|
"""
|
|
21
|
-
Create
|
|
21
|
+
Create QPU token
|
|
22
22
|
|
|
23
23
|
Parameters
|
|
24
24
|
----------
|
|
@@ -29,8 +29,8 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
29
29
|
token: str
|
|
30
30
|
Token
|
|
31
31
|
token_type: QpuTokenTypeEnum
|
|
32
|
-
There are two types of QPU tokens: PERSONAL and
|
|
33
|
-
All users of
|
|
32
|
+
There are two types of QPU tokens: PERSONAL and GROUP.
|
|
33
|
+
All users of a group can use group QPU tokens.
|
|
34
34
|
User QPU tokens can only be used by the user who created them.
|
|
35
35
|
encryption_key: Optional[str]
|
|
36
36
|
Encryption key to be used for encryption of QPU tokens.
|
|
@@ -50,6 +50,8 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
50
50
|
filter_provider: Optional[str] = None,
|
|
51
51
|
name: Optional[str] = None,
|
|
52
52
|
token_type: Optional[QpuTokenTypeEnum] = None,
|
|
53
|
+
limit: Optional[int] = None,
|
|
54
|
+
offset: Optional[int] = None,
|
|
53
55
|
**kwargs,
|
|
54
56
|
) -> Dict[QpuTokenTypeEnum, List[QpuTokenOut]]:
|
|
55
57
|
"""
|
|
@@ -62,8 +64,12 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
62
64
|
name: Optional[str]
|
|
63
65
|
Name of the QPU token that should be retrieved
|
|
64
66
|
token_type: Optional[QpuTokenTypeEnum]
|
|
65
|
-
If you want to retrieve only user or
|
|
67
|
+
If you want to retrieve only user or group QPU tokens
|
|
66
68
|
otherwise all QPU tokens will be retrieved
|
|
69
|
+
limit: Optional[int]
|
|
70
|
+
Number of items to fetch. Default is 10.
|
|
71
|
+
offset: Optional[int]
|
|
72
|
+
Optional. Number of items to skip. Default is 0.
|
|
67
73
|
**kwargs
|
|
68
74
|
Parameters to pass to `httpx.request`.
|
|
69
75
|
|
|
@@ -84,8 +90,8 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
84
90
|
name: str
|
|
85
91
|
Name of the QPU token that should be retrieved
|
|
86
92
|
token_type: QpuTokenTypeEnum
|
|
87
|
-
There are two types of QPU tokens: PERSONAL and
|
|
88
|
-
All users of
|
|
93
|
+
There are two types of QPU tokens: PERSONAL and GROUP.
|
|
94
|
+
All users of a group can use group QPU tokens.
|
|
89
95
|
User QPU tokens can only be used by the user who created them.
|
|
90
96
|
**kwargs
|
|
91
97
|
Parameters to pass to `httpx.request`.
|
|
@@ -106,7 +112,7 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
106
112
|
**kwargs,
|
|
107
113
|
) -> QpuTokenOut:
|
|
108
114
|
"""
|
|
109
|
-
Update
|
|
115
|
+
Update QPU token by id.
|
|
110
116
|
|
|
111
117
|
Parameters
|
|
112
118
|
----------
|
|
@@ -115,8 +121,8 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
115
121
|
new_name: str
|
|
116
122
|
The new name
|
|
117
123
|
token_type: QpuTokenTypeEnum
|
|
118
|
-
There are two types of QPU tokens: PERSONAL and
|
|
119
|
-
All users of
|
|
124
|
+
There are two types of QPU tokens: PERSONAL and GROUP.
|
|
125
|
+
All users of a group can use group QPU tokens.
|
|
120
126
|
User QPU tokens can only be used by the user who created them.
|
|
121
127
|
**kwargs
|
|
122
128
|
Parameters to pass to `httpx.request`.
|
|
@@ -131,15 +137,15 @@ class IQpuTokenRepo(IRepository, ABC):
|
|
|
131
137
|
@abstractmethod
|
|
132
138
|
def delete(self, name: str, token_type: QpuTokenTypeEnum, **kwargs) -> None:
|
|
133
139
|
"""
|
|
134
|
-
Delete
|
|
140
|
+
Delete QPU token by name.
|
|
135
141
|
|
|
136
142
|
Parameters
|
|
137
143
|
----------
|
|
138
144
|
name: str
|
|
139
145
|
Name of the QPU token that should be deleted
|
|
140
146
|
token_type: QpuTokenTypeEnum
|
|
141
|
-
There are two types of QPU tokens: PERSONAL and
|
|
142
|
-
All users of
|
|
147
|
+
There are two types of QPU tokens: PERSONAL and GROUP.
|
|
148
|
+
All users of a group can use organization QPU tokens.
|
|
143
149
|
User QPU tokens can only be used by the user who created them.
|
|
144
150
|
**kwargs
|
|
145
151
|
Parameters to pass to `httpx.request`.
|
|
@@ -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
|
|
|
@@ -22,15 +22,15 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
22
22
|
if token_type is None:
|
|
23
23
|
return f"{self._endpoint}"
|
|
24
24
|
elif token_type == QpuTokenTypeEnum.PERSONAL:
|
|
25
|
-
return f"{self._endpoint}/
|
|
25
|
+
return f"{self._endpoint}/private"
|
|
26
26
|
else:
|
|
27
|
-
return f"{self._endpoint}/
|
|
27
|
+
return f"{self._endpoint}/shared"
|
|
28
28
|
|
|
29
29
|
def _get_by_name(
|
|
30
30
|
self, name: str, token_type: QpuTokenTypeEnum, **kwargs
|
|
31
31
|
) -> QpuTokenOut:
|
|
32
32
|
response: Response = self._client.get(
|
|
33
|
-
f"{self._get_endpoint_by_type(token_type)}/
|
|
33
|
+
f"{self._get_endpoint_by_type(token_type)}/{name}", **kwargs
|
|
34
34
|
)
|
|
35
35
|
response.raise_for_status()
|
|
36
36
|
|
|
@@ -72,6 +72,8 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
72
72
|
filter_provider: Optional[str] = None,
|
|
73
73
|
name: Optional[str] = None,
|
|
74
74
|
token_type: Optional[QpuTokenTypeEnum] = None,
|
|
75
|
+
limit: Optional[int] = None,
|
|
76
|
+
offset: Optional[int] = None,
|
|
75
77
|
**kwargs,
|
|
76
78
|
) -> Dict[QpuTokenTypeEnum, List[QpuTokenOut]]:
|
|
77
79
|
params = {}
|
|
@@ -80,20 +82,36 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
80
82
|
|
|
81
83
|
if name:
|
|
82
84
|
params["name"] = name
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
response.raise_for_status()
|
|
85
|
+
if limit is not None:
|
|
86
|
+
params["limit"] = str(limit)
|
|
87
|
+
if offset is not None:
|
|
88
|
+
params["offset"] = str(offset)
|
|
88
89
|
|
|
89
90
|
to_return: Dict[QpuTokenTypeEnum, List[QpuTokenOut]] = {}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
if token_type is None or token_type == QpuTokenTypeEnum.PERSONAL:
|
|
92
|
+
response = self._client.get(
|
|
93
|
+
self._get_endpoint_by_type(QpuTokenTypeEnum.PERSONAL),
|
|
94
|
+
params=params,
|
|
95
|
+
**kwargs,
|
|
96
|
+
)
|
|
97
|
+
response.raise_for_status()
|
|
98
|
+
personal_qpu_tokens = response.json()
|
|
99
|
+
to_return[QpuTokenTypeEnum.PERSONAL] = [
|
|
100
|
+
QpuTokenOut(**qpu_token, token_type=QpuTokenTypeEnum.PERSONAL)
|
|
101
|
+
for qpu_token in personal_qpu_tokens
|
|
102
|
+
]
|
|
103
|
+
if token_type is None or token_type == QpuTokenTypeEnum.GROUP:
|
|
104
|
+
response = self._client.get(
|
|
105
|
+
self._get_endpoint_by_type(QpuTokenTypeEnum.GROUP),
|
|
106
|
+
params=params,
|
|
107
|
+
**kwargs,
|
|
108
|
+
)
|
|
109
|
+
response.raise_for_status()
|
|
110
|
+
shared_qpu_tokens = response.json()
|
|
111
|
+
to_return[QpuTokenTypeEnum.GROUP] = [
|
|
112
|
+
QpuTokenOut(**qpu_token, token_type=QpuTokenTypeEnum.GROUP)
|
|
113
|
+
for qpu_token in shared_qpu_tokens
|
|
114
|
+
]
|
|
97
115
|
|
|
98
116
|
return to_return
|
|
99
117
|
|
|
@@ -114,8 +132,8 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
114
132
|
|
|
115
133
|
token: QpuTokenOut = self.get(name, token_type)
|
|
116
134
|
|
|
117
|
-
response = self._client.
|
|
118
|
-
f"{self._get_endpoint_by_type(token_type)}/{token.
|
|
135
|
+
response = self._client.patch(
|
|
136
|
+
f"{self._get_endpoint_by_type(token_type)}/{token.name}",
|
|
119
137
|
content=json.dumps(qpu_token_update_data),
|
|
120
138
|
**kwargs,
|
|
121
139
|
)
|
|
@@ -126,9 +144,7 @@ class QpuTokenRepo(IQpuTokenRepo):
|
|
|
126
144
|
return QpuTokenOut.model_validate(qpu_token_data)
|
|
127
145
|
|
|
128
146
|
def delete(self, name: str, token_type: QpuTokenTypeEnum, **kwargs) -> None:
|
|
129
|
-
token: QpuTokenOut = self.get(name, token_type)
|
|
130
|
-
|
|
131
147
|
response = self._client.delete(
|
|
132
|
-
f"{self._get_endpoint_by_type(token_type)}/{
|
|
148
|
+
f"{self._get_endpoint_by_type(token_type)}/{name}", **kwargs
|
|
133
149
|
)
|
|
134
150
|
response.raise_for_status()
|
|
@@ -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,24 +34,13 @@ 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
|
model_config = ConfigDict(extra="ignore", from_attributes=False)
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
class OptimizationQubo(BaseModel):
|
|
44
|
-
id: str
|
|
45
|
-
name: Optional[str] = None
|
|
46
|
-
created_date: PydanticDatetimeWrapper
|
|
47
|
-
created_by: str
|
|
48
|
-
modified_date: Optional[PydanticDatetimeWrapper] = None
|
|
49
|
-
modified_by: Optional[str] = None
|
|
50
|
-
|
|
51
|
-
matrix: List[List[float]]
|
|
52
|
-
|
|
53
|
-
|
|
54
44
|
class OptimizationBQM(Optimization, BQMSchema): ...
|
|
55
45
|
|
|
56
46
|
|
|
@@ -60,10 +50,13 @@ class OptimizationCQM(Optimization, CQMSchema): ...
|
|
|
60
50
|
class OptimizationLP(Optimization, LPSchema): ...
|
|
61
51
|
|
|
62
52
|
|
|
63
|
-
class OptimizationUseCase(Optimization,
|
|
53
|
+
class OptimizationUseCase(Optimization, QuboSchema):
|
|
64
54
|
use_case: Dict[str, Any]
|
|
65
55
|
|
|
66
56
|
|
|
57
|
+
class OptimizationQubo(Optimization, QuboSchema): ...
|
|
58
|
+
|
|
59
|
+
|
|
67
60
|
T = TypeVar("T")
|
|
68
61
|
|
|
69
62
|
|
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
|
|
luna_sdk/utils/qpu_tokens.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
|
-
from luna_sdk.schemas import
|
|
3
|
+
from luna_sdk.schemas.rest.qpu_token.qpu_token_source import _RESTQpuTokenSource
|
|
4
4
|
from luna_sdk.schemas.rest.qpu_token.token_provider import (
|
|
5
5
|
RestAPITokenProvider,
|
|
6
6
|
AWSQpuTokens,
|
|
7
|
+
_RestQpuToken,
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
|
|
@@ -15,37 +16,37 @@ def extract_qpu_tokens_from_env() -> RestAPITokenProvider:
|
|
|
15
16
|
aws_access_key = os.environ.get("LUNA_AWS_ACCESS_KEY")
|
|
16
17
|
aws_access_secret_key = os.environ.get("LUNA_AWS_SECRET_ACCESS_KEY")
|
|
17
18
|
return RestAPITokenProvider(
|
|
18
|
-
ibm=
|
|
19
|
-
source=
|
|
19
|
+
ibm=_RestQpuToken(
|
|
20
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
20
21
|
token=ibm_token,
|
|
21
22
|
)
|
|
22
23
|
if ibm_token
|
|
23
24
|
else None,
|
|
24
|
-
dwave=
|
|
25
|
-
source=
|
|
25
|
+
dwave=_RestQpuToken(
|
|
26
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
26
27
|
token=dwave_token,
|
|
27
28
|
)
|
|
28
29
|
if dwave_token
|
|
29
30
|
else None,
|
|
30
|
-
qctrl=
|
|
31
|
-
source=
|
|
31
|
+
qctrl=_RestQpuToken(
|
|
32
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
32
33
|
token=qctrl_token,
|
|
33
34
|
)
|
|
34
35
|
if qctrl_token
|
|
35
36
|
else None,
|
|
36
|
-
fujitsu=
|
|
37
|
-
source=
|
|
37
|
+
fujitsu=_RestQpuToken(
|
|
38
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
38
39
|
token=fujitsu_token,
|
|
39
40
|
)
|
|
40
41
|
if fujitsu_token
|
|
41
42
|
else None,
|
|
42
43
|
aws=AWSQpuTokens(
|
|
43
|
-
aws_access_key=
|
|
44
|
-
source=
|
|
44
|
+
aws_access_key=_RestQpuToken(
|
|
45
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
45
46
|
token=aws_access_key,
|
|
46
47
|
),
|
|
47
|
-
aws_secret_access_key=
|
|
48
|
-
source=
|
|
48
|
+
aws_secret_access_key=_RestQpuToken(
|
|
49
|
+
source=_RESTQpuTokenSource.INLINE,
|
|
49
50
|
token=aws_access_secret_key,
|
|
50
51
|
),
|
|
51
52
|
),
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from http.client import UNAUTHORIZED
|
|
3
|
-
from importlib.metadata import version
|
|
4
|
-
|
|
5
|
-
from httpx import Client, ReadTimeout, Response
|
|
6
|
-
|
|
7
|
-
from luna_sdk.error.http_error_utils import HttpErrorUtils
|
|
8
|
-
from luna_sdk.exceptions.timeout_exception import TimeoutException
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class CustomLoginClient(Client):
|
|
12
|
-
_login_url: str
|
|
13
|
-
_email: str
|
|
14
|
-
_password: str
|
|
15
|
-
_bearer_token: str
|
|
16
|
-
|
|
17
|
-
_version: str = version("luna-quantum")
|
|
18
|
-
|
|
19
|
-
_user_agent: str = f"LunaSDK/{_version}"
|
|
20
|
-
|
|
21
|
-
def __init__(self, email: str, password: str, login_url: str, *args, **kwargs):
|
|
22
|
-
super().__init__(*args, **kwargs)
|
|
23
|
-
self._email = email
|
|
24
|
-
self._password = password
|
|
25
|
-
self._login_url = login_url
|
|
26
|
-
|
|
27
|
-
self.headers["User-Agent"] = self._user_agent
|
|
28
|
-
|
|
29
|
-
def login(self, email: str, password: str):
|
|
30
|
-
with Client() as client:
|
|
31
|
-
headers = {
|
|
32
|
-
"accept": "application/json",
|
|
33
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
34
|
-
"User-Agent": self._user_agent,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
response: Response = client.post(
|
|
38
|
-
self._login_url,
|
|
39
|
-
data={"username": email, "password": password},
|
|
40
|
-
headers=headers,
|
|
41
|
-
# Ensure timeout is high enough. CustomLoginClient will be deleted in
|
|
42
|
-
# near future anyway.
|
|
43
|
-
timeout=None,
|
|
44
|
-
)
|
|
45
|
-
HttpErrorUtils.check_for_error(response)
|
|
46
|
-
|
|
47
|
-
self._bearer_token = response.json()["access_token"]
|
|
48
|
-
|
|
49
|
-
def request(self, *args, **kwargs) -> Response:
|
|
50
|
-
try:
|
|
51
|
-
response: Response = super().request(*args, **kwargs)
|
|
52
|
-
if response.status_code == UNAUTHORIZED:
|
|
53
|
-
logging.info("Unauthorized - trying to login")
|
|
54
|
-
|
|
55
|
-
self.login(self._email, self._password)
|
|
56
|
-
|
|
57
|
-
logging.info("Re-login successful")
|
|
58
|
-
self.headers.update(
|
|
59
|
-
headers={"authorization": f"Bearer {self._bearer_token}"}
|
|
60
|
-
)
|
|
61
|
-
logging.info("Trying request again")
|
|
62
|
-
response = super().request(*args, **kwargs)
|
|
63
|
-
except ReadTimeout:
|
|
64
|
-
raise TimeoutException()
|
|
65
|
-
HttpErrorUtils.check_for_error(response)
|
|
66
|
-
return response
|
|
File without changes
|
|
File without changes
|