azure-quantum 1.1.1__py3-none-any.whl → 1.1.2.dev0__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.
- azure/quantum/_authentication/_chained.py +21 -23
- azure/quantum/_authentication/_default.py +97 -159
- azure/quantum/_authentication/_token.py +41 -38
- azure/quantum/_client/_client.py +35 -9
- azure/quantum/_client/_configuration.py +12 -12
- azure/quantum/_client/_serialization.py +46 -37
- azure/quantum/_client/_version.py +1 -1
- azure/quantum/_client/models/_models.py +8 -8
- azure/quantum/_client/operations/_operations.py +261 -167
- azure/quantum/_constants.py +91 -0
- azure/quantum/_workspace_connection_params.py +544 -0
- azure/quantum/version.py +1 -1
- azure/quantum/workspace.py +119 -147
- {azure_quantum-1.1.1.dist-info → azure_quantum-1.1.2.dev0.dist-info}/METADATA +1 -1
- {azure_quantum-1.1.1.dist-info → azure_quantum-1.1.2.dev0.dist-info}/RECORD +17 -15
- {azure_quantum-1.1.1.dist-info → azure_quantum-1.1.2.dev0.dist-info}/WHEEL +0 -0
- {azure_quantum-1.1.1.dist-info → azure_quantum-1.1.2.dev0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License.
|
|
4
|
+
##
|
|
5
|
+
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from azure.identity._constants import EnvironmentVariables as SdkEnvironmentVariables
|
|
8
|
+
from azure.identity import _internal as AzureIdentityInternals
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EnvironmentVariables:
|
|
12
|
+
USER_AGENT_APPID = "AZURE_QUANTUM_PYTHON_APPID"
|
|
13
|
+
QUANTUM_LOCATION = "AZURE_QUANTUM_WORKSPACE_LOCATION"
|
|
14
|
+
LOCATION = "LOCATION"
|
|
15
|
+
QUANTUM_RESOURCE_GROUP = "AZURE_QUANTUM_WORKSPACE_RG"
|
|
16
|
+
RESOURCE_GROUP = "RESOURCE_GROUP"
|
|
17
|
+
QUANTUM_SUBSCRIPTION_ID = "AZURE_QUANTUM_SUBSCRIPTION_ID"
|
|
18
|
+
SUBSCRIPTION_ID = "SUBSCRIPTION_ID"
|
|
19
|
+
WORKSPACE_NAME = "AZURE_QUANTUM_WORKSPACE_NAME"
|
|
20
|
+
QUANTUM_ENV = "AZURE_QUANTUM_ENV"
|
|
21
|
+
AZURE_CLIENT_ID = SdkEnvironmentVariables.AZURE_CLIENT_ID
|
|
22
|
+
AZURE_CLIENT_SECRET = SdkEnvironmentVariables.AZURE_CLIENT_SECRET
|
|
23
|
+
AZURE_TENANT_ID = SdkEnvironmentVariables.AZURE_TENANT_ID
|
|
24
|
+
QUANTUM_TOKEN_FILE = "AZURE_QUANTUM_TOKEN_FILE"
|
|
25
|
+
CONNECTION_STRING = "AZURE_QUANTUM_CONNECTION_STRING"
|
|
26
|
+
ALL = [
|
|
27
|
+
USER_AGENT_APPID,
|
|
28
|
+
QUANTUM_LOCATION,
|
|
29
|
+
LOCATION,
|
|
30
|
+
QUANTUM_RESOURCE_GROUP,
|
|
31
|
+
RESOURCE_GROUP,
|
|
32
|
+
QUANTUM_SUBSCRIPTION_ID,
|
|
33
|
+
SUBSCRIPTION_ID,
|
|
34
|
+
WORKSPACE_NAME,
|
|
35
|
+
QUANTUM_ENV,
|
|
36
|
+
AZURE_CLIENT_ID,
|
|
37
|
+
AZURE_CLIENT_SECRET,
|
|
38
|
+
AZURE_TENANT_ID,
|
|
39
|
+
QUANTUM_TOKEN_FILE,
|
|
40
|
+
CONNECTION_STRING,
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class EnvironmentKind(Enum):
|
|
45
|
+
PRODUCTION = 1,
|
|
46
|
+
CANARY = 2,
|
|
47
|
+
DOGFOOD = 3
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ConnectionConstants:
|
|
51
|
+
DATA_PLANE_CREDENTIAL_SCOPE = "https://quantum.microsoft.com/.default"
|
|
52
|
+
ARM_CREDENTIAL_SCOPE = "https://management.azure.com/.default"
|
|
53
|
+
|
|
54
|
+
MSA_TENANT_ID = "9188040d-6c67-4c5b-b112-36a304b66dad"
|
|
55
|
+
|
|
56
|
+
AUTHORITY = AzureIdentityInternals.get_default_authority()
|
|
57
|
+
DOGFOOD_AUTHORITY = "login.windows-ppe.net"
|
|
58
|
+
|
|
59
|
+
# pylint: disable=unnecessary-lambda-assignment
|
|
60
|
+
GET_QUANTUM_PRODUCTION_ENDPOINT = \
|
|
61
|
+
lambda location: f"https://{location}.quantum.azure.com/"
|
|
62
|
+
GET_QUANTUM_CANARY_ENDPOINT = \
|
|
63
|
+
lambda location: f"https://{location or 'eastus2euap'}.quantum.azure.com/"
|
|
64
|
+
GET_QUANTUM_DOGFOOD_ENDPOINT = \
|
|
65
|
+
lambda location: f"https://{location}.quantum-test.azure.com/"
|
|
66
|
+
|
|
67
|
+
ARM_PRODUCTION_ENDPOINT = "https://management.azure.com/"
|
|
68
|
+
ARM_DOGFOOD_ENDPOINT = "https://api-dogfood.resources.windows-int.net/"
|
|
69
|
+
|
|
70
|
+
VALID_RESOURCE_ID = (
|
|
71
|
+
lambda subscription_id, resource_group, workspace_name:
|
|
72
|
+
f"/subscriptions/{subscription_id}" +
|
|
73
|
+
f"/resourceGroups/{resource_group}" +
|
|
74
|
+
"/providers/Microsoft.Quantum/" +
|
|
75
|
+
f"Workspaces/{workspace_name}"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
VALID_CONNECTION_STRING = (
|
|
79
|
+
lambda subscription_id, resource_group, workspace_name, api_key, quantum_endpoint:
|
|
80
|
+
f"SubscriptionId={subscription_id};" +
|
|
81
|
+
f"ResourceGroupName={resource_group};" +
|
|
82
|
+
f"WorkspaceName={workspace_name};" +
|
|
83
|
+
f"ApiKey={api_key};" +
|
|
84
|
+
f"QuantumEndpoint={quantum_endpoint};"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
QUANTUM_API_KEY_HEADER = "x-ms-quantum-api-key"
|
|
88
|
+
|
|
89
|
+
GUID_REGEX_PATTERN = (
|
|
90
|
+
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
|
91
|
+
)
|
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License.
|
|
4
|
+
##
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
import re
|
|
7
|
+
import os
|
|
8
|
+
from re import Match
|
|
9
|
+
from typing import (
|
|
10
|
+
Optional,
|
|
11
|
+
Callable,
|
|
12
|
+
Union,
|
|
13
|
+
Any
|
|
14
|
+
)
|
|
15
|
+
from azure.core.credentials import AzureKeyCredential
|
|
16
|
+
from azure.core.pipeline.policies import AzureKeyCredentialPolicy
|
|
17
|
+
from azure.quantum._authentication import _DefaultAzureCredential
|
|
18
|
+
from azure.quantum._constants import (
|
|
19
|
+
EnvironmentKind,
|
|
20
|
+
EnvironmentVariables,
|
|
21
|
+
ConnectionConstants,
|
|
22
|
+
GUID_REGEX_PATTERN,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
class WorkspaceConnectionParams:
|
|
26
|
+
"""
|
|
27
|
+
Internal Azure Quantum Python SDK class to handle logic
|
|
28
|
+
for the parameters needed to connect to a Workspace.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
RESOURCE_ID_REGEX = re.compile(
|
|
32
|
+
fr"""
|
|
33
|
+
^
|
|
34
|
+
/subscriptions/(?P<subscription_id>{GUID_REGEX_PATTERN})
|
|
35
|
+
/resourceGroups/(?P<resource_group>[^\s/]+)
|
|
36
|
+
/providers/Microsoft\.Quantum
|
|
37
|
+
/Workspaces/(?P<workspace_name>[^\s/]+)
|
|
38
|
+
$
|
|
39
|
+
""",
|
|
40
|
+
re.VERBOSE | re.IGNORECASE)
|
|
41
|
+
|
|
42
|
+
CONNECTION_STRING_REGEX = re.compile(
|
|
43
|
+
fr"""
|
|
44
|
+
^
|
|
45
|
+
SubscriptionId=(?P<subscription_id>{GUID_REGEX_PATTERN});
|
|
46
|
+
ResourceGroupName=(?P<resource_group>[^\s;]+);
|
|
47
|
+
WorkspaceName=(?P<workspace_name>[^\s;]+);
|
|
48
|
+
ApiKey=(?P<api_key>[^\s;]+);
|
|
49
|
+
QuantumEndpoint=(?P<quantum_endpoint>https://(?P<location>[^\s\.]+).quantum(?:-test)?.azure.com/);
|
|
50
|
+
""",
|
|
51
|
+
re.VERBOSE | re.IGNORECASE)
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
subscription_id: Optional[str] = None,
|
|
56
|
+
resource_group: Optional[str] = None,
|
|
57
|
+
workspace_name: Optional[str] = None,
|
|
58
|
+
location: Optional[str] = None,
|
|
59
|
+
quantum_endpoint: Optional[str] = None,
|
|
60
|
+
arm_endpoint: Optional[str] = None,
|
|
61
|
+
environment: Union[str, EnvironmentKind, None] = None,
|
|
62
|
+
credential: Optional[object] = None,
|
|
63
|
+
resource_id: Optional[str] = None,
|
|
64
|
+
user_agent: Optional[str] = None,
|
|
65
|
+
user_agent_app_id: Optional[str] = None,
|
|
66
|
+
tenant_id: Optional[str] = None,
|
|
67
|
+
client_id: Optional[str] = None,
|
|
68
|
+
api_version: Optional[str] = None,
|
|
69
|
+
connection_string: Optional[str] = None,
|
|
70
|
+
on_new_client_request: Optional[Callable] = None,
|
|
71
|
+
):
|
|
72
|
+
# fields are used for these properties since
|
|
73
|
+
# they have special getters/setters
|
|
74
|
+
self._location = None
|
|
75
|
+
self._environment = None
|
|
76
|
+
self._quantum_endpoint = None
|
|
77
|
+
self._arm_endpoint = None
|
|
78
|
+
# regular connection properties
|
|
79
|
+
self.subscription_id = None
|
|
80
|
+
self.resource_group = None
|
|
81
|
+
self.workspace_name = None
|
|
82
|
+
self.credential = None
|
|
83
|
+
self.user_agent = None
|
|
84
|
+
self.user_agent_app_id = None
|
|
85
|
+
self.client_id = None
|
|
86
|
+
self.tenant_id = None
|
|
87
|
+
self.api_version = None
|
|
88
|
+
# callback to create a new client if needed
|
|
89
|
+
# for example, when changing the user agent
|
|
90
|
+
self.on_new_client_request = on_new_client_request
|
|
91
|
+
# merge the connection parameters passed
|
|
92
|
+
# connection_string is set first as it
|
|
93
|
+
# should be overridden by other parameters
|
|
94
|
+
self.apply_connection_string(connection_string)
|
|
95
|
+
self.merge(
|
|
96
|
+
api_version=api_version,
|
|
97
|
+
arm_endpoint=arm_endpoint,
|
|
98
|
+
quantum_endpoint=quantum_endpoint,
|
|
99
|
+
client_id=client_id,
|
|
100
|
+
credential=credential,
|
|
101
|
+
environment=environment,
|
|
102
|
+
location=location,
|
|
103
|
+
resource_group=resource_group,
|
|
104
|
+
subscription_id=subscription_id,
|
|
105
|
+
tenant_id=tenant_id,
|
|
106
|
+
user_agent=user_agent,
|
|
107
|
+
user_agent_app_id=user_agent_app_id,
|
|
108
|
+
workspace_name=workspace_name,
|
|
109
|
+
)
|
|
110
|
+
self.apply_resource_id(resource_id=resource_id)
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def location(self):
|
|
114
|
+
"""
|
|
115
|
+
The Azure location.
|
|
116
|
+
On the setter, we normalize the value removing spaces
|
|
117
|
+
and converting it to lowercase.
|
|
118
|
+
"""
|
|
119
|
+
return self._location
|
|
120
|
+
|
|
121
|
+
@location.setter
|
|
122
|
+
def location(self, value: str):
|
|
123
|
+
self._location = (value.replace(" ", "").lower()
|
|
124
|
+
if isinstance(value, str)
|
|
125
|
+
else value)
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def environment(self):
|
|
129
|
+
"""
|
|
130
|
+
The environment kind, such as dogfood, canary or production.
|
|
131
|
+
Defaults to EnvironmentKind.PRODUCTION
|
|
132
|
+
"""
|
|
133
|
+
return self._environment or EnvironmentKind.PRODUCTION
|
|
134
|
+
|
|
135
|
+
@environment.setter
|
|
136
|
+
def environment(self, value: Union[str, EnvironmentKind]):
|
|
137
|
+
self._environment = (EnvironmentKind[value.upper()]
|
|
138
|
+
if isinstance(value, str)
|
|
139
|
+
else value)
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def quantum_endpoint(self):
|
|
143
|
+
"""
|
|
144
|
+
The Azure Quantum data plane endpoint.
|
|
145
|
+
Defaults to well-known endpoint based on the environment.
|
|
146
|
+
"""
|
|
147
|
+
if self._quantum_endpoint:
|
|
148
|
+
return self._quantum_endpoint
|
|
149
|
+
if not self.location:
|
|
150
|
+
raise ValueError("Location not specified")
|
|
151
|
+
if self.environment is EnvironmentKind.PRODUCTION:
|
|
152
|
+
return ConnectionConstants.GET_QUANTUM_PRODUCTION_ENDPOINT(self.location)
|
|
153
|
+
if self.environment is EnvironmentKind.CANARY:
|
|
154
|
+
return ConnectionConstants.GET_QUANTUM_CANARY_ENDPOINT(self.location)
|
|
155
|
+
if self.environment is EnvironmentKind.DOGFOOD:
|
|
156
|
+
return ConnectionConstants.GET_QUANTUM_DOGFOOD_ENDPOINT(self.location)
|
|
157
|
+
raise ValueError(f"Unknown environment `{self.environment}`.")
|
|
158
|
+
|
|
159
|
+
@quantum_endpoint.setter
|
|
160
|
+
def quantum_endpoint(self, value: str):
|
|
161
|
+
self._quantum_endpoint = value
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def arm_endpoint(self):
|
|
165
|
+
"""
|
|
166
|
+
The control plane endpoint.
|
|
167
|
+
Defaults to well-known arm_endpoint based on the environment.
|
|
168
|
+
"""
|
|
169
|
+
if self._arm_endpoint:
|
|
170
|
+
return self._arm_endpoint
|
|
171
|
+
if self.environment is EnvironmentKind.DOGFOOD:
|
|
172
|
+
return ConnectionConstants.ARM_DOGFOOD_ENDPOINT
|
|
173
|
+
if self.environment in [EnvironmentKind.PRODUCTION,
|
|
174
|
+
EnvironmentKind.CANARY]:
|
|
175
|
+
return ConnectionConstants.ARM_PRODUCTION_ENDPOINT
|
|
176
|
+
raise ValueError(f"Unknown environment `{self.environment}`.")
|
|
177
|
+
|
|
178
|
+
@arm_endpoint.setter
|
|
179
|
+
def arm_endpoint(self, value: str):
|
|
180
|
+
self._arm_endpoint = value
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def api_key(self):
|
|
184
|
+
"""
|
|
185
|
+
The api-key stored in a AzureKeyCredential.
|
|
186
|
+
"""
|
|
187
|
+
return (self.credential.key
|
|
188
|
+
if isinstance(self.credential, AzureKeyCredential)
|
|
189
|
+
else None)
|
|
190
|
+
|
|
191
|
+
@api_key.setter
|
|
192
|
+
def api_key(self, value: str):
|
|
193
|
+
if value:
|
|
194
|
+
self.credential = AzureKeyCredential(value)
|
|
195
|
+
self._api_key = value
|
|
196
|
+
|
|
197
|
+
def __repr__(self):
|
|
198
|
+
"""
|
|
199
|
+
Print all fields and properties.
|
|
200
|
+
"""
|
|
201
|
+
info = []
|
|
202
|
+
for key in vars(self):
|
|
203
|
+
info.append(f" {key}: {self.__dict__[key]}")
|
|
204
|
+
cls = type(self)
|
|
205
|
+
for key in dir(self):
|
|
206
|
+
attr = getattr(cls, key, None)
|
|
207
|
+
if attr and isinstance(attr, property) and attr.fget:
|
|
208
|
+
info.append(f" {key}: {attr.fget(self)}")
|
|
209
|
+
info.sort()
|
|
210
|
+
info.insert(0, super().__repr__())
|
|
211
|
+
return "\n".join(info)
|
|
212
|
+
|
|
213
|
+
def apply_resource_id(self, resource_id: str):
|
|
214
|
+
"""
|
|
215
|
+
Parses the resource_id and set the connection
|
|
216
|
+
parameters obtained from it.
|
|
217
|
+
"""
|
|
218
|
+
if resource_id:
|
|
219
|
+
match = re.search(
|
|
220
|
+
WorkspaceConnectionParams.RESOURCE_ID_REGEX,
|
|
221
|
+
resource_id)
|
|
222
|
+
if not match:
|
|
223
|
+
raise ValueError("Invalid resource id")
|
|
224
|
+
self._merge_re_match(match)
|
|
225
|
+
|
|
226
|
+
def apply_connection_string(self, connection_string: str):
|
|
227
|
+
"""
|
|
228
|
+
Parses the connection_string and set the connection
|
|
229
|
+
parameters obtained from it.
|
|
230
|
+
"""
|
|
231
|
+
if connection_string:
|
|
232
|
+
match = re.search(
|
|
233
|
+
WorkspaceConnectionParams.CONNECTION_STRING_REGEX,
|
|
234
|
+
connection_string)
|
|
235
|
+
if not match:
|
|
236
|
+
raise ValueError("Invalid connection string")
|
|
237
|
+
self._merge_re_match(match)
|
|
238
|
+
|
|
239
|
+
def merge(
|
|
240
|
+
self,
|
|
241
|
+
subscription_id: Optional[str] = None,
|
|
242
|
+
resource_group: Optional[str] = None,
|
|
243
|
+
workspace_name: Optional[str] = None,
|
|
244
|
+
location: Optional[str] = None,
|
|
245
|
+
quantum_endpoint: Optional[str] = None,
|
|
246
|
+
arm_endpoint: Optional[str] = None,
|
|
247
|
+
environment: Union[str, EnvironmentKind, None] = None,
|
|
248
|
+
credential: Optional[object] = None,
|
|
249
|
+
user_agent: Optional[str] = None,
|
|
250
|
+
user_agent_app_id: Optional[str] = None,
|
|
251
|
+
tenant_id: Optional[str] = None,
|
|
252
|
+
client_id: Optional[str] = None,
|
|
253
|
+
api_version: Optional[str] = None,
|
|
254
|
+
api_key: Optional[str] = None,
|
|
255
|
+
):
|
|
256
|
+
"""
|
|
257
|
+
Set all fields/properties with `not None` values
|
|
258
|
+
passed in the (named or key-valued) arguments
|
|
259
|
+
into this instance.
|
|
260
|
+
"""
|
|
261
|
+
self._merge(
|
|
262
|
+
api_version=api_version,
|
|
263
|
+
arm_endpoint=arm_endpoint,
|
|
264
|
+
quantum_endpoint=quantum_endpoint,
|
|
265
|
+
client_id=client_id,
|
|
266
|
+
credential=credential,
|
|
267
|
+
environment=environment,
|
|
268
|
+
location=location,
|
|
269
|
+
resource_group=resource_group,
|
|
270
|
+
subscription_id=subscription_id,
|
|
271
|
+
tenant_id=tenant_id,
|
|
272
|
+
user_agent=user_agent,
|
|
273
|
+
user_agent_app_id=user_agent_app_id,
|
|
274
|
+
workspace_name=workspace_name,
|
|
275
|
+
api_key=api_key,
|
|
276
|
+
merge_default_mode=False,
|
|
277
|
+
)
|
|
278
|
+
return self
|
|
279
|
+
|
|
280
|
+
def apply_defaults(
|
|
281
|
+
self,
|
|
282
|
+
subscription_id: Optional[str] = None,
|
|
283
|
+
resource_group: Optional[str] = None,
|
|
284
|
+
workspace_name: Optional[str] = None,
|
|
285
|
+
location: Optional[str] = None,
|
|
286
|
+
quantum_endpoint: Optional[str] = None,
|
|
287
|
+
arm_endpoint: Optional[str] = None,
|
|
288
|
+
environment: Union[str, EnvironmentKind, None] = None,
|
|
289
|
+
credential: Optional[object] = None,
|
|
290
|
+
user_agent: Optional[str] = None,
|
|
291
|
+
user_agent_app_id: Optional[str] = None,
|
|
292
|
+
tenant_id: Optional[str] = None,
|
|
293
|
+
client_id: Optional[str] = None,
|
|
294
|
+
api_version: Optional[str] = None,
|
|
295
|
+
api_key: Optional[str] = None,
|
|
296
|
+
) -> WorkspaceConnectionParams:
|
|
297
|
+
"""
|
|
298
|
+
Set all fields/properties with `not None` values
|
|
299
|
+
passed in the (named or key-valued) arguments
|
|
300
|
+
into this instance IF the instance does not have
|
|
301
|
+
the corresponding parameter set yet.
|
|
302
|
+
"""
|
|
303
|
+
self._merge(
|
|
304
|
+
api_version=api_version,
|
|
305
|
+
arm_endpoint=arm_endpoint,
|
|
306
|
+
quantum_endpoint=quantum_endpoint,
|
|
307
|
+
client_id=client_id,
|
|
308
|
+
credential=credential,
|
|
309
|
+
environment=environment,
|
|
310
|
+
location=location,
|
|
311
|
+
resource_group=resource_group,
|
|
312
|
+
subscription_id=subscription_id,
|
|
313
|
+
tenant_id=tenant_id,
|
|
314
|
+
user_agent=user_agent,
|
|
315
|
+
user_agent_app_id=user_agent_app_id,
|
|
316
|
+
workspace_name=workspace_name,
|
|
317
|
+
api_key=api_key,
|
|
318
|
+
merge_default_mode=True,
|
|
319
|
+
)
|
|
320
|
+
return self
|
|
321
|
+
|
|
322
|
+
def _merge(
|
|
323
|
+
self,
|
|
324
|
+
merge_default_mode: bool,
|
|
325
|
+
subscription_id: Optional[str] = None,
|
|
326
|
+
resource_group: Optional[str] = None,
|
|
327
|
+
workspace_name: Optional[str] = None,
|
|
328
|
+
location: Optional[str] = None,
|
|
329
|
+
quantum_endpoint: Optional[str] = None,
|
|
330
|
+
arm_endpoint: Optional[str] = None,
|
|
331
|
+
environment: Union[str, EnvironmentKind, None] = None,
|
|
332
|
+
credential: Optional[object] = None,
|
|
333
|
+
user_agent: Optional[str] = None,
|
|
334
|
+
user_agent_app_id: Optional[str] = None,
|
|
335
|
+
tenant_id: Optional[str] = None,
|
|
336
|
+
client_id: Optional[str] = None,
|
|
337
|
+
api_version: Optional[str] = None,
|
|
338
|
+
api_key: Optional[str] = None,
|
|
339
|
+
):
|
|
340
|
+
"""
|
|
341
|
+
Set all fields/properties with `not None` values
|
|
342
|
+
passed in the kwargs arguments
|
|
343
|
+
into this instance.
|
|
344
|
+
|
|
345
|
+
If merge_default_mode is True, skip setting
|
|
346
|
+
the field/property if it already has a value.
|
|
347
|
+
"""
|
|
348
|
+
def _get_value_or_default(old_value, new_value):
|
|
349
|
+
if merge_default_mode and old_value:
|
|
350
|
+
return old_value
|
|
351
|
+
if new_value:
|
|
352
|
+
return new_value
|
|
353
|
+
return old_value
|
|
354
|
+
|
|
355
|
+
self.subscription_id = _get_value_or_default(self.subscription_id, subscription_id)
|
|
356
|
+
self.resource_group = _get_value_or_default(self.resource_group, resource_group)
|
|
357
|
+
self.workspace_name = _get_value_or_default(self.workspace_name, workspace_name)
|
|
358
|
+
self.location = _get_value_or_default(self.location, location)
|
|
359
|
+
self.environment = _get_value_or_default(self.environment, environment)
|
|
360
|
+
self.credential = _get_value_or_default(self.credential, credential)
|
|
361
|
+
self.user_agent = _get_value_or_default(self.user_agent, user_agent)
|
|
362
|
+
self.user_agent_app_id = _get_value_or_default(self.user_agent_app_id, user_agent_app_id)
|
|
363
|
+
self.client_id = _get_value_or_default(self.client_id, client_id)
|
|
364
|
+
self.tenant_id = _get_value_or_default(self.tenant_id, tenant_id)
|
|
365
|
+
self.api_version = _get_value_or_default(self.api_version, api_version)
|
|
366
|
+
self.api_key = _get_value_or_default(self.api_key, api_key)
|
|
367
|
+
# for these properties that have a default value in the getter, we use
|
|
368
|
+
# the private field as the old_value
|
|
369
|
+
self.quantum_endpoint = _get_value_or_default(self._quantum_endpoint, quantum_endpoint)
|
|
370
|
+
self.arm_endpoint = _get_value_or_default(self._arm_endpoint, arm_endpoint)
|
|
371
|
+
return self
|
|
372
|
+
|
|
373
|
+
def _merge_connection_params(
|
|
374
|
+
self,
|
|
375
|
+
connection_params: WorkspaceConnectionParams,
|
|
376
|
+
merge_default_mode: bool = False,
|
|
377
|
+
) -> WorkspaceConnectionParams:
|
|
378
|
+
"""
|
|
379
|
+
Set all fields/properties with `not None` values
|
|
380
|
+
from the `connection_params` into this instance.
|
|
381
|
+
"""
|
|
382
|
+
self._merge(
|
|
383
|
+
api_version=connection_params.api_version,
|
|
384
|
+
client_id=connection_params.client_id,
|
|
385
|
+
credential=connection_params.credential,
|
|
386
|
+
environment=connection_params.environment,
|
|
387
|
+
location=connection_params.location,
|
|
388
|
+
resource_group=connection_params.resource_group,
|
|
389
|
+
subscription_id=connection_params.subscription_id,
|
|
390
|
+
tenant_id=connection_params.tenant_id,
|
|
391
|
+
user_agent=connection_params.user_agent,
|
|
392
|
+
user_agent_app_id=connection_params.user_agent_app_id,
|
|
393
|
+
workspace_name=connection_params.workspace_name,
|
|
394
|
+
merge_default_mode=merge_default_mode,
|
|
395
|
+
# for these properties that have a default value in the getter,
|
|
396
|
+
# so we use the private field instead
|
|
397
|
+
# pylint: disable=protected-access
|
|
398
|
+
arm_endpoint=connection_params._arm_endpoint,
|
|
399
|
+
quantum_endpoint=connection_params._quantum_endpoint,
|
|
400
|
+
)
|
|
401
|
+
return self
|
|
402
|
+
|
|
403
|
+
def get_credential_or_default(self) -> Any:
|
|
404
|
+
"""
|
|
405
|
+
Get the credential if one was set,
|
|
406
|
+
or defaults to a new _DefaultAzureCredential.
|
|
407
|
+
"""
|
|
408
|
+
return (self.credential
|
|
409
|
+
or _DefaultAzureCredential(
|
|
410
|
+
subscription_id=self.subscription_id,
|
|
411
|
+
arm_endpoint=self.arm_endpoint,
|
|
412
|
+
tenant_id=self.tenant_id))
|
|
413
|
+
|
|
414
|
+
def get_auth_policy(self) -> Any:
|
|
415
|
+
"""
|
|
416
|
+
Returns a AzureKeyCredentialPolicy if using an AzureKeyCredential.
|
|
417
|
+
Defaults to None.
|
|
418
|
+
"""
|
|
419
|
+
if isinstance(self.credential, AzureKeyCredential):
|
|
420
|
+
return AzureKeyCredentialPolicy(self.credential,
|
|
421
|
+
ConnectionConstants.QUANTUM_API_KEY_HEADER)
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
def append_user_agent(self, value: str):
|
|
425
|
+
"""
|
|
426
|
+
Append a new value to the Workspace's UserAgent and re-initialize the
|
|
427
|
+
QuantumClient. The values are appended using a dash.
|
|
428
|
+
|
|
429
|
+
:param value: UserAgent value to add, e.g. "azure-quantum-<plugin>"
|
|
430
|
+
"""
|
|
431
|
+
new_user_agent = None
|
|
432
|
+
|
|
433
|
+
if (
|
|
434
|
+
value
|
|
435
|
+
and value not in (self.user_agent or "")
|
|
436
|
+
):
|
|
437
|
+
new_user_agent = (f"{self.user_agent}-{value}"
|
|
438
|
+
if self.user_agent else value)
|
|
439
|
+
|
|
440
|
+
if new_user_agent != self.user_agent:
|
|
441
|
+
self.user_agent = new_user_agent
|
|
442
|
+
if self.on_new_client_request:
|
|
443
|
+
self.on_new_client_request()
|
|
444
|
+
|
|
445
|
+
def get_full_user_agent(self):
|
|
446
|
+
"""
|
|
447
|
+
Get the full Azure Quantum Python SDK UserAgent
|
|
448
|
+
that is sent to the service via the header.
|
|
449
|
+
"""
|
|
450
|
+
full_user_agent = self.user_agent
|
|
451
|
+
app_id = self.user_agent_app_id
|
|
452
|
+
if self.user_agent_app_id:
|
|
453
|
+
full_user_agent = (f"{app_id} {full_user_agent}"
|
|
454
|
+
if full_user_agent else app_id)
|
|
455
|
+
return full_user_agent
|
|
456
|
+
|
|
457
|
+
def is_complete(self) -> bool:
|
|
458
|
+
"""
|
|
459
|
+
Returns true if we have all necessary parameters
|
|
460
|
+
to connect to the Azure Quantum Workspace.
|
|
461
|
+
"""
|
|
462
|
+
return (self.location
|
|
463
|
+
and self.subscription_id
|
|
464
|
+
and self.resource_group
|
|
465
|
+
and self.workspace_name
|
|
466
|
+
and self.get_credential_or_default())
|
|
467
|
+
|
|
468
|
+
def assert_complete(self):
|
|
469
|
+
"""
|
|
470
|
+
Raises ValueError if we don't have all necessary parameters
|
|
471
|
+
to connect to the Azure Quantum Workspace.
|
|
472
|
+
"""
|
|
473
|
+
if not self.is_complete():
|
|
474
|
+
raise ValueError(
|
|
475
|
+
"""
|
|
476
|
+
Azure Quantum workspace not fully specified.
|
|
477
|
+
Please specify one of the following:
|
|
478
|
+
1) A valid combination of location and resource ID.
|
|
479
|
+
2) A valid combination of location, subscription ID,
|
|
480
|
+
resource group name, and workspace name.
|
|
481
|
+
3) A valid connection string (via Workspace.from_connection_string()).
|
|
482
|
+
""")
|
|
483
|
+
|
|
484
|
+
def default_from_env_vars(self) -> WorkspaceConnectionParams:
|
|
485
|
+
"""
|
|
486
|
+
Apply default values found in the environment variables
|
|
487
|
+
if current parameters are not set.
|
|
488
|
+
"""
|
|
489
|
+
self.subscription_id = (self.subscription_id
|
|
490
|
+
or os.environ.get(EnvironmentVariables.QUANTUM_SUBSCRIPTION_ID)
|
|
491
|
+
or os.environ.get(EnvironmentVariables.SUBSCRIPTION_ID))
|
|
492
|
+
self.resource_group = (self.resource_group
|
|
493
|
+
or os.environ.get(EnvironmentVariables.QUANTUM_RESOURCE_GROUP)
|
|
494
|
+
or os.environ.get(EnvironmentVariables.RESOURCE_GROUP))
|
|
495
|
+
self.workspace_name = (self.workspace_name
|
|
496
|
+
or os.environ.get(EnvironmentVariables.WORKSPACE_NAME))
|
|
497
|
+
self.location = (self.location
|
|
498
|
+
or os.environ.get(EnvironmentVariables.QUANTUM_LOCATION)
|
|
499
|
+
or os.environ.get(EnvironmentVariables.LOCATION))
|
|
500
|
+
self.user_agent_app_id = (self.user_agent_app_id
|
|
501
|
+
or os.environ.get(EnvironmentVariables.USER_AGENT_APPID))
|
|
502
|
+
self.tenant_id = (self.tenant_id
|
|
503
|
+
or os.environ.get(EnvironmentVariables.AZURE_TENANT_ID))
|
|
504
|
+
self.client_id = (self.client_id
|
|
505
|
+
or os.environ.get(EnvironmentVariables.AZURE_CLIENT_ID))
|
|
506
|
+
# for these properties we use the private field
|
|
507
|
+
# because the getter return default values
|
|
508
|
+
self.environment = (self._environment
|
|
509
|
+
or os.environ.get(EnvironmentVariables.QUANTUM_ENV))
|
|
510
|
+
# only try to use the connection string from env var if
|
|
511
|
+
# we really need it
|
|
512
|
+
if (not self.location
|
|
513
|
+
or not self.subscription_id
|
|
514
|
+
or not self.resource_group
|
|
515
|
+
or not self.workspace_name
|
|
516
|
+
or not self.credential
|
|
517
|
+
):
|
|
518
|
+
self._merge_connection_params(
|
|
519
|
+
connection_params=WorkspaceConnectionParams(
|
|
520
|
+
connection_string=os.environ.get(EnvironmentVariables.CONNECTION_STRING)),
|
|
521
|
+
merge_default_mode=True)
|
|
522
|
+
return self
|
|
523
|
+
|
|
524
|
+
@classmethod
|
|
525
|
+
def from_env_vars(
|
|
526
|
+
cls,
|
|
527
|
+
) -> WorkspaceConnectionParams:
|
|
528
|
+
"""
|
|
529
|
+
Initialize the WorkspaceConnectionParams from values found
|
|
530
|
+
in the environment variables.
|
|
531
|
+
"""
|
|
532
|
+
return WorkspaceConnectionParams().default_from_env_vars()
|
|
533
|
+
|
|
534
|
+
def _merge_re_match(self, re_match: Match[str]):
|
|
535
|
+
def get_value(group_name):
|
|
536
|
+
return re_match.groupdict().get(group_name)
|
|
537
|
+
self.merge(
|
|
538
|
+
subscription_id=get_value('subscription_id'),
|
|
539
|
+
resource_group=get_value('resource_group'),
|
|
540
|
+
workspace_name=get_value('workspace_name'),
|
|
541
|
+
location=get_value('location'),
|
|
542
|
+
quantum_endpoint=get_value('quantum_endpoint'),
|
|
543
|
+
api_key=get_value('api_key'),
|
|
544
|
+
)
|
azure/quantum/version.py
CHANGED