databricks-sdk 0.41.0__py3-none-any.whl → 0.42.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.
- databricks/sdk/__init__.py +252 -238
- databricks/sdk/_base_client.py +20 -21
- databricks/sdk/credentials_provider.py +12 -6
- databricks/sdk/mixins/open_ai_client.py +25 -10
- databricks/sdk/retries.py +5 -1
- databricks/sdk/service/billing.py +348 -0
- databricks/sdk/service/catalog.py +15 -62
- databricks/sdk/service/cleanrooms.py +71 -1
- databricks/sdk/service/compute.py +36 -0
- databricks/sdk/service/dashboards.py +5 -0
- databricks/sdk/service/jobs.py +85 -1
- databricks/sdk/service/oauth2.py +41 -5
- databricks/sdk/service/serving.py +34 -40
- databricks/sdk/service/settings.py +206 -0
- databricks/sdk/useragent.py +54 -0
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.41.0.dist-info → databricks_sdk-0.42.0.dist-info}/METADATA +1 -1
- {databricks_sdk-0.41.0.dist-info → databricks_sdk-0.42.0.dist-info}/RECORD +22 -22
- {databricks_sdk-0.41.0.dist-info → databricks_sdk-0.42.0.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.41.0.dist-info → databricks_sdk-0.42.0.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.41.0.dist-info → databricks_sdk-0.42.0.dist-info}/WHEEL +0 -0
- {databricks_sdk-0.41.0.dist-info → databricks_sdk-0.42.0.dist-info}/top_level.txt +0 -0
databricks/sdk/_base_client.py
CHANGED
|
@@ -159,16 +159,29 @@ class _BaseClient:
|
|
|
159
159
|
if isinstance(data, (str, bytes)):
|
|
160
160
|
data = io.BytesIO(data.encode('utf-8') if isinstance(data, str) else data)
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# re-read already read data from the body.
|
|
165
|
-
if data is not None and not self._is_seekable_stream(data):
|
|
166
|
-
logger.debug(f"Retry disabled for non-seekable stream: type={type(data)}")
|
|
167
|
-
call = self._perform
|
|
168
|
-
else:
|
|
162
|
+
if not data:
|
|
163
|
+
# The request is not a stream.
|
|
169
164
|
call = retried(timeout=timedelta(seconds=self._retry_timeout_seconds),
|
|
170
165
|
is_retryable=self._is_retryable,
|
|
171
166
|
clock=self._clock)(self._perform)
|
|
167
|
+
elif self._is_seekable_stream(data):
|
|
168
|
+
# Keep track of the initial position of the stream so that we can rewind to it
|
|
169
|
+
# if we need to retry the request.
|
|
170
|
+
initial_data_position = data.tell()
|
|
171
|
+
|
|
172
|
+
def rewind():
|
|
173
|
+
logger.debug(f"Rewinding input data to offset {initial_data_position} before retry")
|
|
174
|
+
data.seek(initial_data_position)
|
|
175
|
+
|
|
176
|
+
call = retried(timeout=timedelta(seconds=self._retry_timeout_seconds),
|
|
177
|
+
is_retryable=self._is_retryable,
|
|
178
|
+
clock=self._clock,
|
|
179
|
+
before_retry=rewind)(self._perform)
|
|
180
|
+
else:
|
|
181
|
+
# Do not retry if the stream is not seekable. This is necessary to avoid bugs
|
|
182
|
+
# where the retry doesn't re-read already read data from the stream.
|
|
183
|
+
logger.debug(f"Retry disabled for non-seekable stream: type={type(data)}")
|
|
184
|
+
call = self._perform
|
|
172
185
|
|
|
173
186
|
response = call(method,
|
|
174
187
|
url,
|
|
@@ -249,12 +262,6 @@ class _BaseClient:
|
|
|
249
262
|
files=None,
|
|
250
263
|
data=None,
|
|
251
264
|
auth: Callable[[requests.PreparedRequest], requests.PreparedRequest] = None):
|
|
252
|
-
# Keep track of the initial position of the stream so that we can rewind it if
|
|
253
|
-
# we need to retry the request.
|
|
254
|
-
initial_data_position = 0
|
|
255
|
-
if self._is_seekable_stream(data):
|
|
256
|
-
initial_data_position = data.tell()
|
|
257
|
-
|
|
258
265
|
response = self._session.request(method,
|
|
259
266
|
url,
|
|
260
267
|
params=self._fix_query_string(query),
|
|
@@ -266,16 +273,8 @@ class _BaseClient:
|
|
|
266
273
|
stream=raw,
|
|
267
274
|
timeout=self._http_timeout_seconds)
|
|
268
275
|
self._record_request_log(response, raw=raw or data is not None or files is not None)
|
|
269
|
-
|
|
270
276
|
error = self._error_parser.get_api_error(response)
|
|
271
277
|
if error is not None:
|
|
272
|
-
# If the request body is a seekable stream, rewind it so that it is ready
|
|
273
|
-
# to be read again in case of a retry.
|
|
274
|
-
#
|
|
275
|
-
# TODO: This should be moved into a "before-retry" hook to avoid one
|
|
276
|
-
# unnecessary seek on the last failed retry before aborting.
|
|
277
|
-
if self._is_seekable_stream(data):
|
|
278
|
-
data.seek(initial_data_position)
|
|
279
278
|
raise error from None
|
|
280
279
|
|
|
281
280
|
return response
|
|
@@ -676,12 +676,18 @@ class MetadataServiceTokenSource(Refreshable):
|
|
|
676
676
|
self.host = cfg.host
|
|
677
677
|
|
|
678
678
|
def refresh(self) -> Token:
|
|
679
|
-
resp = requests.get(
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
679
|
+
resp = requests.get(
|
|
680
|
+
self.url,
|
|
681
|
+
timeout=self._metadata_service_timeout,
|
|
682
|
+
headers={
|
|
683
|
+
self.METADATA_SERVICE_VERSION_HEADER: self.METADATA_SERVICE_VERSION,
|
|
684
|
+
self.METADATA_SERVICE_HOST_HEADER: self.host
|
|
685
|
+
},
|
|
686
|
+
proxies={
|
|
687
|
+
# Explicitly exclude localhost from being proxied. This is necessary
|
|
688
|
+
# for Metadata URLs which typically point to localhost.
|
|
689
|
+
"no_proxy": "localhost,127.0.0.1"
|
|
690
|
+
})
|
|
685
691
|
json_resp: dict[str, Union[str, float]] = resp.json()
|
|
686
692
|
access_token = json_resp.get("access_token", None)
|
|
687
693
|
if access_token is None:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import json as js
|
|
2
2
|
from typing import Dict, Optional
|
|
3
3
|
|
|
4
|
+
from requests import Response
|
|
5
|
+
|
|
4
6
|
from databricks.sdk.service.serving import (ExternalFunctionRequestHttpMethod,
|
|
5
|
-
ExternalFunctionResponse,
|
|
6
7
|
ServingEndpointsAPI)
|
|
7
8
|
|
|
8
9
|
|
|
@@ -63,7 +64,7 @@ class ServingEndpointsExt(ServingEndpointsAPI):
|
|
|
63
64
|
*,
|
|
64
65
|
headers: Optional[Dict[str, str]] = None,
|
|
65
66
|
json: Optional[Dict[str, str]] = None,
|
|
66
|
-
params: Optional[Dict[str, str]] = None) ->
|
|
67
|
+
params: Optional[Dict[str, str]] = None) -> Response:
|
|
67
68
|
"""Make external services call using the credentials stored in UC Connection.
|
|
68
69
|
**NOTE:** Experimental: This API may change or be removed in a future release without warning.
|
|
69
70
|
:param conn: str
|
|
@@ -79,13 +80,27 @@ class ServingEndpointsExt(ServingEndpointsAPI):
|
|
|
79
80
|
JSON payload for the request.
|
|
80
81
|
:param params: Dict[str,str] (optional)
|
|
81
82
|
Query parameters for the request.
|
|
82
|
-
:returns: :class:`
|
|
83
|
+
:returns: :class:`Response`
|
|
83
84
|
"""
|
|
85
|
+
response = Response()
|
|
86
|
+
response.status_code = 200
|
|
87
|
+
server_response = super().http_request(connection_name=conn,
|
|
88
|
+
method=method,
|
|
89
|
+
path=path,
|
|
90
|
+
headers=js.dumps(headers) if headers is not None else None,
|
|
91
|
+
json=js.dumps(json) if json is not None else None,
|
|
92
|
+
params=js.dumps(params) if params is not None else None)
|
|
93
|
+
|
|
94
|
+
# Read the content from the HttpRequestResponse object
|
|
95
|
+
if hasattr(server_response, "contents") and hasattr(server_response.contents, "read"):
|
|
96
|
+
raw_content = server_response.contents.read() # Read the bytes
|
|
97
|
+
else:
|
|
98
|
+
raise ValueError("Invalid response from the server.")
|
|
99
|
+
|
|
100
|
+
# Set the raw content
|
|
101
|
+
if isinstance(raw_content, bytes):
|
|
102
|
+
response._content = raw_content
|
|
103
|
+
else:
|
|
104
|
+
raise ValueError("Contents must be bytes.")
|
|
84
105
|
|
|
85
|
-
return
|
|
86
|
-
method=method,
|
|
87
|
-
path=path,
|
|
88
|
-
headers=js.dumps(headers),
|
|
89
|
-
json=js.dumps(json),
|
|
90
|
-
params=js.dumps(params),
|
|
91
|
-
)
|
|
106
|
+
return response
|
databricks/sdk/retries.py
CHANGED
|
@@ -13,7 +13,8 @@ def retried(*,
|
|
|
13
13
|
on: Sequence[Type[BaseException]] = None,
|
|
14
14
|
is_retryable: Callable[[BaseException], Optional[str]] = None,
|
|
15
15
|
timeout=timedelta(minutes=20),
|
|
16
|
-
clock: Clock = None
|
|
16
|
+
clock: Clock = None,
|
|
17
|
+
before_retry: Callable = None):
|
|
17
18
|
has_allowlist = on is not None
|
|
18
19
|
has_callback = is_retryable is not None
|
|
19
20
|
if not (has_allowlist or has_callback) or (has_allowlist and has_callback):
|
|
@@ -54,6 +55,9 @@ def retried(*,
|
|
|
54
55
|
raise err
|
|
55
56
|
|
|
56
57
|
logger.debug(f'Retrying: {retry_reason} (sleeping ~{sleep}s)')
|
|
58
|
+
if before_retry:
|
|
59
|
+
before_retry()
|
|
60
|
+
|
|
57
61
|
clock.sleep(sleep + random())
|
|
58
62
|
attempt += 1
|
|
59
63
|
raise TimeoutError(f'Timed out after {timeout}') from last_err
|
|
@@ -11,6 +11,8 @@ from ._internal import _enum, _from_dict, _repeated_dict
|
|
|
11
11
|
|
|
12
12
|
_LOG = logging.getLogger('databricks.sdk')
|
|
13
13
|
|
|
14
|
+
from databricks.sdk.service import compute
|
|
15
|
+
|
|
14
16
|
# all definitions in this file are in alphabetical order
|
|
15
17
|
|
|
16
18
|
|
|
@@ -311,6 +313,44 @@ class BudgetConfigurationFilterWorkspaceIdClause:
|
|
|
311
313
|
values=d.get('values', None))
|
|
312
314
|
|
|
313
315
|
|
|
316
|
+
@dataclass
|
|
317
|
+
class BudgetPolicy:
|
|
318
|
+
"""Contains the BudgetPolicy details."""
|
|
319
|
+
|
|
320
|
+
policy_id: str
|
|
321
|
+
"""The Id of the policy. This field is generated by Databricks and globally unique."""
|
|
322
|
+
|
|
323
|
+
custom_tags: Optional[List[compute.CustomPolicyTag]] = None
|
|
324
|
+
"""A list of tags defined by the customer. At most 20 entries are allowed per policy."""
|
|
325
|
+
|
|
326
|
+
policy_name: Optional[str] = None
|
|
327
|
+
"""The name of the policy. - Must be unique among active policies. - Can contain only characters
|
|
328
|
+
from the ISO 8859-1 (latin1) set."""
|
|
329
|
+
|
|
330
|
+
def as_dict(self) -> dict:
|
|
331
|
+
"""Serializes the BudgetPolicy into a dictionary suitable for use as a JSON request body."""
|
|
332
|
+
body = {}
|
|
333
|
+
if self.custom_tags: body['custom_tags'] = [v.as_dict() for v in self.custom_tags]
|
|
334
|
+
if self.policy_id is not None: body['policy_id'] = self.policy_id
|
|
335
|
+
if self.policy_name is not None: body['policy_name'] = self.policy_name
|
|
336
|
+
return body
|
|
337
|
+
|
|
338
|
+
def as_shallow_dict(self) -> dict:
|
|
339
|
+
"""Serializes the BudgetPolicy into a shallow dictionary of its immediate attributes."""
|
|
340
|
+
body = {}
|
|
341
|
+
if self.custom_tags: body['custom_tags'] = self.custom_tags
|
|
342
|
+
if self.policy_id is not None: body['policy_id'] = self.policy_id
|
|
343
|
+
if self.policy_name is not None: body['policy_name'] = self.policy_name
|
|
344
|
+
return body
|
|
345
|
+
|
|
346
|
+
@classmethod
|
|
347
|
+
def from_dict(cls, d: Dict[str, any]) -> BudgetPolicy:
|
|
348
|
+
"""Deserializes the BudgetPolicy from a dictionary."""
|
|
349
|
+
return cls(custom_tags=_repeated_dict(d, 'custom_tags', compute.CustomPolicyTag),
|
|
350
|
+
policy_id=d.get('policy_id', None),
|
|
351
|
+
policy_name=d.get('policy_name', None))
|
|
352
|
+
|
|
353
|
+
|
|
314
354
|
@dataclass
|
|
315
355
|
class CreateBillingUsageDashboardRequest:
|
|
316
356
|
dashboard_type: Optional[UsageDashboardType] = None
|
|
@@ -536,6 +576,45 @@ class CreateBudgetConfigurationResponse:
|
|
|
536
576
|
return cls(budget=_from_dict(d, 'budget', BudgetConfiguration))
|
|
537
577
|
|
|
538
578
|
|
|
579
|
+
@dataclass
|
|
580
|
+
class CreateBudgetPolicyRequest:
|
|
581
|
+
"""A request to create a BudgetPolicy."""
|
|
582
|
+
|
|
583
|
+
custom_tags: Optional[List[compute.CustomPolicyTag]] = None
|
|
584
|
+
"""A list of tags defined by the customer. At most 40 entries are allowed per policy."""
|
|
585
|
+
|
|
586
|
+
policy_name: Optional[str] = None
|
|
587
|
+
"""The name of the policy. - Must be unique among active policies. - Can contain only characters of
|
|
588
|
+
0-9, a-z, A-Z, -, =, ., :, /, @, _, +, whitespace."""
|
|
589
|
+
|
|
590
|
+
request_id: Optional[str] = None
|
|
591
|
+
"""A unique identifier for this request. Restricted to 36 ASCII characters. A random UUID is
|
|
592
|
+
recommended. This request is only idempotent if a `request_id` is provided."""
|
|
593
|
+
|
|
594
|
+
def as_dict(self) -> dict:
|
|
595
|
+
"""Serializes the CreateBudgetPolicyRequest into a dictionary suitable for use as a JSON request body."""
|
|
596
|
+
body = {}
|
|
597
|
+
if self.custom_tags: body['custom_tags'] = [v.as_dict() for v in self.custom_tags]
|
|
598
|
+
if self.policy_name is not None: body['policy_name'] = self.policy_name
|
|
599
|
+
if self.request_id is not None: body['request_id'] = self.request_id
|
|
600
|
+
return body
|
|
601
|
+
|
|
602
|
+
def as_shallow_dict(self) -> dict:
|
|
603
|
+
"""Serializes the CreateBudgetPolicyRequest into a shallow dictionary of its immediate attributes."""
|
|
604
|
+
body = {}
|
|
605
|
+
if self.custom_tags: body['custom_tags'] = self.custom_tags
|
|
606
|
+
if self.policy_name is not None: body['policy_name'] = self.policy_name
|
|
607
|
+
if self.request_id is not None: body['request_id'] = self.request_id
|
|
608
|
+
return body
|
|
609
|
+
|
|
610
|
+
@classmethod
|
|
611
|
+
def from_dict(cls, d: Dict[str, any]) -> CreateBudgetPolicyRequest:
|
|
612
|
+
"""Deserializes the CreateBudgetPolicyRequest from a dictionary."""
|
|
613
|
+
return cls(custom_tags=_repeated_dict(d, 'custom_tags', compute.CustomPolicyTag),
|
|
614
|
+
policy_name=d.get('policy_name', None),
|
|
615
|
+
request_id=d.get('request_id', None))
|
|
616
|
+
|
|
617
|
+
|
|
539
618
|
@dataclass
|
|
540
619
|
class CreateLogDeliveryConfigurationParams:
|
|
541
620
|
log_type: LogType
|
|
@@ -670,6 +749,25 @@ class DeleteBudgetConfigurationResponse:
|
|
|
670
749
|
return cls()
|
|
671
750
|
|
|
672
751
|
|
|
752
|
+
@dataclass
|
|
753
|
+
class DeleteResponse:
|
|
754
|
+
|
|
755
|
+
def as_dict(self) -> dict:
|
|
756
|
+
"""Serializes the DeleteResponse into a dictionary suitable for use as a JSON request body."""
|
|
757
|
+
body = {}
|
|
758
|
+
return body
|
|
759
|
+
|
|
760
|
+
def as_shallow_dict(self) -> dict:
|
|
761
|
+
"""Serializes the DeleteResponse into a shallow dictionary of its immediate attributes."""
|
|
762
|
+
body = {}
|
|
763
|
+
return body
|
|
764
|
+
|
|
765
|
+
@classmethod
|
|
766
|
+
def from_dict(cls, d: Dict[str, any]) -> DeleteResponse:
|
|
767
|
+
"""Deserializes the DeleteResponse from a dictionary."""
|
|
768
|
+
return cls()
|
|
769
|
+
|
|
770
|
+
|
|
673
771
|
class DeliveryStatus(Enum):
|
|
674
772
|
"""The status string for log delivery. Possible values are: * `CREATED`: There were no log delivery
|
|
675
773
|
attempts since the config was created. * `SUCCEEDED`: The latest attempt of log delivery has
|
|
@@ -708,6 +806,44 @@ class DownloadResponse:
|
|
|
708
806
|
return cls(contents=d.get('contents', None))
|
|
709
807
|
|
|
710
808
|
|
|
809
|
+
@dataclass
|
|
810
|
+
class Filter:
|
|
811
|
+
"""Structured representation of a filter to be applied to a list of policies. All specified filters
|
|
812
|
+
will be applied in conjunction."""
|
|
813
|
+
|
|
814
|
+
creator_user_id: Optional[int] = None
|
|
815
|
+
"""The policy creator user id to be filtered on. If unspecified, all policies will be returned."""
|
|
816
|
+
|
|
817
|
+
creator_user_name: Optional[str] = None
|
|
818
|
+
"""The policy creator user name to be filtered on. If unspecified, all policies will be returned."""
|
|
819
|
+
|
|
820
|
+
policy_name: Optional[str] = None
|
|
821
|
+
"""The partial name of policies to be filtered on. If unspecified, all policies will be returned."""
|
|
822
|
+
|
|
823
|
+
def as_dict(self) -> dict:
|
|
824
|
+
"""Serializes the Filter into a dictionary suitable for use as a JSON request body."""
|
|
825
|
+
body = {}
|
|
826
|
+
if self.creator_user_id is not None: body['creator_user_id'] = self.creator_user_id
|
|
827
|
+
if self.creator_user_name is not None: body['creator_user_name'] = self.creator_user_name
|
|
828
|
+
if self.policy_name is not None: body['policy_name'] = self.policy_name
|
|
829
|
+
return body
|
|
830
|
+
|
|
831
|
+
def as_shallow_dict(self) -> dict:
|
|
832
|
+
"""Serializes the Filter into a shallow dictionary of its immediate attributes."""
|
|
833
|
+
body = {}
|
|
834
|
+
if self.creator_user_id is not None: body['creator_user_id'] = self.creator_user_id
|
|
835
|
+
if self.creator_user_name is not None: body['creator_user_name'] = self.creator_user_name
|
|
836
|
+
if self.policy_name is not None: body['policy_name'] = self.policy_name
|
|
837
|
+
return body
|
|
838
|
+
|
|
839
|
+
@classmethod
|
|
840
|
+
def from_dict(cls, d: Dict[str, any]) -> Filter:
|
|
841
|
+
"""Deserializes the Filter from a dictionary."""
|
|
842
|
+
return cls(creator_user_id=d.get('creator_user_id', None),
|
|
843
|
+
creator_user_name=d.get('creator_user_name', None),
|
|
844
|
+
policy_name=d.get('policy_name', None))
|
|
845
|
+
|
|
846
|
+
|
|
711
847
|
@dataclass
|
|
712
848
|
class GetBillingUsageDashboardResponse:
|
|
713
849
|
dashboard_id: Optional[str] = None
|
|
@@ -787,6 +923,44 @@ class ListBudgetConfigurationsResponse:
|
|
|
787
923
|
next_page_token=d.get('next_page_token', None))
|
|
788
924
|
|
|
789
925
|
|
|
926
|
+
@dataclass
|
|
927
|
+
class ListBudgetPoliciesResponse:
|
|
928
|
+
"""A list of policies."""
|
|
929
|
+
|
|
930
|
+
next_page_token: Optional[str] = None
|
|
931
|
+
"""A token that can be sent as `page_token` to retrieve the next page. If this field is omitted,
|
|
932
|
+
there are no subsequent pages."""
|
|
933
|
+
|
|
934
|
+
policies: Optional[List[BudgetPolicy]] = None
|
|
935
|
+
|
|
936
|
+
previous_page_token: Optional[str] = None
|
|
937
|
+
"""A token that can be sent as `page_token` to retrieve the previous page. In this field is
|
|
938
|
+
omitted, there are no previous pages."""
|
|
939
|
+
|
|
940
|
+
def as_dict(self) -> dict:
|
|
941
|
+
"""Serializes the ListBudgetPoliciesResponse into a dictionary suitable for use as a JSON request body."""
|
|
942
|
+
body = {}
|
|
943
|
+
if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
|
|
944
|
+
if self.policies: body['policies'] = [v.as_dict() for v in self.policies]
|
|
945
|
+
if self.previous_page_token is not None: body['previous_page_token'] = self.previous_page_token
|
|
946
|
+
return body
|
|
947
|
+
|
|
948
|
+
def as_shallow_dict(self) -> dict:
|
|
949
|
+
"""Serializes the ListBudgetPoliciesResponse into a shallow dictionary of its immediate attributes."""
|
|
950
|
+
body = {}
|
|
951
|
+
if self.next_page_token is not None: body['next_page_token'] = self.next_page_token
|
|
952
|
+
if self.policies: body['policies'] = self.policies
|
|
953
|
+
if self.previous_page_token is not None: body['previous_page_token'] = self.previous_page_token
|
|
954
|
+
return body
|
|
955
|
+
|
|
956
|
+
@classmethod
|
|
957
|
+
def from_dict(cls, d: Dict[str, any]) -> ListBudgetPoliciesResponse:
|
|
958
|
+
"""Deserializes the ListBudgetPoliciesResponse from a dictionary."""
|
|
959
|
+
return cls(next_page_token=d.get('next_page_token', None),
|
|
960
|
+
policies=_repeated_dict(d, 'policies', BudgetPolicy),
|
|
961
|
+
previous_page_token=d.get('previous_page_token', None))
|
|
962
|
+
|
|
963
|
+
|
|
790
964
|
class LogDeliveryConfigStatus(Enum):
|
|
791
965
|
"""Status of log delivery configuration. Set to `ENABLED` (enabled) or `DISABLED` (disabled).
|
|
792
966
|
Defaults to `ENABLED`. You can [enable or disable the
|
|
@@ -1046,6 +1220,39 @@ class PatchStatusResponse:
|
|
|
1046
1220
|
return cls()
|
|
1047
1221
|
|
|
1048
1222
|
|
|
1223
|
+
@dataclass
|
|
1224
|
+
class SortSpec:
|
|
1225
|
+
descending: Optional[bool] = None
|
|
1226
|
+
"""Whether to sort in descending order."""
|
|
1227
|
+
|
|
1228
|
+
field: Optional[SortSpecField] = None
|
|
1229
|
+
"""The filed to sort by"""
|
|
1230
|
+
|
|
1231
|
+
def as_dict(self) -> dict:
|
|
1232
|
+
"""Serializes the SortSpec into a dictionary suitable for use as a JSON request body."""
|
|
1233
|
+
body = {}
|
|
1234
|
+
if self.descending is not None: body['descending'] = self.descending
|
|
1235
|
+
if self.field is not None: body['field'] = self.field.value
|
|
1236
|
+
return body
|
|
1237
|
+
|
|
1238
|
+
def as_shallow_dict(self) -> dict:
|
|
1239
|
+
"""Serializes the SortSpec into a shallow dictionary of its immediate attributes."""
|
|
1240
|
+
body = {}
|
|
1241
|
+
if self.descending is not None: body['descending'] = self.descending
|
|
1242
|
+
if self.field is not None: body['field'] = self.field
|
|
1243
|
+
return body
|
|
1244
|
+
|
|
1245
|
+
@classmethod
|
|
1246
|
+
def from_dict(cls, d: Dict[str, any]) -> SortSpec:
|
|
1247
|
+
"""Deserializes the SortSpec from a dictionary."""
|
|
1248
|
+
return cls(descending=d.get('descending', None), field=_enum(d, 'field', SortSpecField))
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
class SortSpecField(Enum):
|
|
1252
|
+
|
|
1253
|
+
POLICY_NAME = 'POLICY_NAME'
|
|
1254
|
+
|
|
1255
|
+
|
|
1049
1256
|
@dataclass
|
|
1050
1257
|
class UpdateBudgetConfigurationBudget:
|
|
1051
1258
|
account_id: Optional[str] = None
|
|
@@ -1315,6 +1522,147 @@ class BillableUsageAPI:
|
|
|
1315
1522
|
return DownloadResponse.from_dict(res)
|
|
1316
1523
|
|
|
1317
1524
|
|
|
1525
|
+
class BudgetPolicyAPI:
|
|
1526
|
+
"""A service serves REST API about Budget policies"""
|
|
1527
|
+
|
|
1528
|
+
def __init__(self, api_client):
|
|
1529
|
+
self._api = api_client
|
|
1530
|
+
|
|
1531
|
+
def create(self,
|
|
1532
|
+
*,
|
|
1533
|
+
custom_tags: Optional[List[compute.CustomPolicyTag]] = None,
|
|
1534
|
+
policy_name: Optional[str] = None,
|
|
1535
|
+
request_id: Optional[str] = None) -> BudgetPolicy:
|
|
1536
|
+
"""Create a budget policy.
|
|
1537
|
+
|
|
1538
|
+
Creates a new policy.
|
|
1539
|
+
|
|
1540
|
+
:param custom_tags: List[:class:`CustomPolicyTag`] (optional)
|
|
1541
|
+
A list of tags defined by the customer. At most 40 entries are allowed per policy.
|
|
1542
|
+
:param policy_name: str (optional)
|
|
1543
|
+
The name of the policy. - Must be unique among active policies. - Can contain only characters of
|
|
1544
|
+
0-9, a-z, A-Z, -, =, ., :, /, @, _, +, whitespace.
|
|
1545
|
+
:param request_id: str (optional)
|
|
1546
|
+
A unique identifier for this request. Restricted to 36 ASCII characters. A random UUID is
|
|
1547
|
+
recommended. This request is only idempotent if a `request_id` is provided.
|
|
1548
|
+
|
|
1549
|
+
:returns: :class:`BudgetPolicy`
|
|
1550
|
+
"""
|
|
1551
|
+
body = {}
|
|
1552
|
+
if custom_tags is not None: body['custom_tags'] = [v.as_dict() for v in custom_tags]
|
|
1553
|
+
if policy_name is not None: body['policy_name'] = policy_name
|
|
1554
|
+
if request_id is not None: body['request_id'] = request_id
|
|
1555
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
1556
|
+
|
|
1557
|
+
res = self._api.do('POST',
|
|
1558
|
+
f'/api/2.1/accounts/{self._api.account_id}/budget-policies',
|
|
1559
|
+
body=body,
|
|
1560
|
+
headers=headers)
|
|
1561
|
+
return BudgetPolicy.from_dict(res)
|
|
1562
|
+
|
|
1563
|
+
def delete(self, policy_id: str):
|
|
1564
|
+
"""Delete a budget policy.
|
|
1565
|
+
|
|
1566
|
+
Deletes a policy
|
|
1567
|
+
|
|
1568
|
+
:param policy_id: str
|
|
1569
|
+
The Id of the policy.
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
"""
|
|
1573
|
+
|
|
1574
|
+
headers = {'Accept': 'application/json', }
|
|
1575
|
+
|
|
1576
|
+
self._api.do('DELETE',
|
|
1577
|
+
f'/api/2.1/accounts/{self._api.account_id}/budget-policies/{policy_id}',
|
|
1578
|
+
headers=headers)
|
|
1579
|
+
|
|
1580
|
+
def get(self, policy_id: str) -> BudgetPolicy:
|
|
1581
|
+
"""Get a budget policy.
|
|
1582
|
+
|
|
1583
|
+
Retrieves a policy by it's ID.
|
|
1584
|
+
|
|
1585
|
+
:param policy_id: str
|
|
1586
|
+
The Id of the policy.
|
|
1587
|
+
|
|
1588
|
+
:returns: :class:`BudgetPolicy`
|
|
1589
|
+
"""
|
|
1590
|
+
|
|
1591
|
+
headers = {'Accept': 'application/json', }
|
|
1592
|
+
|
|
1593
|
+
res = self._api.do('GET',
|
|
1594
|
+
f'/api/2.1/accounts/{self._api.account_id}/budget-policies/{policy_id}',
|
|
1595
|
+
headers=headers)
|
|
1596
|
+
return BudgetPolicy.from_dict(res)
|
|
1597
|
+
|
|
1598
|
+
def list(self,
|
|
1599
|
+
*,
|
|
1600
|
+
filter_by: Optional[Filter] = None,
|
|
1601
|
+
page_size: Optional[int] = None,
|
|
1602
|
+
page_token: Optional[str] = None,
|
|
1603
|
+
sort_spec: Optional[SortSpec] = None) -> Iterator[BudgetPolicy]:
|
|
1604
|
+
"""List policies.
|
|
1605
|
+
|
|
1606
|
+
Lists all policies. Policies are returned in the alphabetically ascending order of their names.
|
|
1607
|
+
|
|
1608
|
+
:param filter_by: :class:`Filter` (optional)
|
|
1609
|
+
A filter to apply to the list of policies.
|
|
1610
|
+
:param page_size: int (optional)
|
|
1611
|
+
The maximum number of budget policies to return. If unspecified, at most 100 budget policies will be
|
|
1612
|
+
returned. The maximum value is 1000; values above 1000 will be coerced to 1000.
|
|
1613
|
+
:param page_token: str (optional)
|
|
1614
|
+
A page token, received from a previous `ListServerlessPolicies` call. Provide this to retrieve the
|
|
1615
|
+
subsequent page. If unspecified, the first page will be returned.
|
|
1616
|
+
|
|
1617
|
+
When paginating, all other parameters provided to `ListServerlessPoliciesRequest` must match the
|
|
1618
|
+
call that provided the page token.
|
|
1619
|
+
:param sort_spec: :class:`SortSpec` (optional)
|
|
1620
|
+
The sort specification.
|
|
1621
|
+
|
|
1622
|
+
:returns: Iterator over :class:`BudgetPolicy`
|
|
1623
|
+
"""
|
|
1624
|
+
|
|
1625
|
+
query = {}
|
|
1626
|
+
if filter_by is not None: query['filter_by'] = filter_by.as_dict()
|
|
1627
|
+
if page_size is not None: query['page_size'] = page_size
|
|
1628
|
+
if page_token is not None: query['page_token'] = page_token
|
|
1629
|
+
if sort_spec is not None: query['sort_spec'] = sort_spec.as_dict()
|
|
1630
|
+
headers = {'Accept': 'application/json', }
|
|
1631
|
+
|
|
1632
|
+
while True:
|
|
1633
|
+
json = self._api.do('GET',
|
|
1634
|
+
f'/api/2.1/accounts/{self._api.account_id}/budget-policies',
|
|
1635
|
+
query=query,
|
|
1636
|
+
headers=headers)
|
|
1637
|
+
if 'policies' in json:
|
|
1638
|
+
for v in json['policies']:
|
|
1639
|
+
yield BudgetPolicy.from_dict(v)
|
|
1640
|
+
if 'next_page_token' not in json or not json['next_page_token']:
|
|
1641
|
+
return
|
|
1642
|
+
query['page_token'] = json['next_page_token']
|
|
1643
|
+
|
|
1644
|
+
def update(self, policy_id: str, *, policy: Optional[BudgetPolicy] = None) -> BudgetPolicy:
|
|
1645
|
+
"""Update a budget policy.
|
|
1646
|
+
|
|
1647
|
+
Updates a policy
|
|
1648
|
+
|
|
1649
|
+
:param policy_id: str
|
|
1650
|
+
The Id of the policy. This field is generated by Databricks and globally unique.
|
|
1651
|
+
:param policy: :class:`BudgetPolicy` (optional)
|
|
1652
|
+
Contains the BudgetPolicy details.
|
|
1653
|
+
|
|
1654
|
+
:returns: :class:`BudgetPolicy`
|
|
1655
|
+
"""
|
|
1656
|
+
body = policy.as_dict()
|
|
1657
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
1658
|
+
|
|
1659
|
+
res = self._api.do('PATCH',
|
|
1660
|
+
f'/api/2.1/accounts/{self._api.account_id}/budget-policies/{policy_id}',
|
|
1661
|
+
body=body,
|
|
1662
|
+
headers=headers)
|
|
1663
|
+
return BudgetPolicy.from_dict(res)
|
|
1664
|
+
|
|
1665
|
+
|
|
1318
1666
|
class BudgetsAPI:
|
|
1319
1667
|
"""These APIs manage budget configurations for this account. Budgets enable you to monitor usage across your
|
|
1320
1668
|
account. You can set up budgets to either track account-wide spending, or apply filters to track the
|