databricks-sdk 0.28.0__py3-none-any.whl → 0.30.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of databricks-sdk might be problematic. Click here for more details.

Files changed (31) hide show
  1. databricks/sdk/__init__.py +74 -22
  2. databricks/sdk/config.py +89 -48
  3. databricks/sdk/core.py +38 -9
  4. databricks/sdk/credentials_provider.py +134 -57
  5. databricks/sdk/data_plane.py +65 -0
  6. databricks/sdk/dbutils.py +81 -3
  7. databricks/sdk/mixins/files.py +12 -4
  8. databricks/sdk/oauth.py +8 -6
  9. databricks/sdk/service/apps.py +977 -0
  10. databricks/sdk/service/billing.py +602 -218
  11. databricks/sdk/service/catalog.py +263 -62
  12. databricks/sdk/service/compute.py +515 -94
  13. databricks/sdk/service/dashboards.py +1310 -2
  14. databricks/sdk/service/iam.py +99 -88
  15. databricks/sdk/service/jobs.py +159 -166
  16. databricks/sdk/service/marketplace.py +74 -58
  17. databricks/sdk/service/oauth2.py +149 -70
  18. databricks/sdk/service/pipelines.py +73 -53
  19. databricks/sdk/service/serving.py +332 -694
  20. databricks/sdk/service/settings.py +424 -4
  21. databricks/sdk/service/sharing.py +235 -26
  22. databricks/sdk/service/sql.py +2484 -553
  23. databricks/sdk/service/vectorsearch.py +75 -0
  24. databricks/sdk/useragent.py +144 -0
  25. databricks/sdk/version.py +1 -1
  26. {databricks_sdk-0.28.0.dist-info → databricks_sdk-0.30.0.dist-info}/METADATA +37 -16
  27. {databricks_sdk-0.28.0.dist-info → databricks_sdk-0.30.0.dist-info}/RECORD +31 -28
  28. {databricks_sdk-0.28.0.dist-info → databricks_sdk-0.30.0.dist-info}/WHEEL +1 -1
  29. {databricks_sdk-0.28.0.dist-info → databricks_sdk-0.30.0.dist-info}/LICENSE +0 -0
  30. {databricks_sdk-0.28.0.dist-info → databricks_sdk-0.30.0.dist-info}/NOTICE +0 -0
  31. {databricks_sdk-0.28.0.dist-info → databricks_sdk-0.30.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,977 @@
1
+ # Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import random
7
+ import time
8
+ from dataclasses import dataclass
9
+ from datetime import timedelta
10
+ from enum import Enum
11
+ from typing import Callable, Dict, Iterator, List, Optional
12
+
13
+ from ..errors import OperationFailed
14
+ from ._internal import Wait, _enum, _from_dict, _repeated_dict
15
+
16
+ _LOG = logging.getLogger('databricks.sdk')
17
+
18
+ # all definitions in this file are in alphabetical order
19
+
20
+
21
+ @dataclass
22
+ class App:
23
+ name: str
24
+ """The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.
25
+ It must be unique within the workspace."""
26
+
27
+ active_deployment: Optional[AppDeployment] = None
28
+ """The active deployment of the app."""
29
+
30
+ create_time: Optional[str] = None
31
+ """The creation time of the app. Formatted timestamp in ISO 6801."""
32
+
33
+ creator: Optional[str] = None
34
+ """The email of the user that created the app."""
35
+
36
+ description: Optional[str] = None
37
+ """The description of the app."""
38
+
39
+ pending_deployment: Optional[AppDeployment] = None
40
+ """The pending deployment of the app."""
41
+
42
+ service_principal_id: Optional[int] = None
43
+
44
+ service_principal_name: Optional[str] = None
45
+
46
+ status: Optional[AppStatus] = None
47
+
48
+ update_time: Optional[str] = None
49
+ """The update time of the app. Formatted timestamp in ISO 6801."""
50
+
51
+ updater: Optional[str] = None
52
+ """The email of the user that last updated the app."""
53
+
54
+ url: Optional[str] = None
55
+ """The URL of the app once it is deployed."""
56
+
57
+ def as_dict(self) -> dict:
58
+ """Serializes the App into a dictionary suitable for use as a JSON request body."""
59
+ body = {}
60
+ if self.active_deployment: body['active_deployment'] = self.active_deployment.as_dict()
61
+ if self.create_time is not None: body['create_time'] = self.create_time
62
+ if self.creator is not None: body['creator'] = self.creator
63
+ if self.description is not None: body['description'] = self.description
64
+ if self.name is not None: body['name'] = self.name
65
+ if self.pending_deployment: body['pending_deployment'] = self.pending_deployment.as_dict()
66
+ if self.service_principal_id is not None: body['service_principal_id'] = self.service_principal_id
67
+ if self.service_principal_name is not None:
68
+ body['service_principal_name'] = self.service_principal_name
69
+ if self.status: body['status'] = self.status.as_dict()
70
+ if self.update_time is not None: body['update_time'] = self.update_time
71
+ if self.updater is not None: body['updater'] = self.updater
72
+ if self.url is not None: body['url'] = self.url
73
+ return body
74
+
75
+ @classmethod
76
+ def from_dict(cls, d: Dict[str, any]) -> App:
77
+ """Deserializes the App from a dictionary."""
78
+ return cls(active_deployment=_from_dict(d, 'active_deployment', AppDeployment),
79
+ create_time=d.get('create_time', None),
80
+ creator=d.get('creator', None),
81
+ description=d.get('description', None),
82
+ name=d.get('name', None),
83
+ pending_deployment=_from_dict(d, 'pending_deployment', AppDeployment),
84
+ service_principal_id=d.get('service_principal_id', None),
85
+ service_principal_name=d.get('service_principal_name', None),
86
+ status=_from_dict(d, 'status', AppStatus),
87
+ update_time=d.get('update_time', None),
88
+ updater=d.get('updater', None),
89
+ url=d.get('url', None))
90
+
91
+
92
+ @dataclass
93
+ class AppAccessControlRequest:
94
+ group_name: Optional[str] = None
95
+ """name of the group"""
96
+
97
+ permission_level: Optional[AppPermissionLevel] = None
98
+ """Permission level"""
99
+
100
+ service_principal_name: Optional[str] = None
101
+ """application ID of a service principal"""
102
+
103
+ user_name: Optional[str] = None
104
+ """name of the user"""
105
+
106
+ def as_dict(self) -> dict:
107
+ """Serializes the AppAccessControlRequest into a dictionary suitable for use as a JSON request body."""
108
+ body = {}
109
+ if self.group_name is not None: body['group_name'] = self.group_name
110
+ if self.permission_level is not None: body['permission_level'] = self.permission_level.value
111
+ if self.service_principal_name is not None:
112
+ body['service_principal_name'] = self.service_principal_name
113
+ if self.user_name is not None: body['user_name'] = self.user_name
114
+ return body
115
+
116
+ @classmethod
117
+ def from_dict(cls, d: Dict[str, any]) -> AppAccessControlRequest:
118
+ """Deserializes the AppAccessControlRequest from a dictionary."""
119
+ return cls(group_name=d.get('group_name', None),
120
+ permission_level=_enum(d, 'permission_level', AppPermissionLevel),
121
+ service_principal_name=d.get('service_principal_name', None),
122
+ user_name=d.get('user_name', None))
123
+
124
+
125
+ @dataclass
126
+ class AppAccessControlResponse:
127
+ all_permissions: Optional[List[AppPermission]] = None
128
+ """All permissions."""
129
+
130
+ display_name: Optional[str] = None
131
+ """Display name of the user or service principal."""
132
+
133
+ group_name: Optional[str] = None
134
+ """name of the group"""
135
+
136
+ service_principal_name: Optional[str] = None
137
+ """Name of the service principal."""
138
+
139
+ user_name: Optional[str] = None
140
+ """name of the user"""
141
+
142
+ def as_dict(self) -> dict:
143
+ """Serializes the AppAccessControlResponse into a dictionary suitable for use as a JSON request body."""
144
+ body = {}
145
+ if self.all_permissions: body['all_permissions'] = [v.as_dict() for v in self.all_permissions]
146
+ if self.display_name is not None: body['display_name'] = self.display_name
147
+ if self.group_name is not None: body['group_name'] = self.group_name
148
+ if self.service_principal_name is not None:
149
+ body['service_principal_name'] = self.service_principal_name
150
+ if self.user_name is not None: body['user_name'] = self.user_name
151
+ return body
152
+
153
+ @classmethod
154
+ def from_dict(cls, d: Dict[str, any]) -> AppAccessControlResponse:
155
+ """Deserializes the AppAccessControlResponse from a dictionary."""
156
+ return cls(all_permissions=_repeated_dict(d, 'all_permissions', AppPermission),
157
+ display_name=d.get('display_name', None),
158
+ group_name=d.get('group_name', None),
159
+ service_principal_name=d.get('service_principal_name', None),
160
+ user_name=d.get('user_name', None))
161
+
162
+
163
+ @dataclass
164
+ class AppDeployment:
165
+ source_code_path: str
166
+ """The workspace file system path of the source code used to create the app deployment. This is
167
+ different from `deployment_artifacts.source_code_path`, which is the path used by the deployed
168
+ app. The former refers to the original source code location of the app in the workspace during
169
+ deployment creation, whereas the latter provides a system generated stable snapshotted source
170
+ code path used by the deployment."""
171
+
172
+ create_time: Optional[str] = None
173
+ """The creation time of the deployment. Formatted timestamp in ISO 6801."""
174
+
175
+ creator: Optional[str] = None
176
+ """The email of the user creates the deployment."""
177
+
178
+ deployment_artifacts: Optional[AppDeploymentArtifacts] = None
179
+ """The deployment artifacts for an app."""
180
+
181
+ deployment_id: Optional[str] = None
182
+ """The unique id of the deployment."""
183
+
184
+ mode: Optional[AppDeploymentMode] = None
185
+ """The mode of which the deployment will manage the source code."""
186
+
187
+ status: Optional[AppDeploymentStatus] = None
188
+ """Status and status message of the deployment"""
189
+
190
+ update_time: Optional[str] = None
191
+ """The update time of the deployment. Formatted timestamp in ISO 6801."""
192
+
193
+ def as_dict(self) -> dict:
194
+ """Serializes the AppDeployment into a dictionary suitable for use as a JSON request body."""
195
+ body = {}
196
+ if self.create_time is not None: body['create_time'] = self.create_time
197
+ if self.creator is not None: body['creator'] = self.creator
198
+ if self.deployment_artifacts: body['deployment_artifacts'] = self.deployment_artifacts.as_dict()
199
+ if self.deployment_id is not None: body['deployment_id'] = self.deployment_id
200
+ if self.mode is not None: body['mode'] = self.mode.value
201
+ if self.source_code_path is not None: body['source_code_path'] = self.source_code_path
202
+ if self.status: body['status'] = self.status.as_dict()
203
+ if self.update_time is not None: body['update_time'] = self.update_time
204
+ return body
205
+
206
+ @classmethod
207
+ def from_dict(cls, d: Dict[str, any]) -> AppDeployment:
208
+ """Deserializes the AppDeployment from a dictionary."""
209
+ return cls(create_time=d.get('create_time', None),
210
+ creator=d.get('creator', None),
211
+ deployment_artifacts=_from_dict(d, 'deployment_artifacts', AppDeploymentArtifacts),
212
+ deployment_id=d.get('deployment_id', None),
213
+ mode=_enum(d, 'mode', AppDeploymentMode),
214
+ source_code_path=d.get('source_code_path', None),
215
+ status=_from_dict(d, 'status', AppDeploymentStatus),
216
+ update_time=d.get('update_time', None))
217
+
218
+
219
+ @dataclass
220
+ class AppDeploymentArtifacts:
221
+ source_code_path: Optional[str] = None
222
+ """The snapshotted workspace file system path of the source code loaded by the deployed app."""
223
+
224
+ def as_dict(self) -> dict:
225
+ """Serializes the AppDeploymentArtifacts into a dictionary suitable for use as a JSON request body."""
226
+ body = {}
227
+ if self.source_code_path is not None: body['source_code_path'] = self.source_code_path
228
+ return body
229
+
230
+ @classmethod
231
+ def from_dict(cls, d: Dict[str, any]) -> AppDeploymentArtifacts:
232
+ """Deserializes the AppDeploymentArtifacts from a dictionary."""
233
+ return cls(source_code_path=d.get('source_code_path', None))
234
+
235
+
236
+ class AppDeploymentMode(Enum):
237
+
238
+ AUTO_SYNC = 'AUTO_SYNC'
239
+ SNAPSHOT = 'SNAPSHOT'
240
+
241
+
242
+ class AppDeploymentState(Enum):
243
+
244
+ FAILED = 'FAILED'
245
+ IN_PROGRESS = 'IN_PROGRESS'
246
+ STOPPED = 'STOPPED'
247
+ SUCCEEDED = 'SUCCEEDED'
248
+
249
+
250
+ @dataclass
251
+ class AppDeploymentStatus:
252
+ message: Optional[str] = None
253
+ """Message corresponding with the deployment state."""
254
+
255
+ state: Optional[AppDeploymentState] = None
256
+ """State of the deployment."""
257
+
258
+ def as_dict(self) -> dict:
259
+ """Serializes the AppDeploymentStatus into a dictionary suitable for use as a JSON request body."""
260
+ body = {}
261
+ if self.message is not None: body['message'] = self.message
262
+ if self.state is not None: body['state'] = self.state.value
263
+ return body
264
+
265
+ @classmethod
266
+ def from_dict(cls, d: Dict[str, any]) -> AppDeploymentStatus:
267
+ """Deserializes the AppDeploymentStatus from a dictionary."""
268
+ return cls(message=d.get('message', None), state=_enum(d, 'state', AppDeploymentState))
269
+
270
+
271
+ @dataclass
272
+ class AppPermission:
273
+ inherited: Optional[bool] = None
274
+
275
+ inherited_from_object: Optional[List[str]] = None
276
+
277
+ permission_level: Optional[AppPermissionLevel] = None
278
+ """Permission level"""
279
+
280
+ def as_dict(self) -> dict:
281
+ """Serializes the AppPermission into a dictionary suitable for use as a JSON request body."""
282
+ body = {}
283
+ if self.inherited is not None: body['inherited'] = self.inherited
284
+ if self.inherited_from_object: body['inherited_from_object'] = [v for v in self.inherited_from_object]
285
+ if self.permission_level is not None: body['permission_level'] = self.permission_level.value
286
+ return body
287
+
288
+ @classmethod
289
+ def from_dict(cls, d: Dict[str, any]) -> AppPermission:
290
+ """Deserializes the AppPermission from a dictionary."""
291
+ return cls(inherited=d.get('inherited', None),
292
+ inherited_from_object=d.get('inherited_from_object', None),
293
+ permission_level=_enum(d, 'permission_level', AppPermissionLevel))
294
+
295
+
296
+ class AppPermissionLevel(Enum):
297
+ """Permission level"""
298
+
299
+ CAN_MANAGE = 'CAN_MANAGE'
300
+ CAN_USE = 'CAN_USE'
301
+
302
+
303
+ @dataclass
304
+ class AppPermissions:
305
+ access_control_list: Optional[List[AppAccessControlResponse]] = None
306
+
307
+ object_id: Optional[str] = None
308
+
309
+ object_type: Optional[str] = None
310
+
311
+ def as_dict(self) -> dict:
312
+ """Serializes the AppPermissions into a dictionary suitable for use as a JSON request body."""
313
+ body = {}
314
+ if self.access_control_list:
315
+ body['access_control_list'] = [v.as_dict() for v in self.access_control_list]
316
+ if self.object_id is not None: body['object_id'] = self.object_id
317
+ if self.object_type is not None: body['object_type'] = self.object_type
318
+ return body
319
+
320
+ @classmethod
321
+ def from_dict(cls, d: Dict[str, any]) -> AppPermissions:
322
+ """Deserializes the AppPermissions from a dictionary."""
323
+ return cls(access_control_list=_repeated_dict(d, 'access_control_list', AppAccessControlResponse),
324
+ object_id=d.get('object_id', None),
325
+ object_type=d.get('object_type', None))
326
+
327
+
328
+ @dataclass
329
+ class AppPermissionsDescription:
330
+ description: Optional[str] = None
331
+
332
+ permission_level: Optional[AppPermissionLevel] = None
333
+ """Permission level"""
334
+
335
+ def as_dict(self) -> dict:
336
+ """Serializes the AppPermissionsDescription into a dictionary suitable for use as a JSON request body."""
337
+ body = {}
338
+ if self.description is not None: body['description'] = self.description
339
+ if self.permission_level is not None: body['permission_level'] = self.permission_level.value
340
+ return body
341
+
342
+ @classmethod
343
+ def from_dict(cls, d: Dict[str, any]) -> AppPermissionsDescription:
344
+ """Deserializes the AppPermissionsDescription from a dictionary."""
345
+ return cls(description=d.get('description', None),
346
+ permission_level=_enum(d, 'permission_level', AppPermissionLevel))
347
+
348
+
349
+ @dataclass
350
+ class AppPermissionsRequest:
351
+ access_control_list: Optional[List[AppAccessControlRequest]] = None
352
+
353
+ app_name: Optional[str] = None
354
+ """The app for which to get or manage permissions."""
355
+
356
+ def as_dict(self) -> dict:
357
+ """Serializes the AppPermissionsRequest into a dictionary suitable for use as a JSON request body."""
358
+ body = {}
359
+ if self.access_control_list:
360
+ body['access_control_list'] = [v.as_dict() for v in self.access_control_list]
361
+ if self.app_name is not None: body['app_name'] = self.app_name
362
+ return body
363
+
364
+ @classmethod
365
+ def from_dict(cls, d: Dict[str, any]) -> AppPermissionsRequest:
366
+ """Deserializes the AppPermissionsRequest from a dictionary."""
367
+ return cls(access_control_list=_repeated_dict(d, 'access_control_list', AppAccessControlRequest),
368
+ app_name=d.get('app_name', None))
369
+
370
+
371
+ class AppState(Enum):
372
+
373
+ CREATING = 'CREATING'
374
+ DELETED = 'DELETED'
375
+ DELETING = 'DELETING'
376
+ ERROR = 'ERROR'
377
+ IDLE = 'IDLE'
378
+ RUNNING = 'RUNNING'
379
+ STARTING = 'STARTING'
380
+
381
+
382
+ @dataclass
383
+ class AppStatus:
384
+ message: Optional[str] = None
385
+ """Message corresponding with the app state."""
386
+
387
+ state: Optional[AppState] = None
388
+ """State of the app."""
389
+
390
+ def as_dict(self) -> dict:
391
+ """Serializes the AppStatus into a dictionary suitable for use as a JSON request body."""
392
+ body = {}
393
+ if self.message is not None: body['message'] = self.message
394
+ if self.state is not None: body['state'] = self.state.value
395
+ return body
396
+
397
+ @classmethod
398
+ def from_dict(cls, d: Dict[str, any]) -> AppStatus:
399
+ """Deserializes the AppStatus from a dictionary."""
400
+ return cls(message=d.get('message', None), state=_enum(d, 'state', AppState))
401
+
402
+
403
+ @dataclass
404
+ class CreateAppDeploymentRequest:
405
+ source_code_path: str
406
+ """The workspace file system path of the source code used to create the app deployment. This is
407
+ different from `deployment_artifacts.source_code_path`, which is the path used by the deployed
408
+ app. The former refers to the original source code location of the app in the workspace during
409
+ deployment creation, whereas the latter provides a system generated stable snapshotted source
410
+ code path used by the deployment."""
411
+
412
+ app_name: Optional[str] = None
413
+ """The name of the app."""
414
+
415
+ mode: Optional[AppDeploymentMode] = None
416
+ """The mode of which the deployment will manage the source code."""
417
+
418
+ def as_dict(self) -> dict:
419
+ """Serializes the CreateAppDeploymentRequest into a dictionary suitable for use as a JSON request body."""
420
+ body = {}
421
+ if self.app_name is not None: body['app_name'] = self.app_name
422
+ if self.mode is not None: body['mode'] = self.mode.value
423
+ if self.source_code_path is not None: body['source_code_path'] = self.source_code_path
424
+ return body
425
+
426
+ @classmethod
427
+ def from_dict(cls, d: Dict[str, any]) -> CreateAppDeploymentRequest:
428
+ """Deserializes the CreateAppDeploymentRequest from a dictionary."""
429
+ return cls(app_name=d.get('app_name', None),
430
+ mode=_enum(d, 'mode', AppDeploymentMode),
431
+ source_code_path=d.get('source_code_path', None))
432
+
433
+
434
+ @dataclass
435
+ class CreateAppRequest:
436
+ name: str
437
+ """The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.
438
+ It must be unique within the workspace."""
439
+
440
+ description: Optional[str] = None
441
+ """The description of the app."""
442
+
443
+ def as_dict(self) -> dict:
444
+ """Serializes the CreateAppRequest into a dictionary suitable for use as a JSON request body."""
445
+ body = {}
446
+ if self.description is not None: body['description'] = self.description
447
+ if self.name is not None: body['name'] = self.name
448
+ return body
449
+
450
+ @classmethod
451
+ def from_dict(cls, d: Dict[str, any]) -> CreateAppRequest:
452
+ """Deserializes the CreateAppRequest from a dictionary."""
453
+ return cls(description=d.get('description', None), name=d.get('name', None))
454
+
455
+
456
+ @dataclass
457
+ class DeleteResponse:
458
+
459
+ def as_dict(self) -> dict:
460
+ """Serializes the DeleteResponse into a dictionary suitable for use as a JSON request body."""
461
+ body = {}
462
+ return body
463
+
464
+ @classmethod
465
+ def from_dict(cls, d: Dict[str, any]) -> DeleteResponse:
466
+ """Deserializes the DeleteResponse from a dictionary."""
467
+ return cls()
468
+
469
+
470
+ @dataclass
471
+ class GetAppPermissionLevelsResponse:
472
+ permission_levels: Optional[List[AppPermissionsDescription]] = None
473
+ """Specific permission levels"""
474
+
475
+ def as_dict(self) -> dict:
476
+ """Serializes the GetAppPermissionLevelsResponse into a dictionary suitable for use as a JSON request body."""
477
+ body = {}
478
+ if self.permission_levels: body['permission_levels'] = [v.as_dict() for v in self.permission_levels]
479
+ return body
480
+
481
+ @classmethod
482
+ def from_dict(cls, d: Dict[str, any]) -> GetAppPermissionLevelsResponse:
483
+ """Deserializes the GetAppPermissionLevelsResponse from a dictionary."""
484
+ return cls(permission_levels=_repeated_dict(d, 'permission_levels', AppPermissionsDescription))
485
+
486
+
487
+ @dataclass
488
+ class ListAppDeploymentsResponse:
489
+ app_deployments: Optional[List[AppDeployment]] = None
490
+ """Deployment history of the app."""
491
+
492
+ next_page_token: Optional[str] = None
493
+ """Pagination token to request the next page of apps."""
494
+
495
+ def as_dict(self) -> dict:
496
+ """Serializes the ListAppDeploymentsResponse into a dictionary suitable for use as a JSON request body."""
497
+ body = {}
498
+ if self.app_deployments: body['app_deployments'] = [v.as_dict() for v in self.app_deployments]
499
+ if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
500
+ return body
501
+
502
+ @classmethod
503
+ def from_dict(cls, d: Dict[str, any]) -> ListAppDeploymentsResponse:
504
+ """Deserializes the ListAppDeploymentsResponse from a dictionary."""
505
+ return cls(app_deployments=_repeated_dict(d, 'app_deployments', AppDeployment),
506
+ next_page_token=d.get('next_page_token', None))
507
+
508
+
509
+ @dataclass
510
+ class ListAppsResponse:
511
+ apps: Optional[List[App]] = None
512
+
513
+ next_page_token: Optional[str] = None
514
+ """Pagination token to request the next page of apps."""
515
+
516
+ def as_dict(self) -> dict:
517
+ """Serializes the ListAppsResponse into a dictionary suitable for use as a JSON request body."""
518
+ body = {}
519
+ if self.apps: body['apps'] = [v.as_dict() for v in self.apps]
520
+ if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
521
+ return body
522
+
523
+ @classmethod
524
+ def from_dict(cls, d: Dict[str, any]) -> ListAppsResponse:
525
+ """Deserializes the ListAppsResponse from a dictionary."""
526
+ return cls(apps=_repeated_dict(d, 'apps', App), next_page_token=d.get('next_page_token', None))
527
+
528
+
529
+ @dataclass
530
+ class StartAppRequest:
531
+ name: Optional[str] = None
532
+ """The name of the app."""
533
+
534
+
535
+ @dataclass
536
+ class StopAppRequest:
537
+ name: Optional[str] = None
538
+ """The name of the app."""
539
+
540
+
541
+ @dataclass
542
+ class StopAppResponse:
543
+
544
+ def as_dict(self) -> dict:
545
+ """Serializes the StopAppResponse into a dictionary suitable for use as a JSON request body."""
546
+ body = {}
547
+ return body
548
+
549
+ @classmethod
550
+ def from_dict(cls, d: Dict[str, any]) -> StopAppResponse:
551
+ """Deserializes the StopAppResponse from a dictionary."""
552
+ return cls()
553
+
554
+
555
+ @dataclass
556
+ class UpdateAppRequest:
557
+ name: str
558
+ """The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.
559
+ It must be unique within the workspace."""
560
+
561
+ description: Optional[str] = None
562
+ """The description of the app."""
563
+
564
+ def as_dict(self) -> dict:
565
+ """Serializes the UpdateAppRequest into a dictionary suitable for use as a JSON request body."""
566
+ body = {}
567
+ if self.description is not None: body['description'] = self.description
568
+ if self.name is not None: body['name'] = self.name
569
+ return body
570
+
571
+ @classmethod
572
+ def from_dict(cls, d: Dict[str, any]) -> UpdateAppRequest:
573
+ """Deserializes the UpdateAppRequest from a dictionary."""
574
+ return cls(description=d.get('description', None), name=d.get('name', None))
575
+
576
+
577
+ class AppsAPI:
578
+ """Apps run directly on a customer’s Databricks instance, integrate with their data, use and extend
579
+ Databricks services, and enable users to interact through single sign-on."""
580
+
581
+ def __init__(self, api_client):
582
+ self._api = api_client
583
+
584
+ def wait_get_app_idle(self,
585
+ name: str,
586
+ timeout=timedelta(minutes=20),
587
+ callback: Optional[Callable[[App], None]] = None) -> App:
588
+ deadline = time.time() + timeout.total_seconds()
589
+ target_states = (AppState.IDLE, )
590
+ failure_states = (AppState.ERROR, )
591
+ status_message = 'polling...'
592
+ attempt = 1
593
+ while time.time() < deadline:
594
+ poll = self.get(name=name)
595
+ status = poll.status.state
596
+ status_message = f'current status: {status}'
597
+ if poll.status:
598
+ status_message = poll.status.message
599
+ if status in target_states:
600
+ return poll
601
+ if callback:
602
+ callback(poll)
603
+ if status in failure_states:
604
+ msg = f'failed to reach IDLE, got {status}: {status_message}'
605
+ raise OperationFailed(msg)
606
+ prefix = f"name={name}"
607
+ sleep = attempt
608
+ if sleep > 10:
609
+ # sleep 10s max per attempt
610
+ sleep = 10
611
+ _LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
612
+ time.sleep(sleep + random.random())
613
+ attempt += 1
614
+ raise TimeoutError(f'timed out after {timeout}: {status_message}')
615
+
616
+ def wait_get_deployment_app_succeeded(
617
+ self,
618
+ app_name: str,
619
+ deployment_id: str,
620
+ timeout=timedelta(minutes=20),
621
+ callback: Optional[Callable[[AppDeployment], None]] = None) -> AppDeployment:
622
+ deadline = time.time() + timeout.total_seconds()
623
+ target_states = (AppDeploymentState.SUCCEEDED, )
624
+ failure_states = (AppDeploymentState.FAILED, )
625
+ status_message = 'polling...'
626
+ attempt = 1
627
+ while time.time() < deadline:
628
+ poll = self.get_deployment(app_name=app_name, deployment_id=deployment_id)
629
+ status = poll.status.state
630
+ status_message = f'current status: {status}'
631
+ if poll.status:
632
+ status_message = poll.status.message
633
+ if status in target_states:
634
+ return poll
635
+ if callback:
636
+ callback(poll)
637
+ if status in failure_states:
638
+ msg = f'failed to reach SUCCEEDED, got {status}: {status_message}'
639
+ raise OperationFailed(msg)
640
+ prefix = f"app_name={app_name}, deployment_id={deployment_id}"
641
+ sleep = attempt
642
+ if sleep > 10:
643
+ # sleep 10s max per attempt
644
+ sleep = 10
645
+ _LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
646
+ time.sleep(sleep + random.random())
647
+ attempt += 1
648
+ raise TimeoutError(f'timed out after {timeout}: {status_message}')
649
+
650
+ def create(self, name: str, *, description: Optional[str] = None) -> Wait[App]:
651
+ """Create an app.
652
+
653
+ Creates a new app.
654
+
655
+ :param name: str
656
+ The name of the app. The name must contain only lowercase alphanumeric characters and hyphens. It
657
+ must be unique within the workspace.
658
+ :param description: str (optional)
659
+ The description of the app.
660
+
661
+ :returns:
662
+ Long-running operation waiter for :class:`App`.
663
+ See :method:wait_get_app_idle for more details.
664
+ """
665
+ body = {}
666
+ if description is not None: body['description'] = description
667
+ if name is not None: body['name'] = name
668
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
669
+
670
+ op_response = self._api.do('POST', '/api/2.0/preview/apps', body=body, headers=headers)
671
+ return Wait(self.wait_get_app_idle, response=App.from_dict(op_response), name=op_response['name'])
672
+
673
+ def create_and_wait(self,
674
+ name: str,
675
+ *,
676
+ description: Optional[str] = None,
677
+ timeout=timedelta(minutes=20)) -> App:
678
+ return self.create(description=description, name=name).result(timeout=timeout)
679
+
680
+ def delete(self, name: str):
681
+ """Delete an app.
682
+
683
+ Deletes an app.
684
+
685
+ :param name: str
686
+ The name of the app.
687
+
688
+
689
+ """
690
+
691
+ headers = {'Accept': 'application/json', }
692
+
693
+ self._api.do('DELETE', f'/api/2.0/preview/apps/{name}', headers=headers)
694
+
695
+ def deploy(self,
696
+ app_name: str,
697
+ source_code_path: str,
698
+ *,
699
+ mode: Optional[AppDeploymentMode] = None) -> Wait[AppDeployment]:
700
+ """Create an app deployment.
701
+
702
+ Creates an app deployment for the app with the supplied name.
703
+
704
+ :param app_name: str
705
+ The name of the app.
706
+ :param source_code_path: str
707
+ The workspace file system path of the source code used to create the app deployment. This is
708
+ different from `deployment_artifacts.source_code_path`, which is the path used by the deployed app.
709
+ The former refers to the original source code location of the app in the workspace during deployment
710
+ creation, whereas the latter provides a system generated stable snapshotted source code path used by
711
+ the deployment.
712
+ :param mode: :class:`AppDeploymentMode` (optional)
713
+ The mode of which the deployment will manage the source code.
714
+
715
+ :returns:
716
+ Long-running operation waiter for :class:`AppDeployment`.
717
+ See :method:wait_get_deployment_app_succeeded for more details.
718
+ """
719
+ body = {}
720
+ if mode is not None: body['mode'] = mode.value
721
+ if source_code_path is not None: body['source_code_path'] = source_code_path
722
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
723
+
724
+ op_response = self._api.do('POST',
725
+ f'/api/2.0/preview/apps/{app_name}/deployments',
726
+ body=body,
727
+ headers=headers)
728
+ return Wait(self.wait_get_deployment_app_succeeded,
729
+ response=AppDeployment.from_dict(op_response),
730
+ app_name=app_name,
731
+ deployment_id=op_response['deployment_id'])
732
+
733
+ def deploy_and_wait(
734
+ self,
735
+ app_name: str,
736
+ source_code_path: str,
737
+ *,
738
+ mode: Optional[AppDeploymentMode] = None,
739
+ timeout=timedelta(minutes=20)) -> AppDeployment:
740
+ return self.deploy(app_name=app_name, mode=mode,
741
+ source_code_path=source_code_path).result(timeout=timeout)
742
+
743
+ def get(self, name: str) -> App:
744
+ """Get an app.
745
+
746
+ Retrieves information for the app with the supplied name.
747
+
748
+ :param name: str
749
+ The name of the app.
750
+
751
+ :returns: :class:`App`
752
+ """
753
+
754
+ headers = {'Accept': 'application/json', }
755
+
756
+ res = self._api.do('GET', f'/api/2.0/preview/apps/{name}', headers=headers)
757
+ return App.from_dict(res)
758
+
759
+ def get_deployment(self, app_name: str, deployment_id: str) -> AppDeployment:
760
+ """Get an app deployment.
761
+
762
+ Retrieves information for the app deployment with the supplied name and deployment id.
763
+
764
+ :param app_name: str
765
+ The name of the app.
766
+ :param deployment_id: str
767
+ The unique id of the deployment.
768
+
769
+ :returns: :class:`AppDeployment`
770
+ """
771
+
772
+ headers = {'Accept': 'application/json', }
773
+
774
+ res = self._api.do('GET',
775
+ f'/api/2.0/preview/apps/{app_name}/deployments/{deployment_id}',
776
+ headers=headers)
777
+ return AppDeployment.from_dict(res)
778
+
779
+ def get_permission_levels(self, app_name: str) -> GetAppPermissionLevelsResponse:
780
+ """Get app permission levels.
781
+
782
+ Gets the permission levels that a user can have on an object.
783
+
784
+ :param app_name: str
785
+ The app for which to get or manage permissions.
786
+
787
+ :returns: :class:`GetAppPermissionLevelsResponse`
788
+ """
789
+
790
+ headers = {'Accept': 'application/json', }
791
+
792
+ res = self._api.do('GET', f'/api/2.0/permissions/apps/{app_name}/permissionLevels', headers=headers)
793
+ return GetAppPermissionLevelsResponse.from_dict(res)
794
+
795
+ def get_permissions(self, app_name: str) -> AppPermissions:
796
+ """Get app permissions.
797
+
798
+ Gets the permissions of an app. Apps can inherit permissions from their root object.
799
+
800
+ :param app_name: str
801
+ The app for which to get or manage permissions.
802
+
803
+ :returns: :class:`AppPermissions`
804
+ """
805
+
806
+ headers = {'Accept': 'application/json', }
807
+
808
+ res = self._api.do('GET', f'/api/2.0/permissions/apps/{app_name}', headers=headers)
809
+ return AppPermissions.from_dict(res)
810
+
811
+ def list(self, *, page_size: Optional[int] = None, page_token: Optional[str] = None) -> Iterator[App]:
812
+ """List apps.
813
+
814
+ Lists all apps in the workspace.
815
+
816
+ :param page_size: int (optional)
817
+ Upper bound for items returned.
818
+ :param page_token: str (optional)
819
+ Pagination token to go to the next page of apps. Requests first page if absent.
820
+
821
+ :returns: Iterator over :class:`App`
822
+ """
823
+
824
+ query = {}
825
+ if page_size is not None: query['page_size'] = page_size
826
+ if page_token is not None: query['page_token'] = page_token
827
+ headers = {'Accept': 'application/json', }
828
+
829
+ while True:
830
+ json = self._api.do('GET', '/api/2.0/preview/apps', query=query, headers=headers)
831
+ if 'apps' in json:
832
+ for v in json['apps']:
833
+ yield App.from_dict(v)
834
+ if 'next_page_token' not in json or not json['next_page_token']:
835
+ return
836
+ query['page_token'] = json['next_page_token']
837
+
838
+ def list_deployments(self,
839
+ app_name: str,
840
+ *,
841
+ page_size: Optional[int] = None,
842
+ page_token: Optional[str] = None) -> Iterator[AppDeployment]:
843
+ """List app deployments.
844
+
845
+ Lists all app deployments for the app with the supplied name.
846
+
847
+ :param app_name: str
848
+ The name of the app.
849
+ :param page_size: int (optional)
850
+ Upper bound for items returned.
851
+ :param page_token: str (optional)
852
+ Pagination token to go to the next page of apps. Requests first page if absent.
853
+
854
+ :returns: Iterator over :class:`AppDeployment`
855
+ """
856
+
857
+ query = {}
858
+ if page_size is not None: query['page_size'] = page_size
859
+ if page_token is not None: query['page_token'] = page_token
860
+ headers = {'Accept': 'application/json', }
861
+
862
+ while True:
863
+ json = self._api.do('GET',
864
+ f'/api/2.0/preview/apps/{app_name}/deployments',
865
+ query=query,
866
+ headers=headers)
867
+ if 'app_deployments' in json:
868
+ for v in json['app_deployments']:
869
+ yield AppDeployment.from_dict(v)
870
+ if 'next_page_token' not in json or not json['next_page_token']:
871
+ return
872
+ query['page_token'] = json['next_page_token']
873
+
874
+ def set_permissions(
875
+ self,
876
+ app_name: str,
877
+ *,
878
+ access_control_list: Optional[List[AppAccessControlRequest]] = None) -> AppPermissions:
879
+ """Set app permissions.
880
+
881
+ Sets permissions on an app. Apps can inherit permissions from their root object.
882
+
883
+ :param app_name: str
884
+ The app for which to get or manage permissions.
885
+ :param access_control_list: List[:class:`AppAccessControlRequest`] (optional)
886
+
887
+ :returns: :class:`AppPermissions`
888
+ """
889
+ body = {}
890
+ if access_control_list is not None:
891
+ body['access_control_list'] = [v.as_dict() for v in access_control_list]
892
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
893
+
894
+ res = self._api.do('PUT', f'/api/2.0/permissions/apps/{app_name}', body=body, headers=headers)
895
+ return AppPermissions.from_dict(res)
896
+
897
+ def start(self, name: str) -> Wait[AppDeployment]:
898
+ """Start an app.
899
+
900
+ Start the last active deployment of the app in the workspace.
901
+
902
+ :param name: str
903
+ The name of the app.
904
+
905
+ :returns:
906
+ Long-running operation waiter for :class:`AppDeployment`.
907
+ See :method:wait_get_deployment_app_succeeded for more details.
908
+ """
909
+
910
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
911
+
912
+ op_response = self._api.do('POST', f'/api/2.0/preview/apps/{name}/start', headers=headers)
913
+ return Wait(self.wait_get_deployment_app_succeeded,
914
+ response=AppDeployment.from_dict(op_response),
915
+ app_name=name,
916
+ deployment_id=op_response['deployment_id'])
917
+
918
+ def start_and_wait(self, name: str, timeout=timedelta(minutes=20)) -> AppDeployment:
919
+ return self.start(name=name).result(timeout=timeout)
920
+
921
+ def stop(self, name: str):
922
+ """Stop an app.
923
+
924
+ Stops the active deployment of the app in the workspace.
925
+
926
+ :param name: str
927
+ The name of the app.
928
+
929
+
930
+ """
931
+
932
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
933
+
934
+ self._api.do('POST', f'/api/2.0/preview/apps/{name}/stop', headers=headers)
935
+
936
+ def update(self, name: str, *, description: Optional[str] = None) -> App:
937
+ """Update an app.
938
+
939
+ Updates the app with the supplied name.
940
+
941
+ :param name: str
942
+ The name of the app. The name must contain only lowercase alphanumeric characters and hyphens. It
943
+ must be unique within the workspace.
944
+ :param description: str (optional)
945
+ The description of the app.
946
+
947
+ :returns: :class:`App`
948
+ """
949
+ body = {}
950
+ if description is not None: body['description'] = description
951
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
952
+
953
+ res = self._api.do('PATCH', f'/api/2.0/preview/apps/{name}', body=body, headers=headers)
954
+ return App.from_dict(res)
955
+
956
+ def update_permissions(
957
+ self,
958
+ app_name: str,
959
+ *,
960
+ access_control_list: Optional[List[AppAccessControlRequest]] = None) -> AppPermissions:
961
+ """Update app permissions.
962
+
963
+ Updates the permissions on an app. Apps can inherit permissions from their root object.
964
+
965
+ :param app_name: str
966
+ The app for which to get or manage permissions.
967
+ :param access_control_list: List[:class:`AppAccessControlRequest`] (optional)
968
+
969
+ :returns: :class:`AppPermissions`
970
+ """
971
+ body = {}
972
+ if access_control_list is not None:
973
+ body['access_control_list'] = [v.as_dict() for v in access_control_list]
974
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
975
+
976
+ res = self._api.do('PATCH', f'/api/2.0/permissions/apps/{app_name}', body=body, headers=headers)
977
+ return AppPermissions.from_dict(res)