databricks-sdk 0.43.0__py3-none-any.whl → 0.44.1__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.
- databricks/sdk/__init__.py +250 -243
- databricks/sdk/credentials_provider.py +71 -16
- databricks/sdk/mixins/jobs.py +12 -6
- databricks/sdk/service/apps.py +6 -0
- databricks/sdk/service/billing.py +31 -1
- databricks/sdk/service/catalog.py +8 -0
- databricks/sdk/service/cleanrooms.py +1 -71
- databricks/sdk/service/compute.py +50 -42
- databricks/sdk/service/dashboards.py +28 -0
- databricks/sdk/service/serving.py +1 -1
- databricks/sdk/service/sharing.py +15 -6
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.43.0.dist-info → databricks_sdk-0.44.1.dist-info}/METADATA +1 -1
- {databricks_sdk-0.43.0.dist-info → databricks_sdk-0.44.1.dist-info}/RECORD +18 -18
- {databricks_sdk-0.43.0.dist-info → databricks_sdk-0.44.1.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.43.0.dist-info → databricks_sdk-0.44.1.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.43.0.dist-info → databricks_sdk-0.44.1.dist-info}/WHEEL +0 -0
- {databricks_sdk-0.43.0.dist-info → databricks_sdk-0.44.1.dist-info}/top_level.txt +0 -0
|
@@ -9,6 +9,7 @@ import pathlib
|
|
|
9
9
|
import platform
|
|
10
10
|
import subprocess
|
|
11
11
|
import sys
|
|
12
|
+
import threading
|
|
12
13
|
import time
|
|
13
14
|
from datetime import datetime
|
|
14
15
|
from typing import Callable, Dict, List, Optional, Tuple, Union
|
|
@@ -723,14 +724,17 @@ def metadata_service(cfg: 'Config') -> Optional[CredentialsProvider]:
|
|
|
723
724
|
# This Code is derived from Mlflow DatabricksModelServingConfigProvider
|
|
724
725
|
# https://github.com/mlflow/mlflow/blob/1219e3ef1aac7d337a618a352cd859b336cf5c81/mlflow/legacy_databricks_cli/configure/provider.py#L332
|
|
725
726
|
class ModelServingAuthProvider():
|
|
727
|
+
USER_CREDENTIALS = "user_credentials"
|
|
728
|
+
|
|
726
729
|
_MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH = "/var/credentials-secret/model-dependencies-oauth-token"
|
|
727
730
|
|
|
728
|
-
def __init__(self):
|
|
731
|
+
def __init__(self, credential_type: Optional[str]):
|
|
729
732
|
self.expiry_time = -1
|
|
730
733
|
self.current_token = None
|
|
731
734
|
self.refresh_duration = 300 # 300 Seconds
|
|
735
|
+
self.credential_type = credential_type
|
|
732
736
|
|
|
733
|
-
def should_fetch_model_serving_environment_oauth(
|
|
737
|
+
def should_fetch_model_serving_environment_oauth() -> bool:
|
|
734
738
|
"""
|
|
735
739
|
Check whether this is the model serving environment
|
|
736
740
|
Additionally check if the oauth token file path exists
|
|
@@ -739,15 +743,15 @@ class ModelServingAuthProvider():
|
|
|
739
743
|
is_in_model_serving_env = (os.environ.get("IS_IN_DB_MODEL_SERVING_ENV")
|
|
740
744
|
or os.environ.get("IS_IN_DATABRICKS_MODEL_SERVING_ENV") or "false")
|
|
741
745
|
return (is_in_model_serving_env == "true"
|
|
742
|
-
and os.path.isfile(
|
|
746
|
+
and os.path.isfile(ModelServingAuthProvider._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH))
|
|
743
747
|
|
|
744
|
-
def
|
|
748
|
+
def _get_model_dependency_oauth_token(self, should_retry=True) -> str:
|
|
745
749
|
# Use Cached value if it is valid
|
|
746
750
|
if self.current_token is not None and self.expiry_time > time.time():
|
|
747
751
|
return self.current_token
|
|
748
752
|
|
|
749
753
|
try:
|
|
750
|
-
with open(
|
|
754
|
+
with open(ModelServingAuthProvider._MODEL_DEPENDENCY_OAUTH_TOKEN_FILE_PATH) as f:
|
|
751
755
|
oauth_dict = json.load(f)
|
|
752
756
|
self.current_token = oauth_dict["OAUTH_TOKEN"][0]["oauthTokenValue"]
|
|
753
757
|
self.expiry_time = time.time() + self.refresh_duration
|
|
@@ -757,32 +761,43 @@ class ModelServingAuthProvider():
|
|
|
757
761
|
logger.warning("Unable to read oauth token on first attmept in Model Serving Environment",
|
|
758
762
|
exc_info=e)
|
|
759
763
|
time.sleep(0.5)
|
|
760
|
-
return self.
|
|
764
|
+
return self._get_model_dependency_oauth_token(should_retry=False)
|
|
761
765
|
else:
|
|
762
766
|
raise RuntimeError(
|
|
763
767
|
"Unable to read OAuth credentials from the file mounted in Databricks Model Serving"
|
|
764
768
|
) from e
|
|
765
769
|
return self.current_token
|
|
766
770
|
|
|
771
|
+
def _get_invokers_token(self):
|
|
772
|
+
current_thread = threading.current_thread()
|
|
773
|
+
thread_data = current_thread.__dict__
|
|
774
|
+
invokers_token = None
|
|
775
|
+
if "invokers_token" in thread_data:
|
|
776
|
+
invokers_token = thread_data["invokers_token"]
|
|
777
|
+
|
|
778
|
+
if invokers_token is None:
|
|
779
|
+
raise RuntimeError("Unable to read Invokers Token in Databricks Model Serving")
|
|
780
|
+
|
|
781
|
+
return invokers_token
|
|
782
|
+
|
|
767
783
|
def get_databricks_host_token(self) -> Optional[Tuple[str, str]]:
|
|
768
|
-
if not
|
|
784
|
+
if not ModelServingAuthProvider.should_fetch_model_serving_environment_oauth():
|
|
769
785
|
return None
|
|
770
786
|
|
|
771
787
|
# read from DB_MODEL_SERVING_HOST_ENV_VAR if available otherwise MODEL_SERVING_HOST_ENV_VAR
|
|
772
788
|
host = os.environ.get("DATABRICKS_MODEL_SERVING_HOST_URL") or os.environ.get(
|
|
773
789
|
"DB_MODEL_SERVING_HOST_URL")
|
|
774
|
-
token = self.get_model_dependency_oauth_token()
|
|
775
790
|
|
|
776
|
-
|
|
791
|
+
if self.credential_type == ModelServingAuthProvider.USER_CREDENTIALS:
|
|
792
|
+
return (host, self._get_invokers_token())
|
|
793
|
+
else:
|
|
794
|
+
return (host, self._get_model_dependency_oauth_token())
|
|
777
795
|
|
|
778
796
|
|
|
779
|
-
|
|
780
|
-
|
|
797
|
+
def model_serving_auth_visitor(cfg: 'Config',
|
|
798
|
+
credential_type: Optional[str] = None) -> Optional[CredentialsProvider]:
|
|
781
799
|
try:
|
|
782
|
-
model_serving_auth_provider = ModelServingAuthProvider()
|
|
783
|
-
if not model_serving_auth_provider.should_fetch_model_serving_environment_oauth():
|
|
784
|
-
logger.debug("model-serving: Not in Databricks Model Serving, skipping")
|
|
785
|
-
return None
|
|
800
|
+
model_serving_auth_provider = ModelServingAuthProvider(credential_type)
|
|
786
801
|
host, token = model_serving_auth_provider.get_databricks_host_token()
|
|
787
802
|
if token is None:
|
|
788
803
|
raise ValueError(
|
|
@@ -793,7 +808,6 @@ def model_serving_auth(cfg: 'Config') -> Optional[CredentialsProvider]:
|
|
|
793
808
|
except Exception as e:
|
|
794
809
|
logger.warning("Unable to get auth from Databricks Model Serving Environment", exc_info=e)
|
|
795
810
|
return None
|
|
796
|
-
|
|
797
811
|
logger.info("Using Databricks Model Serving Authentication")
|
|
798
812
|
|
|
799
813
|
def inner() -> Dict[str, str]:
|
|
@@ -804,6 +818,15 @@ def model_serving_auth(cfg: 'Config') -> Optional[CredentialsProvider]:
|
|
|
804
818
|
return inner
|
|
805
819
|
|
|
806
820
|
|
|
821
|
+
@credentials_strategy('model-serving', [])
|
|
822
|
+
def model_serving_auth(cfg: 'Config') -> Optional[CredentialsProvider]:
|
|
823
|
+
if not ModelServingAuthProvider.should_fetch_model_serving_environment_oauth():
|
|
824
|
+
logger.debug("model-serving: Not in Databricks Model Serving, skipping")
|
|
825
|
+
return None
|
|
826
|
+
|
|
827
|
+
return model_serving_auth_visitor(cfg)
|
|
828
|
+
|
|
829
|
+
|
|
807
830
|
class DefaultCredentials:
|
|
808
831
|
""" Select the first applicable credential provider from the chain """
|
|
809
832
|
|
|
@@ -846,3 +869,35 @@ class DefaultCredentials:
|
|
|
846
869
|
raise ValueError(
|
|
847
870
|
f'cannot configure default credentials, please check {auth_flow_url} to configure credentials for your preferred authentication method.'
|
|
848
871
|
)
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
class ModelServingUserCredentials(CredentialsStrategy):
|
|
875
|
+
"""
|
|
876
|
+
This credential strategy is designed for authenticating the Databricks SDK in the model serving environment using user-specific rights.
|
|
877
|
+
In the model serving environment, the strategy retrieves a downscoped user token from the thread-local variable.
|
|
878
|
+
In any other environments, the class defaults to the DefaultCredentialStrategy.
|
|
879
|
+
To use this credential strategy, instantiate the WorkspaceClient with the ModelServingUserCredentials strategy as follows:
|
|
880
|
+
|
|
881
|
+
invokers_client = WorkspaceClient(credential_strategy = ModelServingUserCredentials())
|
|
882
|
+
"""
|
|
883
|
+
|
|
884
|
+
def __init__(self):
|
|
885
|
+
self.credential_type = ModelServingAuthProvider.USER_CREDENTIALS
|
|
886
|
+
self.default_credentials = DefaultCredentials()
|
|
887
|
+
|
|
888
|
+
def auth_type(self):
|
|
889
|
+
if ModelServingAuthProvider.should_fetch_model_serving_environment_oauth():
|
|
890
|
+
return "model_serving_" + self.credential_type
|
|
891
|
+
else:
|
|
892
|
+
return self.default_credentials.auth_type()
|
|
893
|
+
|
|
894
|
+
def __call__(self, cfg: 'Config') -> CredentialsProvider:
|
|
895
|
+
if ModelServingAuthProvider.should_fetch_model_serving_environment_oauth():
|
|
896
|
+
header_factory = model_serving_auth_visitor(cfg, self.credential_type)
|
|
897
|
+
if not header_factory:
|
|
898
|
+
raise ValueError(
|
|
899
|
+
f"Unable to authenticate using {self.credential_type} in Databricks Model Serving Environment"
|
|
900
|
+
)
|
|
901
|
+
return header_factory
|
|
902
|
+
else:
|
|
903
|
+
return self.default_credentials(cfg)
|
databricks/sdk/mixins/jobs.py
CHANGED
|
@@ -11,9 +11,10 @@ class JobsExt(jobs.JobsAPI):
|
|
|
11
11
|
include_history: Optional[bool] = None,
|
|
12
12
|
include_resolved_values: Optional[bool] = None,
|
|
13
13
|
page_token: Optional[str] = None) -> jobs.Run:
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
it will paginate through all pages and
|
|
14
|
+
"""Get a single job run.
|
|
15
|
+
|
|
16
|
+
Retrieve the metadata of a run. If a run has multiple pages of tasks, it will paginate through all pages of tasks, iterations, job_clusters, job_parameters, and repair history.
|
|
17
|
+
|
|
17
18
|
:param run_id: int
|
|
18
19
|
The canonical identifier of the run for which to retrieve the metadata. This field is required.
|
|
19
20
|
:param include_history: bool (optional)
|
|
@@ -21,8 +22,9 @@ class JobsExt(jobs.JobsAPI):
|
|
|
21
22
|
:param include_resolved_values: bool (optional)
|
|
22
23
|
Whether to include resolved parameter values in the response.
|
|
23
24
|
:param page_token: str (optional)
|
|
24
|
-
To list the next page
|
|
25
|
-
|
|
25
|
+
To list the next page of job tasks, set this field to the value of the `next_page_token` returned in
|
|
26
|
+
the GetJob response.
|
|
27
|
+
|
|
26
28
|
:returns: :class:`Run`
|
|
27
29
|
"""
|
|
28
30
|
run = super().get_run(run_id,
|
|
@@ -34,6 +36,7 @@ class JobsExt(jobs.JobsAPI):
|
|
|
34
36
|
# When querying a ForEach task run, a page token is returned when there are more than 100 iterations. Only a single task is returned, corresponding to the ForEach task itself. Therefore, the client only reads the iterations from the next page and not the tasks.
|
|
35
37
|
is_paginating_iterations = run.iterations is not None and len(run.iterations) > 0
|
|
36
38
|
|
|
39
|
+
# runs/get response includes next_page_token as long as there are more pages to fetch.
|
|
37
40
|
while run.next_page_token is not None:
|
|
38
41
|
next_run = super().get_run(run_id,
|
|
39
42
|
include_history=include_history,
|
|
@@ -43,7 +46,10 @@ class JobsExt(jobs.JobsAPI):
|
|
|
43
46
|
run.iterations.extend(next_run.iterations)
|
|
44
47
|
else:
|
|
45
48
|
run.tasks.extend(next_run.tasks)
|
|
49
|
+
# Each new page of runs/get response includes the next page of the job_clusters, job_parameters, and repair history.
|
|
50
|
+
run.job_clusters.extend(next_run.job_clusters)
|
|
51
|
+
run.job_parameters.extend(next_run.job_parameters)
|
|
52
|
+
run.repair_history.extend(next_run.repair_history)
|
|
46
53
|
run.next_page_token = next_run.next_page_token
|
|
47
54
|
|
|
48
|
-
run.prev_page_token = None
|
|
49
55
|
return run
|
databricks/sdk/service/apps.py
CHANGED
|
@@ -45,6 +45,9 @@ class App:
|
|
|
45
45
|
description: Optional[str] = None
|
|
46
46
|
"""The description of the app."""
|
|
47
47
|
|
|
48
|
+
id: Optional[str] = None
|
|
49
|
+
"""The unique identifier of the app."""
|
|
50
|
+
|
|
48
51
|
pending_deployment: Optional[AppDeployment] = None
|
|
49
52
|
"""The pending deployment of the app. A deployment is considered pending when it is being prepared
|
|
50
53
|
for deployment to the app compute."""
|
|
@@ -78,6 +81,7 @@ class App:
|
|
|
78
81
|
if self.default_source_code_path is not None:
|
|
79
82
|
body['default_source_code_path'] = self.default_source_code_path
|
|
80
83
|
if self.description is not None: body['description'] = self.description
|
|
84
|
+
if self.id is not None: body['id'] = self.id
|
|
81
85
|
if self.name is not None: body['name'] = self.name
|
|
82
86
|
if self.pending_deployment: body['pending_deployment'] = self.pending_deployment.as_dict()
|
|
83
87
|
if self.resources: body['resources'] = [v.as_dict() for v in self.resources]
|
|
@@ -102,6 +106,7 @@ class App:
|
|
|
102
106
|
if self.default_source_code_path is not None:
|
|
103
107
|
body['default_source_code_path'] = self.default_source_code_path
|
|
104
108
|
if self.description is not None: body['description'] = self.description
|
|
109
|
+
if self.id is not None: body['id'] = self.id
|
|
105
110
|
if self.name is not None: body['name'] = self.name
|
|
106
111
|
if self.pending_deployment: body['pending_deployment'] = self.pending_deployment
|
|
107
112
|
if self.resources: body['resources'] = self.resources
|
|
@@ -125,6 +130,7 @@ class App:
|
|
|
125
130
|
creator=d.get('creator', None),
|
|
126
131
|
default_source_code_path=d.get('default_source_code_path', None),
|
|
127
132
|
description=d.get('description', None),
|
|
133
|
+
id=d.get('id', None),
|
|
128
134
|
name=d.get('name', None),
|
|
129
135
|
pending_deployment=_from_dict(d, 'pending_deployment', AppDeployment),
|
|
130
136
|
resources=_repeated_dict(d, 'resources', AppResource),
|
|
@@ -894,6 +894,27 @@ class GetBudgetConfigurationResponse:
|
|
|
894
894
|
return cls(budget=_from_dict(d, 'budget', BudgetConfiguration))
|
|
895
895
|
|
|
896
896
|
|
|
897
|
+
@dataclass
|
|
898
|
+
class LimitConfig:
|
|
899
|
+
"""The limit configuration of the policy. Limit configuration provide a budget policy level cost
|
|
900
|
+
control by enforcing the limit."""
|
|
901
|
+
|
|
902
|
+
def as_dict(self) -> dict:
|
|
903
|
+
"""Serializes the LimitConfig into a dictionary suitable for use as a JSON request body."""
|
|
904
|
+
body = {}
|
|
905
|
+
return body
|
|
906
|
+
|
|
907
|
+
def as_shallow_dict(self) -> dict:
|
|
908
|
+
"""Serializes the LimitConfig into a shallow dictionary of its immediate attributes."""
|
|
909
|
+
body = {}
|
|
910
|
+
return body
|
|
911
|
+
|
|
912
|
+
@classmethod
|
|
913
|
+
def from_dict(cls, d: Dict[str, any]) -> LimitConfig:
|
|
914
|
+
"""Deserializes the LimitConfig from a dictionary."""
|
|
915
|
+
return cls()
|
|
916
|
+
|
|
917
|
+
|
|
897
918
|
@dataclass
|
|
898
919
|
class ListBudgetConfigurationsResponse:
|
|
899
920
|
budgets: Optional[List[BudgetConfiguration]] = None
|
|
@@ -1641,23 +1662,32 @@ class BudgetPolicyAPI:
|
|
|
1641
1662
|
return
|
|
1642
1663
|
query['page_token'] = json['next_page_token']
|
|
1643
1664
|
|
|
1644
|
-
def update(self,
|
|
1665
|
+
def update(self,
|
|
1666
|
+
policy_id: str,
|
|
1667
|
+
*,
|
|
1668
|
+
limit_config: Optional[LimitConfig] = None,
|
|
1669
|
+
policy: Optional[BudgetPolicy] = None) -> BudgetPolicy:
|
|
1645
1670
|
"""Update a budget policy.
|
|
1646
1671
|
|
|
1647
1672
|
Updates a policy
|
|
1648
1673
|
|
|
1649
1674
|
:param policy_id: str
|
|
1650
1675
|
The Id of the policy. This field is generated by Databricks and globally unique.
|
|
1676
|
+
:param limit_config: :class:`LimitConfig` (optional)
|
|
1677
|
+
DEPRECATED. This is redundant field as LimitConfig is part of the BudgetPolicy
|
|
1651
1678
|
:param policy: :class:`BudgetPolicy` (optional)
|
|
1652
1679
|
Contains the BudgetPolicy details.
|
|
1653
1680
|
|
|
1654
1681
|
:returns: :class:`BudgetPolicy`
|
|
1655
1682
|
"""
|
|
1656
1683
|
body = policy.as_dict()
|
|
1684
|
+
query = {}
|
|
1685
|
+
if limit_config is not None: query['limit_config'] = limit_config.as_dict()
|
|
1657
1686
|
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
1658
1687
|
|
|
1659
1688
|
res = self._api.do('PATCH',
|
|
1660
1689
|
f'/api/2.1/accounts/{self._api.account_id}/budget-policies/{policy_id}',
|
|
1690
|
+
query=query,
|
|
1661
1691
|
body=body,
|
|
1662
1692
|
headers=headers)
|
|
1663
1693
|
return BudgetPolicy.from_dict(res)
|
|
@@ -8983,6 +8983,7 @@ class CatalogsAPI:
|
|
|
8983
8983
|
if page_token is not None: query['page_token'] = page_token
|
|
8984
8984
|
headers = {'Accept': 'application/json', }
|
|
8985
8985
|
|
|
8986
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
8986
8987
|
while True:
|
|
8987
8988
|
json = self._api.do('GET', '/api/2.1/unity-catalog/catalogs', query=query, headers=headers)
|
|
8988
8989
|
if 'catalogs' in json:
|
|
@@ -9151,6 +9152,7 @@ class ConnectionsAPI:
|
|
|
9151
9152
|
if page_token is not None: query['page_token'] = page_token
|
|
9152
9153
|
headers = {'Accept': 'application/json', }
|
|
9153
9154
|
|
|
9155
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
9154
9156
|
while True:
|
|
9155
9157
|
json = self._api.do('GET', '/api/2.1/unity-catalog/connections', query=query, headers=headers)
|
|
9156
9158
|
if 'connections' in json:
|
|
@@ -9656,6 +9658,7 @@ class ExternalLocationsAPI:
|
|
|
9656
9658
|
if page_token is not None: query['page_token'] = page_token
|
|
9657
9659
|
headers = {'Accept': 'application/json', }
|
|
9658
9660
|
|
|
9661
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
9659
9662
|
while True:
|
|
9660
9663
|
json = self._api.do('GET',
|
|
9661
9664
|
'/api/2.1/unity-catalog/external-locations',
|
|
@@ -11389,6 +11392,7 @@ class SchemasAPI:
|
|
|
11389
11392
|
if page_token is not None: query['page_token'] = page_token
|
|
11390
11393
|
headers = {'Accept': 'application/json', }
|
|
11391
11394
|
|
|
11395
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
11392
11396
|
while True:
|
|
11393
11397
|
json = self._api.do('GET', '/api/2.1/unity-catalog/schemas', query=query, headers=headers)
|
|
11394
11398
|
if 'schemas' in json:
|
|
@@ -11578,6 +11582,7 @@ class StorageCredentialsAPI:
|
|
|
11578
11582
|
if page_token is not None: query['page_token'] = page_token
|
|
11579
11583
|
headers = {'Accept': 'application/json', }
|
|
11580
11584
|
|
|
11585
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
11581
11586
|
while True:
|
|
11582
11587
|
json = self._api.do('GET',
|
|
11583
11588
|
'/api/2.1/unity-catalog/storage-credentials',
|
|
@@ -11802,6 +11807,7 @@ class SystemSchemasAPI:
|
|
|
11802
11807
|
if page_token is not None: query['page_token'] = page_token
|
|
11803
11808
|
headers = {'Accept': 'application/json', }
|
|
11804
11809
|
|
|
11810
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
11805
11811
|
while True:
|
|
11806
11812
|
json = self._api.do('GET',
|
|
11807
11813
|
f'/api/2.1/unity-catalog/metastores/{metastore_id}/systemschemas',
|
|
@@ -12044,6 +12050,7 @@ class TablesAPI:
|
|
|
12044
12050
|
if schema_name is not None: query['schema_name'] = schema_name
|
|
12045
12051
|
headers = {'Accept': 'application/json', }
|
|
12046
12052
|
|
|
12053
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
12047
12054
|
while True:
|
|
12048
12055
|
json = self._api.do('GET', '/api/2.1/unity-catalog/tables', query=query, headers=headers)
|
|
12049
12056
|
if 'tables' in json:
|
|
@@ -12104,6 +12111,7 @@ class TablesAPI:
|
|
|
12104
12111
|
if table_name_pattern is not None: query['table_name_pattern'] = table_name_pattern
|
|
12105
12112
|
headers = {'Accept': 'application/json', }
|
|
12106
12113
|
|
|
12114
|
+
if "max_results" not in query: query['max_results'] = 0
|
|
12107
12115
|
while True:
|
|
12108
12116
|
json = self._api.do('GET', '/api/2.1/unity-catalog/table-summaries', query=query, headers=headers)
|
|
12109
12117
|
if 'tables' in json:
|
|
@@ -289,24 +289,11 @@ class CleanRoomAssetNotebook:
|
|
|
289
289
|
"""Base 64 representation of the notebook contents. This is the same format as returned by
|
|
290
290
|
:method:workspace/export with the format of **HTML**."""
|
|
291
291
|
|
|
292
|
-
review_state: Optional[CleanRoomNotebookReviewNotebookReviewState] = None
|
|
293
|
-
"""top-level status derived from all reviews"""
|
|
294
|
-
|
|
295
|
-
reviews: Optional[List[CleanRoomNotebookReview]] = None
|
|
296
|
-
"""All existing approvals or rejections"""
|
|
297
|
-
|
|
298
|
-
runner_collaborators: Optional[List[CleanRoomCollaborator]] = None
|
|
299
|
-
"""collaborators that can run the notebook"""
|
|
300
|
-
|
|
301
292
|
def as_dict(self) -> dict:
|
|
302
293
|
"""Serializes the CleanRoomAssetNotebook into a dictionary suitable for use as a JSON request body."""
|
|
303
294
|
body = {}
|
|
304
295
|
if self.etag is not None: body['etag'] = self.etag
|
|
305
296
|
if self.notebook_content is not None: body['notebook_content'] = self.notebook_content
|
|
306
|
-
if self.review_state is not None: body['review_state'] = self.review_state.value
|
|
307
|
-
if self.reviews: body['reviews'] = [v.as_dict() for v in self.reviews]
|
|
308
|
-
if self.runner_collaborators:
|
|
309
|
-
body['runner_collaborators'] = [v.as_dict() for v in self.runner_collaborators]
|
|
310
297
|
return body
|
|
311
298
|
|
|
312
299
|
def as_shallow_dict(self) -> dict:
|
|
@@ -314,19 +301,12 @@ class CleanRoomAssetNotebook:
|
|
|
314
301
|
body = {}
|
|
315
302
|
if self.etag is not None: body['etag'] = self.etag
|
|
316
303
|
if self.notebook_content is not None: body['notebook_content'] = self.notebook_content
|
|
317
|
-
if self.review_state is not None: body['review_state'] = self.review_state
|
|
318
|
-
if self.reviews: body['reviews'] = self.reviews
|
|
319
|
-
if self.runner_collaborators: body['runner_collaborators'] = self.runner_collaborators
|
|
320
304
|
return body
|
|
321
305
|
|
|
322
306
|
@classmethod
|
|
323
307
|
def from_dict(cls, d: Dict[str, any]) -> CleanRoomAssetNotebook:
|
|
324
308
|
"""Deserializes the CleanRoomAssetNotebook from a dictionary."""
|
|
325
|
-
return cls(etag=d.get('etag', None),
|
|
326
|
-
notebook_content=d.get('notebook_content', None),
|
|
327
|
-
review_state=_enum(d, 'review_state', CleanRoomNotebookReviewNotebookReviewState),
|
|
328
|
-
reviews=_repeated_dict(d, 'reviews', CleanRoomNotebookReview),
|
|
329
|
-
runner_collaborators=_repeated_dict(d, 'runner_collaborators', CleanRoomCollaborator))
|
|
309
|
+
return cls(etag=d.get('etag', None), notebook_content=d.get('notebook_content', None))
|
|
330
310
|
|
|
331
311
|
|
|
332
312
|
class CleanRoomAssetStatusEnum(Enum):
|
|
@@ -531,56 +511,6 @@ class CleanRoomCollaborator:
|
|
|
531
511
|
organization_name=d.get('organization_name', None))
|
|
532
512
|
|
|
533
513
|
|
|
534
|
-
@dataclass
|
|
535
|
-
class CleanRoomNotebookReview:
|
|
536
|
-
comment: Optional[str] = None
|
|
537
|
-
"""review comment"""
|
|
538
|
-
|
|
539
|
-
created_at_millis: Optional[int] = None
|
|
540
|
-
"""timestamp of when the review was submitted"""
|
|
541
|
-
|
|
542
|
-
review_state: Optional[CleanRoomNotebookReviewNotebookReviewState] = None
|
|
543
|
-
"""review outcome"""
|
|
544
|
-
|
|
545
|
-
reviewer_collaborator_alias: Optional[str] = None
|
|
546
|
-
"""collaborator alias of the reviewer"""
|
|
547
|
-
|
|
548
|
-
def as_dict(self) -> dict:
|
|
549
|
-
"""Serializes the CleanRoomNotebookReview into a dictionary suitable for use as a JSON request body."""
|
|
550
|
-
body = {}
|
|
551
|
-
if self.comment is not None: body['comment'] = self.comment
|
|
552
|
-
if self.created_at_millis is not None: body['created_at_millis'] = self.created_at_millis
|
|
553
|
-
if self.review_state is not None: body['review_state'] = self.review_state.value
|
|
554
|
-
if self.reviewer_collaborator_alias is not None:
|
|
555
|
-
body['reviewer_collaborator_alias'] = self.reviewer_collaborator_alias
|
|
556
|
-
return body
|
|
557
|
-
|
|
558
|
-
def as_shallow_dict(self) -> dict:
|
|
559
|
-
"""Serializes the CleanRoomNotebookReview into a shallow dictionary of its immediate attributes."""
|
|
560
|
-
body = {}
|
|
561
|
-
if self.comment is not None: body['comment'] = self.comment
|
|
562
|
-
if self.created_at_millis is not None: body['created_at_millis'] = self.created_at_millis
|
|
563
|
-
if self.review_state is not None: body['review_state'] = self.review_state
|
|
564
|
-
if self.reviewer_collaborator_alias is not None:
|
|
565
|
-
body['reviewer_collaborator_alias'] = self.reviewer_collaborator_alias
|
|
566
|
-
return body
|
|
567
|
-
|
|
568
|
-
@classmethod
|
|
569
|
-
def from_dict(cls, d: Dict[str, any]) -> CleanRoomNotebookReview:
|
|
570
|
-
"""Deserializes the CleanRoomNotebookReview from a dictionary."""
|
|
571
|
-
return cls(comment=d.get('comment', None),
|
|
572
|
-
created_at_millis=d.get('created_at_millis', None),
|
|
573
|
-
review_state=_enum(d, 'review_state', CleanRoomNotebookReviewNotebookReviewState),
|
|
574
|
-
reviewer_collaborator_alias=d.get('reviewer_collaborator_alias', None))
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
class CleanRoomNotebookReviewNotebookReviewState(Enum):
|
|
578
|
-
|
|
579
|
-
APPROVED = 'APPROVED'
|
|
580
|
-
PENDING = 'PENDING'
|
|
581
|
-
REJECTED = 'REJECTED'
|
|
582
|
-
|
|
583
|
-
|
|
584
514
|
@dataclass
|
|
585
515
|
class CleanRoomNotebookTaskRun:
|
|
586
516
|
"""Stores information about a single task run."""
|
|
@@ -637,11 +637,11 @@ class ClusterAttributes:
|
|
|
637
637
|
a set of default values will be used."""
|
|
638
638
|
|
|
639
639
|
cluster_log_conf: Optional[ClusterLogConf] = None
|
|
640
|
-
"""The configuration for delivering spark logs to a long-term storage destination.
|
|
641
|
-
destinations (
|
|
642
|
-
If the conf is given, the logs will be delivered to the destination
|
|
643
|
-
destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
644
|
-
executor logs is `$destination/$clusterId/executor`."""
|
|
640
|
+
"""The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
641
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
642
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination
|
|
643
|
+
every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
644
|
+
destination of executor logs is `$destination/$clusterId/executor`."""
|
|
645
645
|
|
|
646
646
|
cluster_name: Optional[str] = None
|
|
647
647
|
"""Cluster name requested by the user. This doesn't have to be unique. If not specified at
|
|
@@ -947,11 +947,11 @@ class ClusterDetails:
|
|
|
947
947
|
while each new cluster has a globally unique id."""
|
|
948
948
|
|
|
949
949
|
cluster_log_conf: Optional[ClusterLogConf] = None
|
|
950
|
-
"""The configuration for delivering spark logs to a long-term storage destination.
|
|
951
|
-
destinations (
|
|
952
|
-
If the conf is given, the logs will be delivered to the destination
|
|
953
|
-
destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
954
|
-
executor logs is `$destination/$clusterId/executor`."""
|
|
950
|
+
"""The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
951
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
952
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination
|
|
953
|
+
every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
954
|
+
destination of executor logs is `$destination/$clusterId/executor`."""
|
|
955
955
|
|
|
956
956
|
cluster_log_status: Optional[LogSyncStatus] = None
|
|
957
957
|
"""Cluster log delivery status."""
|
|
@@ -1428,11 +1428,16 @@ class ClusterLogConf:
|
|
|
1428
1428
|
access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to
|
|
1429
1429
|
write data to the s3 destination."""
|
|
1430
1430
|
|
|
1431
|
+
volumes: Optional[VolumesStorageInfo] = None
|
|
1432
|
+
"""destination needs to be provided. e.g. `{ "volumes" : { "destination" :
|
|
1433
|
+
"/Volumes/catalog/schema/volume/cluster_log" } }`"""
|
|
1434
|
+
|
|
1431
1435
|
def as_dict(self) -> dict:
|
|
1432
1436
|
"""Serializes the ClusterLogConf into a dictionary suitable for use as a JSON request body."""
|
|
1433
1437
|
body = {}
|
|
1434
1438
|
if self.dbfs: body['dbfs'] = self.dbfs.as_dict()
|
|
1435
1439
|
if self.s3: body['s3'] = self.s3.as_dict()
|
|
1440
|
+
if self.volumes: body['volumes'] = self.volumes.as_dict()
|
|
1436
1441
|
return body
|
|
1437
1442
|
|
|
1438
1443
|
def as_shallow_dict(self) -> dict:
|
|
@@ -1440,12 +1445,15 @@ class ClusterLogConf:
|
|
|
1440
1445
|
body = {}
|
|
1441
1446
|
if self.dbfs: body['dbfs'] = self.dbfs
|
|
1442
1447
|
if self.s3: body['s3'] = self.s3
|
|
1448
|
+
if self.volumes: body['volumes'] = self.volumes
|
|
1443
1449
|
return body
|
|
1444
1450
|
|
|
1445
1451
|
@classmethod
|
|
1446
1452
|
def from_dict(cls, d: Dict[str, any]) -> ClusterLogConf:
|
|
1447
1453
|
"""Deserializes the ClusterLogConf from a dictionary."""
|
|
1448
|
-
return cls(dbfs=_from_dict(d, 'dbfs', DbfsStorageInfo),
|
|
1454
|
+
return cls(dbfs=_from_dict(d, 'dbfs', DbfsStorageInfo),
|
|
1455
|
+
s3=_from_dict(d, 's3', S3StorageInfo),
|
|
1456
|
+
volumes=_from_dict(d, 'volumes', VolumesStorageInfo))
|
|
1449
1457
|
|
|
1450
1458
|
|
|
1451
1459
|
@dataclass
|
|
@@ -1918,11 +1926,11 @@ class ClusterSpec:
|
|
|
1918
1926
|
a set of default values will be used."""
|
|
1919
1927
|
|
|
1920
1928
|
cluster_log_conf: Optional[ClusterLogConf] = None
|
|
1921
|
-
"""The configuration for delivering spark logs to a long-term storage destination.
|
|
1922
|
-
destinations (
|
|
1923
|
-
If the conf is given, the logs will be delivered to the destination
|
|
1924
|
-
destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
1925
|
-
executor logs is `$destination/$clusterId/executor`."""
|
|
1929
|
+
"""The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
1930
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
1931
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination
|
|
1932
|
+
every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
1933
|
+
destination of executor logs is `$destination/$clusterId/executor`."""
|
|
1926
1934
|
|
|
1927
1935
|
cluster_name: Optional[str] = None
|
|
1928
1936
|
"""Cluster name requested by the user. This doesn't have to be unique. If not specified at
|
|
@@ -2334,11 +2342,11 @@ class CreateCluster:
|
|
|
2334
2342
|
cluster."""
|
|
2335
2343
|
|
|
2336
2344
|
cluster_log_conf: Optional[ClusterLogConf] = None
|
|
2337
|
-
"""The configuration for delivering spark logs to a long-term storage destination.
|
|
2338
|
-
destinations (
|
|
2339
|
-
If the conf is given, the logs will be delivered to the destination
|
|
2340
|
-
destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
2341
|
-
executor logs is `$destination/$clusterId/executor`."""
|
|
2345
|
+
"""The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
2346
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
2347
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination
|
|
2348
|
+
every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
2349
|
+
destination of executor logs is `$destination/$clusterId/executor`."""
|
|
2342
2350
|
|
|
2343
2351
|
cluster_name: Optional[str] = None
|
|
2344
2352
|
"""Cluster name requested by the user. This doesn't have to be unique. If not specified at
|
|
@@ -3469,11 +3477,11 @@ class EditCluster:
|
|
|
3469
3477
|
a set of default values will be used."""
|
|
3470
3478
|
|
|
3471
3479
|
cluster_log_conf: Optional[ClusterLogConf] = None
|
|
3472
|
-
"""The configuration for delivering spark logs to a long-term storage destination.
|
|
3473
|
-
destinations (
|
|
3474
|
-
If the conf is given, the logs will be delivered to the destination
|
|
3475
|
-
destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
3476
|
-
executor logs is `$destination/$clusterId/executor`."""
|
|
3480
|
+
"""The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
3481
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
3482
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination
|
|
3483
|
+
every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
3484
|
+
destination of executor logs is `$destination/$clusterId/executor`."""
|
|
3477
3485
|
|
|
3478
3486
|
cluster_name: Optional[str] = None
|
|
3479
3487
|
"""Cluster name requested by the user. This doesn't have to be unique. If not specified at
|
|
@@ -7773,11 +7781,11 @@ class UpdateClusterResource:
|
|
|
7773
7781
|
a set of default values will be used."""
|
|
7774
7782
|
|
|
7775
7783
|
cluster_log_conf: Optional[ClusterLogConf] = None
|
|
7776
|
-
"""The configuration for delivering spark logs to a long-term storage destination.
|
|
7777
|
-
destinations (
|
|
7778
|
-
If the conf is given, the logs will be delivered to the destination
|
|
7779
|
-
destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
7780
|
-
executor logs is `$destination/$clusterId/executor`."""
|
|
7784
|
+
"""The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
7785
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
7786
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination
|
|
7787
|
+
every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the
|
|
7788
|
+
destination of executor logs is `$destination/$clusterId/executor`."""
|
|
7781
7789
|
|
|
7782
7790
|
cluster_name: Optional[str] = None
|
|
7783
7791
|
"""Cluster name requested by the user. This doesn't have to be unique. If not specified at
|
|
@@ -8077,7 +8085,7 @@ class UpdateResponse:
|
|
|
8077
8085
|
@dataclass
|
|
8078
8086
|
class VolumesStorageInfo:
|
|
8079
8087
|
destination: str
|
|
8080
|
-
"""Unity Catalog
|
|
8088
|
+
"""Unity Catalog volumes file destination, e.g. `/Volumes/catalog/schema/volume/dir/file`"""
|
|
8081
8089
|
|
|
8082
8090
|
def as_dict(self) -> dict:
|
|
8083
8091
|
"""Serializes the VolumesStorageInfo into a dictionary suitable for use as a JSON request body."""
|
|
@@ -8619,11 +8627,11 @@ class ClustersAPI:
|
|
|
8619
8627
|
:param clone_from: :class:`CloneCluster` (optional)
|
|
8620
8628
|
When specified, this clones libraries from a source cluster during the creation of a new cluster.
|
|
8621
8629
|
:param cluster_log_conf: :class:`ClusterLogConf` (optional)
|
|
8622
|
-
The configuration for delivering spark logs to a long-term storage destination.
|
|
8623
|
-
destinations (
|
|
8624
|
-
the conf is given, the logs will be delivered to the destination every
|
|
8625
|
-
driver logs is `$destination/$clusterId/driver`, while the destination
|
|
8626
|
-
`$destination/$clusterId/executor`.
|
|
8630
|
+
The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
8631
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
8632
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination every
|
|
8633
|
+
`5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination
|
|
8634
|
+
of executor logs is `$destination/$clusterId/executor`.
|
|
8627
8635
|
:param cluster_name: str (optional)
|
|
8628
8636
|
Cluster name requested by the user. This doesn't have to be unique. If not specified at creation,
|
|
8629
8637
|
the cluster name will be an empty string.
|
|
@@ -8952,11 +8960,11 @@ class ClustersAPI:
|
|
|
8952
8960
|
Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a
|
|
8953
8961
|
set of default values will be used.
|
|
8954
8962
|
:param cluster_log_conf: :class:`ClusterLogConf` (optional)
|
|
8955
|
-
The configuration for delivering spark logs to a long-term storage destination.
|
|
8956
|
-
destinations (
|
|
8957
|
-
the conf is given, the logs will be delivered to the destination every
|
|
8958
|
-
driver logs is `$destination/$clusterId/driver`, while the destination
|
|
8959
|
-
`$destination/$clusterId/executor`.
|
|
8963
|
+
The configuration for delivering spark logs to a long-term storage destination. Three kinds of
|
|
8964
|
+
destinations (DBFS, S3 and Unity Catalog volumes) are supported. Only one destination can be
|
|
8965
|
+
specified for one cluster. If the conf is given, the logs will be delivered to the destination every
|
|
8966
|
+
`5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination
|
|
8967
|
+
of executor logs is `$destination/$clusterId/executor`.
|
|
8960
8968
|
:param cluster_name: str (optional)
|
|
8961
8969
|
Cluster name requested by the user. This doesn't have to be unique. If not specified at creation,
|
|
8962
8970
|
the cluster name will be an empty string.
|