databricks-sdk 0.59.0__py3-none-any.whl → 0.61.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.
- databricks/sdk/__init__.py +20 -6
- databricks/sdk/credentials_provider.py +2 -2
- databricks/sdk/mixins/files.py +43 -15
- databricks/sdk/mixins/open_ai_client.py +28 -7
- databricks/sdk/oidc.py +6 -2
- databricks/sdk/service/{aibuilder.py → agentbricks.py} +5 -5
- databricks/sdk/service/catalog.py +167 -130
- databricks/sdk/service/cleanrooms.py +524 -30
- databricks/sdk/service/dashboards.py +1 -0
- databricks/sdk/service/database.py +61 -7
- databricks/sdk/service/pipelines.py +2 -0
- databricks/sdk/service/serving.py +1 -0
- databricks/sdk/service/settings.py +1 -0
- databricks/sdk/service/sharing.py +67 -1
- databricks/sdk/service/sql.py +9 -0
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.59.0.dist-info → databricks_sdk-0.61.0.dist-info}/METADATA +1 -1
- {databricks_sdk-0.59.0.dist-info → databricks_sdk-0.61.0.dist-info}/RECORD +22 -22
- {databricks_sdk-0.59.0.dist-info → databricks_sdk-0.61.0.dist-info}/WHEEL +0 -0
- {databricks_sdk-0.59.0.dist-info → databricks_sdk-0.61.0.dist-info}/licenses/LICENSE +0 -0
- {databricks_sdk-0.59.0.dist-info → databricks_sdk-0.61.0.dist-info}/licenses/NOTICE +0 -0
- {databricks_sdk-0.59.0.dist-info → databricks_sdk-0.61.0.dist-info}/top_level.txt +0 -0
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
+
import random
|
|
7
|
+
import time
|
|
6
8
|
from dataclasses import dataclass
|
|
9
|
+
from datetime import timedelta
|
|
7
10
|
from enum import Enum
|
|
8
|
-
from typing import Any, Dict, Iterator, List, Optional
|
|
11
|
+
from typing import Any, Callable, Dict, Iterator, List, Optional
|
|
9
12
|
|
|
10
|
-
from ._internal import _enum, _from_dict, _repeated_dict
|
|
13
|
+
from ._internal import Wait, _enum, _from_dict, _repeated_dict
|
|
11
14
|
|
|
12
15
|
_LOG = logging.getLogger("databricks.sdk")
|
|
13
16
|
|
|
@@ -132,15 +135,24 @@ class CleanRoomAccessRestricted(Enum):
|
|
|
132
135
|
class CleanRoomAsset:
|
|
133
136
|
"""Metadata of the clean room asset"""
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
"""
|
|
138
|
+
name: str
|
|
139
|
+
"""A fully qualified name that uniquely identifies the asset within the clean room. This is also
|
|
140
|
+
the name displayed in the clean room UI.
|
|
141
|
+
|
|
142
|
+
For UC securable assets (tables, volumes, etc.), the format is
|
|
143
|
+
*shared_catalog*.*shared_schema*.*asset_name*
|
|
144
|
+
|
|
145
|
+
For notebooks, the name is the notebook file name."""
|
|
137
146
|
|
|
138
|
-
asset_type:
|
|
147
|
+
asset_type: CleanRoomAssetAssetType
|
|
139
148
|
"""The type of the asset."""
|
|
140
149
|
|
|
150
|
+
added_at: Optional[int] = None
|
|
151
|
+
"""When the asset is added to the clean room, in epoch milliseconds."""
|
|
152
|
+
|
|
141
153
|
clean_room_name: Optional[str] = None
|
|
142
|
-
"""The name of the clean room this asset belongs to. This is
|
|
143
|
-
|
|
154
|
+
"""The name of the clean room this asset belongs to. This field is required for create operations
|
|
155
|
+
and populated by the server for responses."""
|
|
144
156
|
|
|
145
157
|
foreign_table: Optional[CleanRoomAssetForeignTable] = None
|
|
146
158
|
"""Foreign table details available to all collaborators of the clean room. Present if and only if
|
|
@@ -150,15 +162,6 @@ class CleanRoomAsset:
|
|
|
150
162
|
"""Local details for a foreign that are only available to its owner. Present if and only if
|
|
151
163
|
**asset_type** is **FOREIGN_TABLE**"""
|
|
152
164
|
|
|
153
|
-
name: Optional[str] = None
|
|
154
|
-
"""A fully qualified name that uniquely identifies the asset within the clean room. This is also
|
|
155
|
-
the name displayed in the clean room UI.
|
|
156
|
-
|
|
157
|
-
For UC securable assets (tables, volumes, etc.), the format is
|
|
158
|
-
*shared_catalog*.*shared_schema*.*asset_name*
|
|
159
|
-
|
|
160
|
-
For notebooks, the name is the notebook file name."""
|
|
161
|
-
|
|
162
165
|
notebook: Optional[CleanRoomAssetNotebook] = None
|
|
163
166
|
"""Notebook details available to all collaborators of the clean room. Present if and only if
|
|
164
167
|
**asset_type** is **NOTEBOOK_FILE**"""
|
|
@@ -314,7 +317,7 @@ class CleanRoomAssetForeignTable:
|
|
|
314
317
|
|
|
315
318
|
@dataclass
|
|
316
319
|
class CleanRoomAssetForeignTableLocalDetails:
|
|
317
|
-
local_name:
|
|
320
|
+
local_name: str
|
|
318
321
|
"""The fully qualified name of the foreign table in its owner's local metastore, in the format of
|
|
319
322
|
*catalog*.*schema*.*foreign_table_name*"""
|
|
320
323
|
|
|
@@ -340,13 +343,13 @@ class CleanRoomAssetForeignTableLocalDetails:
|
|
|
340
343
|
|
|
341
344
|
@dataclass
|
|
342
345
|
class CleanRoomAssetNotebook:
|
|
343
|
-
|
|
344
|
-
"""Server generated etag that represents the notebook version."""
|
|
345
|
-
|
|
346
|
-
notebook_content: Optional[str] = None
|
|
346
|
+
notebook_content: str
|
|
347
347
|
"""Base 64 representation of the notebook contents. This is the same format as returned by
|
|
348
348
|
:method:workspace/export with the format of **HTML**."""
|
|
349
349
|
|
|
350
|
+
etag: Optional[str] = None
|
|
351
|
+
"""Server generated etag that represents the notebook version."""
|
|
352
|
+
|
|
350
353
|
review_state: Optional[CleanRoomNotebookReviewNotebookReviewState] = None
|
|
351
354
|
"""top-level status derived from all reviews"""
|
|
352
355
|
|
|
@@ -432,7 +435,7 @@ class CleanRoomAssetTable:
|
|
|
432
435
|
|
|
433
436
|
@dataclass
|
|
434
437
|
class CleanRoomAssetTableLocalDetails:
|
|
435
|
-
local_name:
|
|
438
|
+
local_name: str
|
|
436
439
|
"""The fully qualified name of the table in its owner's local metastore, in the format of
|
|
437
440
|
*catalog*.*schema*.*table_name*"""
|
|
438
441
|
|
|
@@ -490,7 +493,7 @@ class CleanRoomAssetView:
|
|
|
490
493
|
|
|
491
494
|
@dataclass
|
|
492
495
|
class CleanRoomAssetViewLocalDetails:
|
|
493
|
-
local_name:
|
|
496
|
+
local_name: str
|
|
494
497
|
"""The fully qualified name of the view in its owner's local metastore, in the format of
|
|
495
498
|
*catalog*.*schema*.*view_name*"""
|
|
496
499
|
|
|
@@ -516,7 +519,7 @@ class CleanRoomAssetViewLocalDetails:
|
|
|
516
519
|
|
|
517
520
|
@dataclass
|
|
518
521
|
class CleanRoomAssetVolumeLocalDetails:
|
|
519
|
-
local_name:
|
|
522
|
+
local_name: str
|
|
520
523
|
"""The fully qualified name of the volume in its owner's local metastore, in the format of
|
|
521
524
|
*catalog*.*schema*.*volume_name*"""
|
|
522
525
|
|
|
@@ -540,6 +543,83 @@ class CleanRoomAssetVolumeLocalDetails:
|
|
|
540
543
|
return cls(local_name=d.get("local_name", None))
|
|
541
544
|
|
|
542
545
|
|
|
546
|
+
@dataclass
|
|
547
|
+
class CleanRoomAutoApprovalRule:
|
|
548
|
+
author_collaborator_alias: Optional[str] = None
|
|
549
|
+
|
|
550
|
+
author_scope: Optional[CleanRoomAutoApprovalRuleAuthorScope] = None
|
|
551
|
+
|
|
552
|
+
clean_room_name: Optional[str] = None
|
|
553
|
+
"""The name of the clean room this auto-approval rule belongs to."""
|
|
554
|
+
|
|
555
|
+
created_at: Optional[int] = None
|
|
556
|
+
"""Timestamp of when the rule was created, in epoch milliseconds."""
|
|
557
|
+
|
|
558
|
+
rule_id: Optional[str] = None
|
|
559
|
+
"""A generated UUID identifying the rule."""
|
|
560
|
+
|
|
561
|
+
rule_owner_collaborator_alias: Optional[str] = None
|
|
562
|
+
"""The owner of the rule to whom the rule applies."""
|
|
563
|
+
|
|
564
|
+
runner_collaborator_alias: Optional[str] = None
|
|
565
|
+
|
|
566
|
+
def as_dict(self) -> dict:
|
|
567
|
+
"""Serializes the CleanRoomAutoApprovalRule into a dictionary suitable for use as a JSON request body."""
|
|
568
|
+
body = {}
|
|
569
|
+
if self.author_collaborator_alias is not None:
|
|
570
|
+
body["author_collaborator_alias"] = self.author_collaborator_alias
|
|
571
|
+
if self.author_scope is not None:
|
|
572
|
+
body["author_scope"] = self.author_scope.value
|
|
573
|
+
if self.clean_room_name is not None:
|
|
574
|
+
body["clean_room_name"] = self.clean_room_name
|
|
575
|
+
if self.created_at is not None:
|
|
576
|
+
body["created_at"] = self.created_at
|
|
577
|
+
if self.rule_id is not None:
|
|
578
|
+
body["rule_id"] = self.rule_id
|
|
579
|
+
if self.rule_owner_collaborator_alias is not None:
|
|
580
|
+
body["rule_owner_collaborator_alias"] = self.rule_owner_collaborator_alias
|
|
581
|
+
if self.runner_collaborator_alias is not None:
|
|
582
|
+
body["runner_collaborator_alias"] = self.runner_collaborator_alias
|
|
583
|
+
return body
|
|
584
|
+
|
|
585
|
+
def as_shallow_dict(self) -> dict:
|
|
586
|
+
"""Serializes the CleanRoomAutoApprovalRule into a shallow dictionary of its immediate attributes."""
|
|
587
|
+
body = {}
|
|
588
|
+
if self.author_collaborator_alias is not None:
|
|
589
|
+
body["author_collaborator_alias"] = self.author_collaborator_alias
|
|
590
|
+
if self.author_scope is not None:
|
|
591
|
+
body["author_scope"] = self.author_scope
|
|
592
|
+
if self.clean_room_name is not None:
|
|
593
|
+
body["clean_room_name"] = self.clean_room_name
|
|
594
|
+
if self.created_at is not None:
|
|
595
|
+
body["created_at"] = self.created_at
|
|
596
|
+
if self.rule_id is not None:
|
|
597
|
+
body["rule_id"] = self.rule_id
|
|
598
|
+
if self.rule_owner_collaborator_alias is not None:
|
|
599
|
+
body["rule_owner_collaborator_alias"] = self.rule_owner_collaborator_alias
|
|
600
|
+
if self.runner_collaborator_alias is not None:
|
|
601
|
+
body["runner_collaborator_alias"] = self.runner_collaborator_alias
|
|
602
|
+
return body
|
|
603
|
+
|
|
604
|
+
@classmethod
|
|
605
|
+
def from_dict(cls, d: Dict[str, Any]) -> CleanRoomAutoApprovalRule:
|
|
606
|
+
"""Deserializes the CleanRoomAutoApprovalRule from a dictionary."""
|
|
607
|
+
return cls(
|
|
608
|
+
author_collaborator_alias=d.get("author_collaborator_alias", None),
|
|
609
|
+
author_scope=_enum(d, "author_scope", CleanRoomAutoApprovalRuleAuthorScope),
|
|
610
|
+
clean_room_name=d.get("clean_room_name", None),
|
|
611
|
+
created_at=d.get("created_at", None),
|
|
612
|
+
rule_id=d.get("rule_id", None),
|
|
613
|
+
rule_owner_collaborator_alias=d.get("rule_owner_collaborator_alias", None),
|
|
614
|
+
runner_collaborator_alias=d.get("runner_collaborator_alias", None),
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
class CleanRoomAutoApprovalRuleAuthorScope(Enum):
|
|
619
|
+
|
|
620
|
+
ANY_AUTHOR = "ANY_AUTHOR"
|
|
621
|
+
|
|
622
|
+
|
|
543
623
|
@dataclass
|
|
544
624
|
class CleanRoomCollaborator:
|
|
545
625
|
"""Publicly visible clean room collaborator."""
|
|
@@ -1017,6 +1097,41 @@ class ComplianceSecurityProfile:
|
|
|
1017
1097
|
)
|
|
1018
1098
|
|
|
1019
1099
|
|
|
1100
|
+
@dataclass
|
|
1101
|
+
class CreateCleanRoomAssetReviewResponse:
|
|
1102
|
+
notebook_review_state: Optional[CleanRoomNotebookReviewNotebookReviewState] = None
|
|
1103
|
+
"""top-level status derived from all reviews"""
|
|
1104
|
+
|
|
1105
|
+
notebook_reviews: Optional[List[CleanRoomNotebookReview]] = None
|
|
1106
|
+
"""All existing notebook approvals or rejections"""
|
|
1107
|
+
|
|
1108
|
+
def as_dict(self) -> dict:
|
|
1109
|
+
"""Serializes the CreateCleanRoomAssetReviewResponse into a dictionary suitable for use as a JSON request body."""
|
|
1110
|
+
body = {}
|
|
1111
|
+
if self.notebook_review_state is not None:
|
|
1112
|
+
body["notebook_review_state"] = self.notebook_review_state.value
|
|
1113
|
+
if self.notebook_reviews:
|
|
1114
|
+
body["notebook_reviews"] = [v.as_dict() for v in self.notebook_reviews]
|
|
1115
|
+
return body
|
|
1116
|
+
|
|
1117
|
+
def as_shallow_dict(self) -> dict:
|
|
1118
|
+
"""Serializes the CreateCleanRoomAssetReviewResponse into a shallow dictionary of its immediate attributes."""
|
|
1119
|
+
body = {}
|
|
1120
|
+
if self.notebook_review_state is not None:
|
|
1121
|
+
body["notebook_review_state"] = self.notebook_review_state
|
|
1122
|
+
if self.notebook_reviews:
|
|
1123
|
+
body["notebook_reviews"] = self.notebook_reviews
|
|
1124
|
+
return body
|
|
1125
|
+
|
|
1126
|
+
@classmethod
|
|
1127
|
+
def from_dict(cls, d: Dict[str, Any]) -> CreateCleanRoomAssetReviewResponse:
|
|
1128
|
+
"""Deserializes the CreateCleanRoomAssetReviewResponse from a dictionary."""
|
|
1129
|
+
return cls(
|
|
1130
|
+
notebook_review_state=_enum(d, "notebook_review_state", CleanRoomNotebookReviewNotebookReviewState),
|
|
1131
|
+
notebook_reviews=_repeated_dict(d, "notebook_reviews", CleanRoomNotebookReview),
|
|
1132
|
+
)
|
|
1133
|
+
|
|
1134
|
+
|
|
1020
1135
|
@dataclass
|
|
1021
1136
|
class CreateCleanRoomOutputCatalogResponse:
|
|
1022
1137
|
output_catalog: Optional[CleanRoomOutputCatalog] = None
|
|
@@ -1062,6 +1177,38 @@ class DeleteCleanRoomAssetResponse:
|
|
|
1062
1177
|
return cls()
|
|
1063
1178
|
|
|
1064
1179
|
|
|
1180
|
+
@dataclass
|
|
1181
|
+
class ListCleanRoomAssetRevisionsResponse:
|
|
1182
|
+
next_page_token: Optional[str] = None
|
|
1183
|
+
|
|
1184
|
+
revisions: Optional[List[CleanRoomAsset]] = None
|
|
1185
|
+
|
|
1186
|
+
def as_dict(self) -> dict:
|
|
1187
|
+
"""Serializes the ListCleanRoomAssetRevisionsResponse into a dictionary suitable for use as a JSON request body."""
|
|
1188
|
+
body = {}
|
|
1189
|
+
if self.next_page_token is not None:
|
|
1190
|
+
body["next_page_token"] = self.next_page_token
|
|
1191
|
+
if self.revisions:
|
|
1192
|
+
body["revisions"] = [v.as_dict() for v in self.revisions]
|
|
1193
|
+
return body
|
|
1194
|
+
|
|
1195
|
+
def as_shallow_dict(self) -> dict:
|
|
1196
|
+
"""Serializes the ListCleanRoomAssetRevisionsResponse into a shallow dictionary of its immediate attributes."""
|
|
1197
|
+
body = {}
|
|
1198
|
+
if self.next_page_token is not None:
|
|
1199
|
+
body["next_page_token"] = self.next_page_token
|
|
1200
|
+
if self.revisions:
|
|
1201
|
+
body["revisions"] = self.revisions
|
|
1202
|
+
return body
|
|
1203
|
+
|
|
1204
|
+
@classmethod
|
|
1205
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListCleanRoomAssetRevisionsResponse:
|
|
1206
|
+
"""Deserializes the ListCleanRoomAssetRevisionsResponse from a dictionary."""
|
|
1207
|
+
return cls(
|
|
1208
|
+
next_page_token=d.get("next_page_token", None), revisions=_repeated_dict(d, "revisions", CleanRoomAsset)
|
|
1209
|
+
)
|
|
1210
|
+
|
|
1211
|
+
|
|
1065
1212
|
@dataclass
|
|
1066
1213
|
class ListCleanRoomAssetsResponse:
|
|
1067
1214
|
assets: Optional[List[CleanRoomAsset]] = None
|
|
@@ -1095,6 +1242,40 @@ class ListCleanRoomAssetsResponse:
|
|
|
1095
1242
|
return cls(assets=_repeated_dict(d, "assets", CleanRoomAsset), next_page_token=d.get("next_page_token", None))
|
|
1096
1243
|
|
|
1097
1244
|
|
|
1245
|
+
@dataclass
|
|
1246
|
+
class ListCleanRoomAutoApprovalRulesResponse:
|
|
1247
|
+
next_page_token: Optional[str] = None
|
|
1248
|
+
"""Opaque token to retrieve the next page of results. Absent if there are no more pages. page_token
|
|
1249
|
+
should be set to this value for the next request (for the next page of results)."""
|
|
1250
|
+
|
|
1251
|
+
rules: Optional[List[CleanRoomAutoApprovalRule]] = None
|
|
1252
|
+
|
|
1253
|
+
def as_dict(self) -> dict:
|
|
1254
|
+
"""Serializes the ListCleanRoomAutoApprovalRulesResponse into a dictionary suitable for use as a JSON request body."""
|
|
1255
|
+
body = {}
|
|
1256
|
+
if self.next_page_token is not None:
|
|
1257
|
+
body["next_page_token"] = self.next_page_token
|
|
1258
|
+
if self.rules:
|
|
1259
|
+
body["rules"] = [v.as_dict() for v in self.rules]
|
|
1260
|
+
return body
|
|
1261
|
+
|
|
1262
|
+
def as_shallow_dict(self) -> dict:
|
|
1263
|
+
"""Serializes the ListCleanRoomAutoApprovalRulesResponse into a shallow dictionary of its immediate attributes."""
|
|
1264
|
+
body = {}
|
|
1265
|
+
if self.next_page_token is not None:
|
|
1266
|
+
body["next_page_token"] = self.next_page_token
|
|
1267
|
+
if self.rules:
|
|
1268
|
+
body["rules"] = self.rules
|
|
1269
|
+
return body
|
|
1270
|
+
|
|
1271
|
+
@classmethod
|
|
1272
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListCleanRoomAutoApprovalRulesResponse:
|
|
1273
|
+
"""Deserializes the ListCleanRoomAutoApprovalRulesResponse from a dictionary."""
|
|
1274
|
+
return cls(
|
|
1275
|
+
next_page_token=d.get("next_page_token", None), rules=_repeated_dict(d, "rules", CleanRoomAutoApprovalRule)
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
|
|
1098
1279
|
@dataclass
|
|
1099
1280
|
class ListCleanRoomNotebookTaskRunsResponse:
|
|
1100
1281
|
next_page_token: Optional[str] = None
|
|
@@ -1164,6 +1345,130 @@ class ListCleanRoomsResponse:
|
|
|
1164
1345
|
)
|
|
1165
1346
|
|
|
1166
1347
|
|
|
1348
|
+
@dataclass
|
|
1349
|
+
class NotebookVersionReview:
|
|
1350
|
+
etag: str
|
|
1351
|
+
"""etag that identifies the notebook version"""
|
|
1352
|
+
|
|
1353
|
+
review_state: CleanRoomNotebookReviewNotebookReviewState
|
|
1354
|
+
"""review outcome"""
|
|
1355
|
+
|
|
1356
|
+
comment: Optional[str] = None
|
|
1357
|
+
"""review comment"""
|
|
1358
|
+
|
|
1359
|
+
def as_dict(self) -> dict:
|
|
1360
|
+
"""Serializes the NotebookVersionReview into a dictionary suitable for use as a JSON request body."""
|
|
1361
|
+
body = {}
|
|
1362
|
+
if self.comment is not None:
|
|
1363
|
+
body["comment"] = self.comment
|
|
1364
|
+
if self.etag is not None:
|
|
1365
|
+
body["etag"] = self.etag
|
|
1366
|
+
if self.review_state is not None:
|
|
1367
|
+
body["review_state"] = self.review_state.value
|
|
1368
|
+
return body
|
|
1369
|
+
|
|
1370
|
+
def as_shallow_dict(self) -> dict:
|
|
1371
|
+
"""Serializes the NotebookVersionReview into a shallow dictionary of its immediate attributes."""
|
|
1372
|
+
body = {}
|
|
1373
|
+
if self.comment is not None:
|
|
1374
|
+
body["comment"] = self.comment
|
|
1375
|
+
if self.etag is not None:
|
|
1376
|
+
body["etag"] = self.etag
|
|
1377
|
+
if self.review_state is not None:
|
|
1378
|
+
body["review_state"] = self.review_state
|
|
1379
|
+
return body
|
|
1380
|
+
|
|
1381
|
+
@classmethod
|
|
1382
|
+
def from_dict(cls, d: Dict[str, Any]) -> NotebookVersionReview:
|
|
1383
|
+
"""Deserializes the NotebookVersionReview from a dictionary."""
|
|
1384
|
+
return cls(
|
|
1385
|
+
comment=d.get("comment", None),
|
|
1386
|
+
etag=d.get("etag", None),
|
|
1387
|
+
review_state=_enum(d, "review_state", CleanRoomNotebookReviewNotebookReviewState),
|
|
1388
|
+
)
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
class CleanRoomAssetRevisionsAPI:
|
|
1392
|
+
"""Clean Room Asset Revisions denote new versions of uploaded assets (e.g. notebooks) in the clean room."""
|
|
1393
|
+
|
|
1394
|
+
def __init__(self, api_client):
|
|
1395
|
+
self._api = api_client
|
|
1396
|
+
|
|
1397
|
+
def get(self, clean_room_name: str, asset_type: CleanRoomAssetAssetType, name: str, etag: str) -> CleanRoomAsset:
|
|
1398
|
+
"""Get a specific revision of an asset
|
|
1399
|
+
|
|
1400
|
+
:param clean_room_name: str
|
|
1401
|
+
Name of the clean room.
|
|
1402
|
+
:param asset_type: :class:`CleanRoomAssetAssetType`
|
|
1403
|
+
Asset type. Only NOTEBOOK_FILE is supported.
|
|
1404
|
+
:param name: str
|
|
1405
|
+
Name of the asset.
|
|
1406
|
+
:param etag: str
|
|
1407
|
+
Revision etag to fetch. If not provided, the latest revision will be returned.
|
|
1408
|
+
|
|
1409
|
+
:returns: :class:`CleanRoomAsset`
|
|
1410
|
+
"""
|
|
1411
|
+
|
|
1412
|
+
headers = {
|
|
1413
|
+
"Accept": "application/json",
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
res = self._api.do(
|
|
1417
|
+
"GET",
|
|
1418
|
+
f"/api/2.0/clean-rooms/{clean_room_name}/assets/{asset_type.value}/{name}/revisions/{etag}",
|
|
1419
|
+
headers=headers,
|
|
1420
|
+
)
|
|
1421
|
+
return CleanRoomAsset.from_dict(res)
|
|
1422
|
+
|
|
1423
|
+
def list(
|
|
1424
|
+
self,
|
|
1425
|
+
clean_room_name: str,
|
|
1426
|
+
asset_type: CleanRoomAssetAssetType,
|
|
1427
|
+
name: str,
|
|
1428
|
+
*,
|
|
1429
|
+
page_size: Optional[int] = None,
|
|
1430
|
+
page_token: Optional[str] = None,
|
|
1431
|
+
) -> Iterator[CleanRoomAsset]:
|
|
1432
|
+
"""List revisions for an asset
|
|
1433
|
+
|
|
1434
|
+
:param clean_room_name: str
|
|
1435
|
+
Name of the clean room.
|
|
1436
|
+
:param asset_type: :class:`CleanRoomAssetAssetType`
|
|
1437
|
+
Asset type. Only NOTEBOOK_FILE is supported.
|
|
1438
|
+
:param name: str
|
|
1439
|
+
Name of the asset.
|
|
1440
|
+
:param page_size: int (optional)
|
|
1441
|
+
Maximum number of asset revisions to return. Defaults to 10.
|
|
1442
|
+
:param page_token: str (optional)
|
|
1443
|
+
Opaque pagination token to go to next page based on the previous query.
|
|
1444
|
+
|
|
1445
|
+
:returns: Iterator over :class:`CleanRoomAsset`
|
|
1446
|
+
"""
|
|
1447
|
+
|
|
1448
|
+
query = {}
|
|
1449
|
+
if page_size is not None:
|
|
1450
|
+
query["page_size"] = page_size
|
|
1451
|
+
if page_token is not None:
|
|
1452
|
+
query["page_token"] = page_token
|
|
1453
|
+
headers = {
|
|
1454
|
+
"Accept": "application/json",
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
while True:
|
|
1458
|
+
json = self._api.do(
|
|
1459
|
+
"GET",
|
|
1460
|
+
f"/api/2.0/clean-rooms/{clean_room_name}/assets/{asset_type.value}/{name}/revisions",
|
|
1461
|
+
query=query,
|
|
1462
|
+
headers=headers,
|
|
1463
|
+
)
|
|
1464
|
+
if "revisions" in json:
|
|
1465
|
+
for v in json["revisions"]:
|
|
1466
|
+
yield CleanRoomAsset.from_dict(v)
|
|
1467
|
+
if "next_page_token" not in json or not json["next_page_token"]:
|
|
1468
|
+
return
|
|
1469
|
+
query["page_token"] = json["next_page_token"]
|
|
1470
|
+
|
|
1471
|
+
|
|
1167
1472
|
class CleanRoomAssetsAPI:
|
|
1168
1473
|
"""Clean room assets are data and code objects — Tables, volumes, and notebooks that are shared with the
|
|
1169
1474
|
clean room."""
|
|
@@ -1178,8 +1483,8 @@ class CleanRoomAssetsAPI:
|
|
|
1178
1483
|
access the asset. Typically, you should use a group as the clean room owner.
|
|
1179
1484
|
|
|
1180
1485
|
:param clean_room_name: str
|
|
1181
|
-
The name of the clean room this asset belongs to. This is
|
|
1182
|
-
|
|
1486
|
+
The name of the clean room this asset belongs to. This field is required for create operations and
|
|
1487
|
+
populated by the server for responses.
|
|
1183
1488
|
:param asset: :class:`CleanRoomAsset`
|
|
1184
1489
|
|
|
1185
1490
|
:returns: :class:`CleanRoomAsset`
|
|
@@ -1193,6 +1498,41 @@ class CleanRoomAssetsAPI:
|
|
|
1193
1498
|
res = self._api.do("POST", f"/api/2.0/clean-rooms/{clean_room_name}/assets", body=body, headers=headers)
|
|
1194
1499
|
return CleanRoomAsset.from_dict(res)
|
|
1195
1500
|
|
|
1501
|
+
def create_clean_room_asset_review(
|
|
1502
|
+
self,
|
|
1503
|
+
clean_room_name: str,
|
|
1504
|
+
asset_type: CleanRoomAssetAssetType,
|
|
1505
|
+
name: str,
|
|
1506
|
+
notebook_review: NotebookVersionReview,
|
|
1507
|
+
) -> CreateCleanRoomAssetReviewResponse:
|
|
1508
|
+
"""submit an asset review
|
|
1509
|
+
|
|
1510
|
+
:param clean_room_name: str
|
|
1511
|
+
Name of the clean room
|
|
1512
|
+
:param asset_type: :class:`CleanRoomAssetAssetType`
|
|
1513
|
+
can only be NOTEBOOK_FILE for now
|
|
1514
|
+
:param name: str
|
|
1515
|
+
Name of the asset
|
|
1516
|
+
:param notebook_review: :class:`NotebookVersionReview`
|
|
1517
|
+
|
|
1518
|
+
:returns: :class:`CreateCleanRoomAssetReviewResponse`
|
|
1519
|
+
"""
|
|
1520
|
+
body = {}
|
|
1521
|
+
if notebook_review is not None:
|
|
1522
|
+
body["notebook_review"] = notebook_review.as_dict()
|
|
1523
|
+
headers = {
|
|
1524
|
+
"Accept": "application/json",
|
|
1525
|
+
"Content-Type": "application/json",
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
res = self._api.do(
|
|
1529
|
+
"POST",
|
|
1530
|
+
f"/api/2.0/clean-rooms/{clean_room_name}/assets/{asset_type.value}/{name}/reviews",
|
|
1531
|
+
body=body,
|
|
1532
|
+
headers=headers,
|
|
1533
|
+
)
|
|
1534
|
+
return CreateCleanRoomAssetReviewResponse.from_dict(res)
|
|
1535
|
+
|
|
1196
1536
|
def delete(self, clean_room_name: str, asset_type: CleanRoomAssetAssetType, name: str):
|
|
1197
1537
|
"""Delete a clean room asset - unshare/remove the asset from the clean room
|
|
1198
1538
|
|
|
@@ -1302,6 +1642,128 @@ class CleanRoomAssetsAPI:
|
|
|
1302
1642
|
return CleanRoomAsset.from_dict(res)
|
|
1303
1643
|
|
|
1304
1644
|
|
|
1645
|
+
class CleanRoomAutoApprovalRulesAPI:
|
|
1646
|
+
"""Clean room auto-approval rules automatically create an approval on your behalf when an asset (e.g.
|
|
1647
|
+
notebook) meeting specific criteria is shared in a clean room."""
|
|
1648
|
+
|
|
1649
|
+
def __init__(self, api_client):
|
|
1650
|
+
self._api = api_client
|
|
1651
|
+
|
|
1652
|
+
def create(self, clean_room_name: str, auto_approval_rule: CleanRoomAutoApprovalRule) -> CleanRoomAutoApprovalRule:
|
|
1653
|
+
"""Create an auto-approval rule
|
|
1654
|
+
|
|
1655
|
+
:param clean_room_name: str
|
|
1656
|
+
The name of the clean room this auto-approval rule belongs to.
|
|
1657
|
+
:param auto_approval_rule: :class:`CleanRoomAutoApprovalRule`
|
|
1658
|
+
|
|
1659
|
+
:returns: :class:`CleanRoomAutoApprovalRule`
|
|
1660
|
+
"""
|
|
1661
|
+
body = {}
|
|
1662
|
+
if auto_approval_rule is not None:
|
|
1663
|
+
body["auto_approval_rule"] = auto_approval_rule.as_dict()
|
|
1664
|
+
headers = {
|
|
1665
|
+
"Accept": "application/json",
|
|
1666
|
+
"Content-Type": "application/json",
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
res = self._api.do(
|
|
1670
|
+
"POST", f"/api/2.0/clean-rooms/{clean_room_name}/auto-approval-rules", body=body, headers=headers
|
|
1671
|
+
)
|
|
1672
|
+
return CleanRoomAutoApprovalRule.from_dict(res)
|
|
1673
|
+
|
|
1674
|
+
def delete(self, clean_room_name: str, rule_id: str):
|
|
1675
|
+
"""Delete a auto-approval rule by rule ID
|
|
1676
|
+
|
|
1677
|
+
:param clean_room_name: str
|
|
1678
|
+
:param rule_id: str
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
"""
|
|
1682
|
+
|
|
1683
|
+
headers = {
|
|
1684
|
+
"Accept": "application/json",
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
self._api.do("DELETE", f"/api/2.0/clean-rooms/{clean_room_name}/auto-approval-rules/{rule_id}", headers=headers)
|
|
1688
|
+
|
|
1689
|
+
def get(self, clean_room_name: str, rule_id: str) -> CleanRoomAutoApprovalRule:
|
|
1690
|
+
"""Get a auto-approval rule by rule ID
|
|
1691
|
+
|
|
1692
|
+
:param clean_room_name: str
|
|
1693
|
+
:param rule_id: str
|
|
1694
|
+
|
|
1695
|
+
:returns: :class:`CleanRoomAutoApprovalRule`
|
|
1696
|
+
"""
|
|
1697
|
+
|
|
1698
|
+
headers = {
|
|
1699
|
+
"Accept": "application/json",
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
res = self._api.do(
|
|
1703
|
+
"GET", f"/api/2.0/clean-rooms/{clean_room_name}/auto-approval-rules/{rule_id}", headers=headers
|
|
1704
|
+
)
|
|
1705
|
+
return CleanRoomAutoApprovalRule.from_dict(res)
|
|
1706
|
+
|
|
1707
|
+
def list(
|
|
1708
|
+
self, clean_room_name: str, *, page_size: Optional[int] = None, page_token: Optional[str] = None
|
|
1709
|
+
) -> Iterator[CleanRoomAutoApprovalRule]:
|
|
1710
|
+
"""List all auto-approval rules for the caller
|
|
1711
|
+
|
|
1712
|
+
:param clean_room_name: str
|
|
1713
|
+
:param page_size: int (optional)
|
|
1714
|
+
Maximum number of auto-approval rules to return. Defaults to 100.
|
|
1715
|
+
:param page_token: str (optional)
|
|
1716
|
+
Opaque pagination token to go to next page based on previous query.
|
|
1717
|
+
|
|
1718
|
+
:returns: Iterator over :class:`CleanRoomAutoApprovalRule`
|
|
1719
|
+
"""
|
|
1720
|
+
|
|
1721
|
+
query = {}
|
|
1722
|
+
if page_size is not None:
|
|
1723
|
+
query["page_size"] = page_size
|
|
1724
|
+
if page_token is not None:
|
|
1725
|
+
query["page_token"] = page_token
|
|
1726
|
+
headers = {
|
|
1727
|
+
"Accept": "application/json",
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
while True:
|
|
1731
|
+
json = self._api.do(
|
|
1732
|
+
"GET", f"/api/2.0/clean-rooms/{clean_room_name}/auto-approval-rules", query=query, headers=headers
|
|
1733
|
+
)
|
|
1734
|
+
if "rules" in json:
|
|
1735
|
+
for v in json["rules"]:
|
|
1736
|
+
yield CleanRoomAutoApprovalRule.from_dict(v)
|
|
1737
|
+
if "next_page_token" not in json or not json["next_page_token"]:
|
|
1738
|
+
return
|
|
1739
|
+
query["page_token"] = json["next_page_token"]
|
|
1740
|
+
|
|
1741
|
+
def update(
|
|
1742
|
+
self, clean_room_name: str, rule_id: str, auto_approval_rule: CleanRoomAutoApprovalRule
|
|
1743
|
+
) -> CleanRoomAutoApprovalRule:
|
|
1744
|
+
"""Update a auto-approval rule by rule ID
|
|
1745
|
+
|
|
1746
|
+
:param clean_room_name: str
|
|
1747
|
+
The name of the clean room this auto-approval rule belongs to.
|
|
1748
|
+
:param rule_id: str
|
|
1749
|
+
A generated UUID identifying the rule.
|
|
1750
|
+
:param auto_approval_rule: :class:`CleanRoomAutoApprovalRule`
|
|
1751
|
+
The auto-approval rule to update. The rule_id field is used to identify the rule to update.
|
|
1752
|
+
|
|
1753
|
+
:returns: :class:`CleanRoomAutoApprovalRule`
|
|
1754
|
+
"""
|
|
1755
|
+
body = auto_approval_rule.as_dict()
|
|
1756
|
+
headers = {
|
|
1757
|
+
"Accept": "application/json",
|
|
1758
|
+
"Content-Type": "application/json",
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
res = self._api.do(
|
|
1762
|
+
"PATCH", f"/api/2.0/clean-rooms/{clean_room_name}/auto-approval-rules/{rule_id}", body=body, headers=headers
|
|
1763
|
+
)
|
|
1764
|
+
return CleanRoomAutoApprovalRule.from_dict(res)
|
|
1765
|
+
|
|
1766
|
+
|
|
1305
1767
|
class CleanRoomTaskRunsAPI:
|
|
1306
1768
|
"""Clean room task runs are the executions of notebooks in a clean room."""
|
|
1307
1769
|
|
|
@@ -1359,7 +1821,32 @@ class CleanRoomsAPI:
|
|
|
1359
1821
|
def __init__(self, api_client):
|
|
1360
1822
|
self._api = api_client
|
|
1361
1823
|
|
|
1362
|
-
def
|
|
1824
|
+
def wait_get_clean_room_active(
|
|
1825
|
+
self, name: str, timeout=timedelta(minutes=20), callback: Optional[Callable[[CleanRoom], None]] = None
|
|
1826
|
+
) -> CleanRoom:
|
|
1827
|
+
deadline = time.time() + timeout.total_seconds()
|
|
1828
|
+
target_states = (CleanRoomStatusEnum.ACTIVE,)
|
|
1829
|
+
status_message = "polling..."
|
|
1830
|
+
attempt = 1
|
|
1831
|
+
while time.time() < deadline:
|
|
1832
|
+
poll = self.get(name=name)
|
|
1833
|
+
status = poll.status
|
|
1834
|
+
status_message = f"current status: {status}"
|
|
1835
|
+
if status in target_states:
|
|
1836
|
+
return poll
|
|
1837
|
+
if callback:
|
|
1838
|
+
callback(poll)
|
|
1839
|
+
prefix = f"name={name}"
|
|
1840
|
+
sleep = attempt
|
|
1841
|
+
if sleep > 10:
|
|
1842
|
+
# sleep 10s max per attempt
|
|
1843
|
+
sleep = 10
|
|
1844
|
+
_LOG.debug(f"{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)")
|
|
1845
|
+
time.sleep(sleep + random.random())
|
|
1846
|
+
attempt += 1
|
|
1847
|
+
raise TimeoutError(f"timed out after {timeout}: {status_message}")
|
|
1848
|
+
|
|
1849
|
+
def create(self, clean_room: CleanRoom) -> Wait[CleanRoom]:
|
|
1363
1850
|
"""Create a new clean room with the specified collaborators. This method is asynchronous; the returned
|
|
1364
1851
|
name field inside the clean_room field can be used to poll the clean room status, using the
|
|
1365
1852
|
:method:cleanrooms/get method. When this method returns, the clean room will be in a PROVISIONING
|
|
@@ -1370,7 +1857,9 @@ class CleanRoomsAPI:
|
|
|
1370
1857
|
|
|
1371
1858
|
:param clean_room: :class:`CleanRoom`
|
|
1372
1859
|
|
|
1373
|
-
:returns:
|
|
1860
|
+
:returns:
|
|
1861
|
+
Long-running operation waiter for :class:`CleanRoom`.
|
|
1862
|
+
See :method:wait_get_clean_room_active for more details.
|
|
1374
1863
|
"""
|
|
1375
1864
|
body = clean_room.as_dict()
|
|
1376
1865
|
headers = {
|
|
@@ -1378,8 +1867,13 @@ class CleanRoomsAPI:
|
|
|
1378
1867
|
"Content-Type": "application/json",
|
|
1379
1868
|
}
|
|
1380
1869
|
|
|
1381
|
-
|
|
1382
|
-
return
|
|
1870
|
+
op_response = self._api.do("POST", "/api/2.0/clean-rooms", body=body, headers=headers)
|
|
1871
|
+
return Wait(
|
|
1872
|
+
self.wait_get_clean_room_active, response=CleanRoom.from_dict(op_response), name=op_response["name"]
|
|
1873
|
+
)
|
|
1874
|
+
|
|
1875
|
+
def create_and_wait(self, clean_room: CleanRoom, timeout=timedelta(minutes=20)) -> CleanRoom:
|
|
1876
|
+
return self.create(clean_room=clean_room).result(timeout=timeout)
|
|
1383
1877
|
|
|
1384
1878
|
def create_output_catalog(
|
|
1385
1879
|
self, clean_room_name: str, output_catalog: CleanRoomOutputCatalog
|