databricks-sdk 0.31.1__py3-none-any.whl → 0.32.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/core.py +17 -130
- databricks/sdk/errors/__init__.py +2 -1
- databricks/sdk/errors/base.py +32 -2
- databricks/sdk/errors/mapper.py +1 -5
- databricks/sdk/errors/parser.py +146 -0
- databricks/sdk/errors/private_link.py +1 -1
- databricks/sdk/logger/__init__.py +1 -0
- databricks/sdk/logger/round_trip_logger.py +118 -0
- databricks/sdk/service/catalog.py +85 -4
- databricks/sdk/service/iam.py +8 -8
- databricks/sdk/service/jobs.py +246 -4
- databricks/sdk/service/ml.py +8 -2
- databricks/sdk/service/serving.py +20 -8
- databricks/sdk/service/vectorsearch.py +8 -1
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.31.1.dist-info → databricks_sdk-0.32.0.dist-info}/METADATA +1 -1
- {databricks_sdk-0.31.1.dist-info → databricks_sdk-0.32.0.dist-info}/RECORD +21 -18
- {databricks_sdk-0.31.1.dist-info → databricks_sdk-0.32.0.dist-info}/WHEEL +1 -1
- {databricks_sdk-0.31.1.dist-info → databricks_sdk-0.32.0.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.31.1.dist-info → databricks_sdk-0.32.0.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.31.1.dist-info → databricks_sdk-0.32.0.dist-info}/top_level.txt +0 -0
databricks/sdk/core.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
-
import urllib.parse
|
|
3
2
|
from datetime import timedelta
|
|
4
|
-
from json import JSONDecodeError
|
|
5
3
|
from types import TracebackType
|
|
6
4
|
from typing import Any, BinaryIO, Iterator, Type
|
|
7
5
|
from urllib.parse import urlencode
|
|
@@ -12,8 +10,8 @@ from .casing import Casing
|
|
|
12
10
|
from .config import *
|
|
13
11
|
# To preserve backwards compatibility (as these definitions were previously in this module)
|
|
14
12
|
from .credentials_provider import *
|
|
15
|
-
from .errors import DatabricksError,
|
|
16
|
-
from .
|
|
13
|
+
from .errors import DatabricksError, get_api_error
|
|
14
|
+
from .logger import RoundTrip
|
|
17
15
|
from .oauth import retrieve_token
|
|
18
16
|
from .retries import retried
|
|
19
17
|
|
|
@@ -262,134 +260,23 @@ class ApiClient:
|
|
|
262
260
|
auth=auth,
|
|
263
261
|
stream=raw,
|
|
264
262
|
timeout=self._http_timeout_seconds)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
if not message:
|
|
280
|
-
message = response.reason
|
|
281
|
-
raise self._make_nicer_error(response=response, message=message) from None
|
|
282
|
-
|
|
283
|
-
@staticmethod
|
|
284
|
-
def _make_sense_from_html(txt: str) -> str:
|
|
285
|
-
matchers = [r'<pre>(.*)</pre>', r'<title>(.*)</title>']
|
|
286
|
-
for attempt in matchers:
|
|
287
|
-
expr = re.compile(attempt, re.MULTILINE)
|
|
288
|
-
match = expr.search(txt)
|
|
289
|
-
if not match:
|
|
290
|
-
continue
|
|
291
|
-
return match.group(1).strip()
|
|
292
|
-
return txt
|
|
293
|
-
|
|
294
|
-
def _make_nicer_error(self, *, response: requests.Response, **kwargs) -> DatabricksError:
|
|
295
|
-
status_code = response.status_code
|
|
296
|
-
message = kwargs.get('message', 'request failed')
|
|
297
|
-
is_http_unauthorized_or_forbidden = status_code in (401, 403)
|
|
298
|
-
is_too_many_requests_or_unavailable = status_code in (429, 503)
|
|
299
|
-
if is_http_unauthorized_or_forbidden:
|
|
300
|
-
message = self._cfg.wrap_debug_info(message)
|
|
301
|
-
if is_too_many_requests_or_unavailable:
|
|
302
|
-
kwargs['retry_after_secs'] = self._parse_retry_after(response)
|
|
303
|
-
kwargs['message'] = message
|
|
304
|
-
return error_mapper(response, kwargs)
|
|
305
|
-
|
|
306
|
-
def _record_request_log(self, response: requests.Response, raw=False):
|
|
263
|
+
self._record_request_log(response, raw=raw or data is not None or files is not None)
|
|
264
|
+
error = get_api_error(response)
|
|
265
|
+
if error is not None:
|
|
266
|
+
status_code = response.status_code
|
|
267
|
+
is_http_unauthorized_or_forbidden = status_code in (401, 403)
|
|
268
|
+
is_too_many_requests_or_unavailable = status_code in (429, 503)
|
|
269
|
+
if is_http_unauthorized_or_forbidden:
|
|
270
|
+
error.message = self._cfg.wrap_debug_info(error.message)
|
|
271
|
+
if is_too_many_requests_or_unavailable:
|
|
272
|
+
error.retry_after_secs = self._parse_retry_after(response)
|
|
273
|
+
raise error from None
|
|
274
|
+
return response
|
|
275
|
+
|
|
276
|
+
def _record_request_log(self, response: requests.Response, raw: bool = False) -> None:
|
|
307
277
|
if not logger.isEnabledFor(logging.DEBUG):
|
|
308
278
|
return
|
|
309
|
-
|
|
310
|
-
url = urllib.parse.urlparse(request.url)
|
|
311
|
-
query = ''
|
|
312
|
-
if url.query:
|
|
313
|
-
query = f'?{urllib.parse.unquote(url.query)}'
|
|
314
|
-
sb = [f'{request.method} {urllib.parse.unquote(url.path)}{query}']
|
|
315
|
-
if self._cfg.debug_headers:
|
|
316
|
-
if self._cfg.host:
|
|
317
|
-
sb.append(f'> * Host: {self._cfg.host}')
|
|
318
|
-
for k, v in request.headers.items():
|
|
319
|
-
sb.append(f'> * {k}: {self._only_n_bytes(v, self._debug_truncate_bytes)}')
|
|
320
|
-
if request.body:
|
|
321
|
-
sb.append("> [raw stream]" if raw else self._redacted_dump("> ", request.body))
|
|
322
|
-
sb.append(f'< {response.status_code} {response.reason}')
|
|
323
|
-
if raw and response.headers.get('Content-Type', None) != 'application/json':
|
|
324
|
-
# Raw streams with `Transfer-Encoding: chunked` do not have `Content-Type` header
|
|
325
|
-
sb.append("< [raw stream]")
|
|
326
|
-
elif response.content:
|
|
327
|
-
sb.append(self._redacted_dump("< ", response.content))
|
|
328
|
-
logger.debug("\n".join(sb))
|
|
329
|
-
|
|
330
|
-
@staticmethod
|
|
331
|
-
def _mask(m: Dict[str, any]):
|
|
332
|
-
for k in m:
|
|
333
|
-
if k in {'bytes_value', 'string_value', 'token_value', 'value', 'content'}:
|
|
334
|
-
m[k] = "**REDACTED**"
|
|
335
|
-
|
|
336
|
-
@staticmethod
|
|
337
|
-
def _map_keys(m: Dict[str, any]) -> List[str]:
|
|
338
|
-
keys = list(m.keys())
|
|
339
|
-
keys.sort()
|
|
340
|
-
return keys
|
|
341
|
-
|
|
342
|
-
@staticmethod
|
|
343
|
-
def _only_n_bytes(j: str, num_bytes: int = 96) -> str:
|
|
344
|
-
diff = len(j.encode('utf-8')) - num_bytes
|
|
345
|
-
if diff > 0:
|
|
346
|
-
return f"{j[:num_bytes]}... ({diff} more bytes)"
|
|
347
|
-
return j
|
|
348
|
-
|
|
349
|
-
def _recursive_marshal_dict(self, m, budget) -> dict:
|
|
350
|
-
out = {}
|
|
351
|
-
self._mask(m)
|
|
352
|
-
for k in sorted(m.keys()):
|
|
353
|
-
raw = self._recursive_marshal(m[k], budget)
|
|
354
|
-
out[k] = raw
|
|
355
|
-
budget -= len(str(raw))
|
|
356
|
-
return out
|
|
357
|
-
|
|
358
|
-
def _recursive_marshal_list(self, s, budget) -> list:
|
|
359
|
-
out = []
|
|
360
|
-
for i in range(len(s)):
|
|
361
|
-
if i > 0 >= budget:
|
|
362
|
-
out.append("... (%d additional elements)" % (len(s) - len(out)))
|
|
363
|
-
break
|
|
364
|
-
raw = self._recursive_marshal(s[i], budget)
|
|
365
|
-
out.append(raw)
|
|
366
|
-
budget -= len(str(raw))
|
|
367
|
-
return out
|
|
368
|
-
|
|
369
|
-
def _recursive_marshal(self, v: any, budget: int) -> any:
|
|
370
|
-
if isinstance(v, dict):
|
|
371
|
-
return self._recursive_marshal_dict(v, budget)
|
|
372
|
-
elif isinstance(v, list):
|
|
373
|
-
return self._recursive_marshal_list(v, budget)
|
|
374
|
-
elif isinstance(v, str):
|
|
375
|
-
return self._only_n_bytes(v, self._debug_truncate_bytes)
|
|
376
|
-
else:
|
|
377
|
-
return v
|
|
378
|
-
|
|
379
|
-
def _redacted_dump(self, prefix: str, body: str) -> str:
|
|
380
|
-
if len(body) == 0:
|
|
381
|
-
return ""
|
|
382
|
-
try:
|
|
383
|
-
# Unmarshal body into primitive types.
|
|
384
|
-
tmp = json.loads(body)
|
|
385
|
-
max_bytes = 96
|
|
386
|
-
if self._debug_truncate_bytes > max_bytes:
|
|
387
|
-
max_bytes = self._debug_truncate_bytes
|
|
388
|
-
# Re-marshal body taking redaction and character limit into account.
|
|
389
|
-
raw = self._recursive_marshal(tmp, max_bytes)
|
|
390
|
-
return "\n".join([f'{prefix}{line}' for line in json.dumps(raw, indent=2).split("\n")])
|
|
391
|
-
except JSONDecodeError:
|
|
392
|
-
return f'{prefix}[non-JSON document of {len(body)} bytes]'
|
|
279
|
+
logger.debug(RoundTrip(response, self._cfg.debug_headers, self._debug_truncate_bytes, raw).generate())
|
|
393
280
|
|
|
394
281
|
|
|
395
282
|
class StreamingResponse(BinaryIO):
|
databricks/sdk/errors/base.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import warnings
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from typing import Dict, List, Optional
|
|
4
5
|
|
|
@@ -41,9 +42,38 @@ class DatabricksError(IOError):
|
|
|
41
42
|
retry_after_secs: int = None,
|
|
42
43
|
details: List[Dict[str, any]] = None,
|
|
43
44
|
**kwargs):
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
:param message:
|
|
48
|
+
:param error_code:
|
|
49
|
+
:param detail: [Deprecated]
|
|
50
|
+
:param status: [Deprecated]
|
|
51
|
+
:param scimType: [Deprecated]
|
|
52
|
+
:param error: [Deprecated]
|
|
53
|
+
:param retry_after_secs:
|
|
54
|
+
:param details:
|
|
55
|
+
:param kwargs:
|
|
56
|
+
"""
|
|
57
|
+
# SCIM-specific parameters are deprecated
|
|
58
|
+
if detail:
|
|
59
|
+
warnings.warn(
|
|
60
|
+
"The 'detail' parameter of DatabricksError is deprecated and will be removed in a future version."
|
|
61
|
+
)
|
|
62
|
+
if scimType:
|
|
63
|
+
warnings.warn(
|
|
64
|
+
"The 'scimType' parameter of DatabricksError is deprecated and will be removed in a future version."
|
|
65
|
+
)
|
|
66
|
+
if status:
|
|
67
|
+
warnings.warn(
|
|
68
|
+
"The 'status' parameter of DatabricksError is deprecated and will be removed in a future version."
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# API 1.2-specific parameters are deprecated
|
|
44
72
|
if error:
|
|
45
|
-
|
|
46
|
-
|
|
73
|
+
warnings.warn(
|
|
74
|
+
"The 'error' parameter of DatabricksError is deprecated and will be removed in a future version."
|
|
75
|
+
)
|
|
76
|
+
|
|
47
77
|
if detail:
|
|
48
78
|
# Handle SCIM error message details
|
|
49
79
|
# @see https://tools.ietf.org/html/rfc7644#section-3.7.3
|
databricks/sdk/errors/mapper.py
CHANGED
|
@@ -4,11 +4,9 @@ from databricks.sdk.errors import platform
|
|
|
4
4
|
from databricks.sdk.errors.base import DatabricksError
|
|
5
5
|
|
|
6
6
|
from .overrides import _ALL_OVERRIDES
|
|
7
|
-
from .private_link import (_get_private_link_validation_error,
|
|
8
|
-
_is_private_link_redirect)
|
|
9
7
|
|
|
10
8
|
|
|
11
|
-
def
|
|
9
|
+
def _error_mapper(response: requests.Response, raw: dict) -> DatabricksError:
|
|
12
10
|
for override in _ALL_OVERRIDES:
|
|
13
11
|
if override.matches(response, raw):
|
|
14
12
|
return override.custom_error(**raw)
|
|
@@ -23,8 +21,6 @@ def error_mapper(response: requests.Response, raw: dict) -> DatabricksError:
|
|
|
23
21
|
# where there's a default exception class per HTTP status code, and we do
|
|
24
22
|
# rely on Databricks platform exception mapper to do the right thing.
|
|
25
23
|
return platform.STATUS_CODE_MAPPING[status_code](**raw)
|
|
26
|
-
if _is_private_link_redirect(response):
|
|
27
|
-
return _get_private_link_validation_error(response.url)
|
|
28
24
|
|
|
29
25
|
# backwards-compatible error creation for cases like using older versions of
|
|
30
26
|
# the SDK on way never releases of the platform.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import re
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from ..logger import RoundTrip
|
|
10
|
+
from .base import DatabricksError
|
|
11
|
+
from .mapper import _error_mapper
|
|
12
|
+
from .private_link import (_get_private_link_validation_error,
|
|
13
|
+
_is_private_link_redirect)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class _ErrorParser(abc.ABC):
|
|
17
|
+
"""A parser for errors from the Databricks REST API."""
|
|
18
|
+
|
|
19
|
+
@abc.abstractmethod
|
|
20
|
+
def parse_error(self, response: requests.Response, response_body: bytes) -> Optional[dict]:
|
|
21
|
+
"""Parses an error from the Databricks REST API. If the error cannot be parsed, returns None."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class _EmptyParser(_ErrorParser):
|
|
25
|
+
"""A parser that handles empty responses."""
|
|
26
|
+
|
|
27
|
+
def parse_error(self, response: requests.Response, response_body: bytes) -> Optional[dict]:
|
|
28
|
+
if len(response_body) == 0:
|
|
29
|
+
return {'message': response.reason}
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class _StandardErrorParser(_ErrorParser):
|
|
34
|
+
"""
|
|
35
|
+
Parses errors from the Databricks REST API using the standard error format.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def parse_error(self, response: requests.Response, response_body: bytes) -> Optional[dict]:
|
|
39
|
+
try:
|
|
40
|
+
payload_str = response_body.decode('utf-8')
|
|
41
|
+
resp: dict = json.loads(payload_str)
|
|
42
|
+
except json.JSONDecodeError as e:
|
|
43
|
+
logging.debug('_StandardErrorParser: unable to deserialize response as json', exc_info=e)
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
error_args = {
|
|
47
|
+
'message': resp.get('message', 'request failed'),
|
|
48
|
+
'error_code': resp.get('error_code'),
|
|
49
|
+
'details': resp.get('details'),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Handle API 1.2-style errors
|
|
53
|
+
if 'error' in resp:
|
|
54
|
+
error_args['message'] = resp['error']
|
|
55
|
+
|
|
56
|
+
# Handle SCIM Errors
|
|
57
|
+
detail = resp.get('detail')
|
|
58
|
+
status = resp.get('status')
|
|
59
|
+
scim_type = resp.get('scimType')
|
|
60
|
+
if detail:
|
|
61
|
+
# Handle SCIM error message details
|
|
62
|
+
# @see https://tools.ietf.org/html/rfc7644#section-3.7.3
|
|
63
|
+
error_args[
|
|
64
|
+
'message'] = f"{scim_type} {error_args.get('message', 'SCIM API Internal Error')}".strip(" ")
|
|
65
|
+
error_args['error_code'] = f"SCIM_{status}"
|
|
66
|
+
return error_args
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class _StringErrorParser(_ErrorParser):
|
|
70
|
+
"""
|
|
71
|
+
Parses errors from the Databricks REST API in the format "ERROR_CODE: MESSAGE".
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
__STRING_ERROR_REGEX = re.compile(r'([A-Z_]+): (.*)')
|
|
75
|
+
|
|
76
|
+
def parse_error(self, response: requests.Response, response_body: bytes) -> Optional[dict]:
|
|
77
|
+
payload_str = response_body.decode('utf-8')
|
|
78
|
+
match = self.__STRING_ERROR_REGEX.match(payload_str)
|
|
79
|
+
if not match:
|
|
80
|
+
logging.debug('_StringErrorParser: unable to parse response as string')
|
|
81
|
+
return None
|
|
82
|
+
error_code, message = match.groups()
|
|
83
|
+
return {'error_code': error_code, 'message': message, 'status': response.status_code, }
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class _HtmlErrorParser(_ErrorParser):
|
|
87
|
+
"""
|
|
88
|
+
Parses errors from the Databricks REST API in HTML format.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
__HTML_ERROR_REGEXES = [re.compile(r'<pre>(.*)</pre>'), re.compile(r'<title>(.*)</title>'), ]
|
|
92
|
+
|
|
93
|
+
def parse_error(self, response: requests.Response, response_body: bytes) -> Optional[dict]:
|
|
94
|
+
payload_str = response_body.decode('utf-8')
|
|
95
|
+
for regex in self.__HTML_ERROR_REGEXES:
|
|
96
|
+
match = regex.search(payload_str)
|
|
97
|
+
if match:
|
|
98
|
+
message = match.group(1) if match.group(1) else response.reason
|
|
99
|
+
return {
|
|
100
|
+
'status': response.status_code,
|
|
101
|
+
'message': message,
|
|
102
|
+
'error_code': response.reason.upper().replace(' ', '_')
|
|
103
|
+
}
|
|
104
|
+
logging.debug('_HtmlErrorParser: no <pre> tag found in error response')
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# A list of ErrorParsers that are tried in order to parse an API error from a response body. Most errors should be
|
|
109
|
+
# parsable by the _StandardErrorParser, but additional parsers can be added here for specific error formats. The order
|
|
110
|
+
# of the parsers is not important, as the set of errors that can be parsed by each parser should be disjoint.
|
|
111
|
+
_error_parsers = [_EmptyParser(), _StandardErrorParser(), _StringErrorParser(), _HtmlErrorParser(), ]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _unknown_error(response: requests.Response) -> str:
|
|
115
|
+
"""A standard error message that can be shown when an API response cannot be parsed.
|
|
116
|
+
|
|
117
|
+
This error message includes a link to the issue tracker for the SDK for users to report the issue to us.
|
|
118
|
+
"""
|
|
119
|
+
request_log = RoundTrip(response, debug_headers=True, debug_truncate_bytes=10 * 1024).generate()
|
|
120
|
+
return (
|
|
121
|
+
'This is likely a bug in the Databricks SDK for Python or the underlying '
|
|
122
|
+
'API. Please report this issue with the following debugging information to the SDK issue tracker at '
|
|
123
|
+
f'https://github.com/databricks/databricks-sdk-go/issues. Request log:```{request_log}```')
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_api_error(response: requests.Response) -> Optional[DatabricksError]:
|
|
127
|
+
"""
|
|
128
|
+
Handles responses from the REST API and returns a DatabricksError if the response indicates an error.
|
|
129
|
+
:param response: The response from the REST API.
|
|
130
|
+
:return: A DatabricksError if the response indicates an error, otherwise None.
|
|
131
|
+
"""
|
|
132
|
+
if not response.ok:
|
|
133
|
+
content = response.content
|
|
134
|
+
for parser in _error_parsers:
|
|
135
|
+
try:
|
|
136
|
+
error_args = parser.parse_error(response, content)
|
|
137
|
+
if error_args:
|
|
138
|
+
return _error_mapper(response, error_args)
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logging.debug(f'Error parsing response with {parser}, continuing', exc_info=e)
|
|
141
|
+
return _error_mapper(response, {'message': 'unable to parse response. ' + _unknown_error(response)})
|
|
142
|
+
|
|
143
|
+
# Private link failures happen via a redirect to the login page. From a requests-perspective, the request
|
|
144
|
+
# is successful, but the response is not what we expect. We need to handle this case separately.
|
|
145
|
+
if _is_private_link_redirect(response):
|
|
146
|
+
return _get_private_link_validation_error(response.url)
|
|
@@ -51,7 +51,7 @@ def _is_private_link_redirect(resp: requests.Response) -> bool:
|
|
|
51
51
|
return parsed.path == '/login.html' and 'error=private-link-validation-error' in parsed.query
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def _get_private_link_validation_error(url: str) ->
|
|
54
|
+
def _get_private_link_validation_error(url: str) -> PrivateLinkValidationError:
|
|
55
55
|
parsed = parse.urlparse(url)
|
|
56
56
|
env = get_environment_for_hostname(parsed.hostname)
|
|
57
57
|
return PrivateLinkValidationError(message=_private_link_info_map[env.cloud].error_message(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .round_trip_logger import RoundTrip
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import urllib.parse
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RoundTrip:
|
|
9
|
+
"""
|
|
10
|
+
A utility class for converting HTTP requests and responses to strings.
|
|
11
|
+
|
|
12
|
+
:param response: The response object to stringify.
|
|
13
|
+
:param debug_headers: Whether to include headers in the generated string.
|
|
14
|
+
:param debug_truncate_bytes: The maximum number of bytes to include in the generated string.
|
|
15
|
+
:param raw: Whether the response is a stream or not. If True, the response will not be logged directly.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self,
|
|
19
|
+
response: requests.Response,
|
|
20
|
+
debug_headers: bool,
|
|
21
|
+
debug_truncate_bytes: int,
|
|
22
|
+
raw=False):
|
|
23
|
+
self._debug_headers = debug_headers
|
|
24
|
+
self._debug_truncate_bytes = max(debug_truncate_bytes, 96)
|
|
25
|
+
self._raw = raw
|
|
26
|
+
self._response = response
|
|
27
|
+
|
|
28
|
+
def generate(self) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Generate a string representation of the request and response. The string will include the request method, URL,
|
|
31
|
+
headers, and body, as well as the response status code, reason, headers, and body. Outgoing information
|
|
32
|
+
will be prefixed with `>`, and incoming information will be prefixed with `<`.
|
|
33
|
+
:return: A string representation of the request.
|
|
34
|
+
"""
|
|
35
|
+
request = self._response.request
|
|
36
|
+
url = urllib.parse.urlparse(request.url)
|
|
37
|
+
query = ''
|
|
38
|
+
if url.query:
|
|
39
|
+
query = f'?{urllib.parse.unquote(url.query)}'
|
|
40
|
+
sb = [f'{request.method} {urllib.parse.unquote(url.path)}{query}']
|
|
41
|
+
if self._debug_headers:
|
|
42
|
+
for k, v in request.headers.items():
|
|
43
|
+
sb.append(f'> * {k}: {self._only_n_bytes(v, self._debug_truncate_bytes)}')
|
|
44
|
+
if request.body:
|
|
45
|
+
sb.append("> [raw stream]" if self._raw else self._redacted_dump("> ", request.body))
|
|
46
|
+
sb.append(f'< {self._response.status_code} {self._response.reason}')
|
|
47
|
+
if self._raw and self._response.headers.get('Content-Type', None) != 'application/json':
|
|
48
|
+
# Raw streams with `Transfer-Encoding: chunked` do not have `Content-Type` header
|
|
49
|
+
sb.append("< [raw stream]")
|
|
50
|
+
elif self._response.content:
|
|
51
|
+
sb.append(self._redacted_dump("< ", self._response.content.decode('utf-8')))
|
|
52
|
+
return '\n'.join(sb)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def _mask(m: Dict[str, any]):
|
|
56
|
+
for k in m:
|
|
57
|
+
if k in {'bytes_value', 'string_value', 'token_value', 'value', 'content'}:
|
|
58
|
+
m[k] = "**REDACTED**"
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def _map_keys(m: Dict[str, any]) -> List[str]:
|
|
62
|
+
keys = list(m.keys())
|
|
63
|
+
keys.sort()
|
|
64
|
+
return keys
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
def _only_n_bytes(j: str, num_bytes: int = 96) -> str:
|
|
68
|
+
diff = len(j.encode('utf-8')) - num_bytes
|
|
69
|
+
if diff > 0:
|
|
70
|
+
return f"{j[:num_bytes]}... ({diff} more bytes)"
|
|
71
|
+
return j
|
|
72
|
+
|
|
73
|
+
def _recursive_marshal_dict(self, m, budget) -> dict:
|
|
74
|
+
out = {}
|
|
75
|
+
self._mask(m)
|
|
76
|
+
for k in sorted(m.keys()):
|
|
77
|
+
raw = self._recursive_marshal(m[k], budget)
|
|
78
|
+
out[k] = raw
|
|
79
|
+
budget -= len(str(raw))
|
|
80
|
+
return out
|
|
81
|
+
|
|
82
|
+
def _recursive_marshal_list(self, s, budget) -> list:
|
|
83
|
+
out = []
|
|
84
|
+
for i in range(len(s)):
|
|
85
|
+
if i > 0 >= budget:
|
|
86
|
+
out.append("... (%d additional elements)" % (len(s) - len(out)))
|
|
87
|
+
break
|
|
88
|
+
raw = self._recursive_marshal(s[i], budget)
|
|
89
|
+
out.append(raw)
|
|
90
|
+
budget -= len(str(raw))
|
|
91
|
+
return out
|
|
92
|
+
|
|
93
|
+
def _recursive_marshal(self, v: any, budget: int) -> any:
|
|
94
|
+
if isinstance(v, dict):
|
|
95
|
+
return self._recursive_marshal_dict(v, budget)
|
|
96
|
+
elif isinstance(v, list):
|
|
97
|
+
return self._recursive_marshal_list(v, budget)
|
|
98
|
+
elif isinstance(v, str):
|
|
99
|
+
return self._only_n_bytes(v, self._debug_truncate_bytes)
|
|
100
|
+
else:
|
|
101
|
+
return v
|
|
102
|
+
|
|
103
|
+
def _redacted_dump(self, prefix: str, body: str) -> str:
|
|
104
|
+
if len(body) == 0:
|
|
105
|
+
return ""
|
|
106
|
+
try:
|
|
107
|
+
# Unmarshal body into primitive types.
|
|
108
|
+
tmp = json.loads(body)
|
|
109
|
+
max_bytes = 96
|
|
110
|
+
if self._debug_truncate_bytes > max_bytes:
|
|
111
|
+
max_bytes = self._debug_truncate_bytes
|
|
112
|
+
# Re-marshal body taking redaction and character limit into account.
|
|
113
|
+
raw = self._recursive_marshal(tmp, max_bytes)
|
|
114
|
+
return "\n".join([f'{prefix}{line}' for line in json.dumps(raw, indent=2).split("\n")])
|
|
115
|
+
except json.JSONDecodeError:
|
|
116
|
+
to_log = self._only_n_bytes(body, self._debug_truncate_bytes)
|
|
117
|
+
log_lines = [prefix + x.strip('\r') for x in to_log.split("\n")]
|
|
118
|
+
return '\n'.join(log_lines)
|
|
@@ -1268,7 +1268,8 @@ class CreateMetastoreAssignment:
|
|
|
1268
1268
|
"""The unique ID of the metastore."""
|
|
1269
1269
|
|
|
1270
1270
|
default_catalog_name: str
|
|
1271
|
-
"""The name of the default catalog in the metastore."
|
|
1271
|
+
"""The name of the default catalog in the metastore. This field is depracted. Please use "Default
|
|
1272
|
+
Namespace API" to configure the default catalog for a Databricks workspace."""
|
|
1272
1273
|
|
|
1273
1274
|
workspace_id: Optional[int] = None
|
|
1274
1275
|
"""A workspace ID."""
|
|
@@ -4150,6 +4151,49 @@ class QuotaInfo:
|
|
|
4150
4151
|
quota_name=d.get('quota_name', None))
|
|
4151
4152
|
|
|
4152
4153
|
|
|
4154
|
+
@dataclass
|
|
4155
|
+
class RegenerateDashboardRequest:
|
|
4156
|
+
table_name: Optional[str] = None
|
|
4157
|
+
"""Full name of the table."""
|
|
4158
|
+
|
|
4159
|
+
warehouse_id: Optional[str] = None
|
|
4160
|
+
"""Optional argument to specify the warehouse for dashboard regeneration. If not specified, the
|
|
4161
|
+
first running warehouse will be used."""
|
|
4162
|
+
|
|
4163
|
+
def as_dict(self) -> dict:
|
|
4164
|
+
"""Serializes the RegenerateDashboardRequest into a dictionary suitable for use as a JSON request body."""
|
|
4165
|
+
body = {}
|
|
4166
|
+
if self.table_name is not None: body['table_name'] = self.table_name
|
|
4167
|
+
if self.warehouse_id is not None: body['warehouse_id'] = self.warehouse_id
|
|
4168
|
+
return body
|
|
4169
|
+
|
|
4170
|
+
@classmethod
|
|
4171
|
+
def from_dict(cls, d: Dict[str, any]) -> RegenerateDashboardRequest:
|
|
4172
|
+
"""Deserializes the RegenerateDashboardRequest from a dictionary."""
|
|
4173
|
+
return cls(table_name=d.get('table_name', None), warehouse_id=d.get('warehouse_id', None))
|
|
4174
|
+
|
|
4175
|
+
|
|
4176
|
+
@dataclass
|
|
4177
|
+
class RegenerateDashboardResponse:
|
|
4178
|
+
dashboard_id: Optional[str] = None
|
|
4179
|
+
"""Id of the regenerated monitoring dashboard."""
|
|
4180
|
+
|
|
4181
|
+
parent_folder: Optional[str] = None
|
|
4182
|
+
"""The directory where the regenerated dashboard is stored."""
|
|
4183
|
+
|
|
4184
|
+
def as_dict(self) -> dict:
|
|
4185
|
+
"""Serializes the RegenerateDashboardResponse into a dictionary suitable for use as a JSON request body."""
|
|
4186
|
+
body = {}
|
|
4187
|
+
if self.dashboard_id is not None: body['dashboard_id'] = self.dashboard_id
|
|
4188
|
+
if self.parent_folder is not None: body['parent_folder'] = self.parent_folder
|
|
4189
|
+
return body
|
|
4190
|
+
|
|
4191
|
+
@classmethod
|
|
4192
|
+
def from_dict(cls, d: Dict[str, any]) -> RegenerateDashboardResponse:
|
|
4193
|
+
"""Deserializes the RegenerateDashboardResponse from a dictionary."""
|
|
4194
|
+
return cls(dashboard_id=d.get('dashboard_id', None), parent_folder=d.get('parent_folder', None))
|
|
4195
|
+
|
|
4196
|
+
|
|
4153
4197
|
@dataclass
|
|
4154
4198
|
class RegisteredModelAlias:
|
|
4155
4199
|
"""Registered model alias."""
|
|
@@ -5220,7 +5264,8 @@ class UpdateMetastore:
|
|
|
5220
5264
|
@dataclass
|
|
5221
5265
|
class UpdateMetastoreAssignment:
|
|
5222
5266
|
default_catalog_name: Optional[str] = None
|
|
5223
|
-
"""The name of the default catalog
|
|
5267
|
+
"""The name of the default catalog in the metastore. This field is depracted. Please use "Default
|
|
5268
|
+
Namespace API" to configure the default catalog for a Databricks workspace."""
|
|
5224
5269
|
|
|
5225
5270
|
metastore_id: Optional[str] = None
|
|
5226
5271
|
"""The unique ID of the metastore."""
|
|
@@ -7208,7 +7253,8 @@ class MetastoresAPI:
|
|
|
7208
7253
|
:param metastore_id: str
|
|
7209
7254
|
The unique ID of the metastore.
|
|
7210
7255
|
:param default_catalog_name: str
|
|
7211
|
-
The name of the default catalog in the metastore.
|
|
7256
|
+
The name of the default catalog in the metastore. This field is depracted. Please use "Default
|
|
7257
|
+
Namespace API" to configure the default catalog for a Databricks workspace.
|
|
7212
7258
|
|
|
7213
7259
|
|
|
7214
7260
|
"""
|
|
@@ -7421,7 +7467,8 @@ class MetastoresAPI:
|
|
|
7421
7467
|
:param workspace_id: int
|
|
7422
7468
|
A workspace ID.
|
|
7423
7469
|
:param default_catalog_name: str (optional)
|
|
7424
|
-
The name of the default catalog
|
|
7470
|
+
The name of the default catalog in the metastore. This field is depracted. Please use "Default
|
|
7471
|
+
Namespace API" to configure the default catalog for a Databricks workspace.
|
|
7425
7472
|
:param metastore_id: str (optional)
|
|
7426
7473
|
The unique ID of the metastore.
|
|
7427
7474
|
|
|
@@ -7916,6 +7963,40 @@ class QualityMonitorsAPI:
|
|
|
7916
7963
|
headers=headers)
|
|
7917
7964
|
return MonitorRefreshListResponse.from_dict(res)
|
|
7918
7965
|
|
|
7966
|
+
def regenerate_dashboard(self,
|
|
7967
|
+
table_name: str,
|
|
7968
|
+
*,
|
|
7969
|
+
warehouse_id: Optional[str] = None) -> RegenerateDashboardResponse:
|
|
7970
|
+
"""Regenerate a monitoring dashboard.
|
|
7971
|
+
|
|
7972
|
+
Regenerates the monitoring dashboard for the specified table.
|
|
7973
|
+
|
|
7974
|
+
The caller must either: 1. be an owner of the table's parent catalog 2. have **USE_CATALOG** on the
|
|
7975
|
+
table's parent catalog and be an owner of the table's parent schema 3. have the following permissions:
|
|
7976
|
+
- **USE_CATALOG** on the table's parent catalog - **USE_SCHEMA** on the table's parent schema - be an
|
|
7977
|
+
owner of the table
|
|
7978
|
+
|
|
7979
|
+
The call must be made from the workspace where the monitor was created. The dashboard will be
|
|
7980
|
+
regenerated in the assets directory that was specified when the monitor was created.
|
|
7981
|
+
|
|
7982
|
+
:param table_name: str
|
|
7983
|
+
Full name of the table.
|
|
7984
|
+
:param warehouse_id: str (optional)
|
|
7985
|
+
Optional argument to specify the warehouse for dashboard regeneration. If not specified, the first
|
|
7986
|
+
running warehouse will be used.
|
|
7987
|
+
|
|
7988
|
+
:returns: :class:`RegenerateDashboardResponse`
|
|
7989
|
+
"""
|
|
7990
|
+
body = {}
|
|
7991
|
+
if warehouse_id is not None: body['warehouse_id'] = warehouse_id
|
|
7992
|
+
headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
|
|
7993
|
+
|
|
7994
|
+
res = self._api.do('POST',
|
|
7995
|
+
f'/api/2.1/quality-monitoring/tables/{table_name}/monitor/dashboard',
|
|
7996
|
+
body=body,
|
|
7997
|
+
headers=headers)
|
|
7998
|
+
return RegenerateDashboardResponse.from_dict(res)
|
|
7999
|
+
|
|
7919
8000
|
def run_refresh(self, table_name: str) -> MonitorRefreshInfo:
|
|
7920
8001
|
"""Queue a metric refresh for a monitor.
|
|
7921
8002
|
|
databricks/sdk/service/iam.py
CHANGED
|
@@ -892,8 +892,8 @@ class PermissionsRequest:
|
|
|
892
892
|
|
|
893
893
|
request_object_type: Optional[str] = None
|
|
894
894
|
"""The type of the request object. Can be one of the following: alerts, authorization, clusters,
|
|
895
|
-
cluster-policies, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
896
|
-
notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses."""
|
|
895
|
+
cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
896
|
+
jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses."""
|
|
897
897
|
|
|
898
898
|
def as_dict(self) -> dict:
|
|
899
899
|
"""Serializes the PermissionsRequest into a dictionary suitable for use as a JSON request body."""
|
|
@@ -2600,8 +2600,8 @@ class PermissionsAPI:
|
|
|
2600
2600
|
|
|
2601
2601
|
:param request_object_type: str
|
|
2602
2602
|
The type of the request object. Can be one of the following: alerts, authorization, clusters,
|
|
2603
|
-
cluster-policies, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
2604
|
-
notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses.
|
|
2603
|
+
cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
2604
|
+
jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses.
|
|
2605
2605
|
:param request_object_id: str
|
|
2606
2606
|
The id of the request object.
|
|
2607
2607
|
|
|
@@ -2648,8 +2648,8 @@ class PermissionsAPI:
|
|
|
2648
2648
|
|
|
2649
2649
|
:param request_object_type: str
|
|
2650
2650
|
The type of the request object. Can be one of the following: alerts, authorization, clusters,
|
|
2651
|
-
cluster-policies, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
2652
|
-
notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses.
|
|
2651
|
+
cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
2652
|
+
jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses.
|
|
2653
2653
|
:param request_object_id: str
|
|
2654
2654
|
The id of the request object.
|
|
2655
2655
|
:param access_control_list: List[:class:`AccessControlRequest`] (optional)
|
|
@@ -2679,8 +2679,8 @@ class PermissionsAPI:
|
|
|
2679
2679
|
|
|
2680
2680
|
:param request_object_type: str
|
|
2681
2681
|
The type of the request object. Can be one of the following: alerts, authorization, clusters,
|
|
2682
|
-
cluster-policies, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
2683
|
-
notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses.
|
|
2682
|
+
cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, instance-pools,
|
|
2683
|
+
jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or warehouses.
|
|
2684
2684
|
:param request_object_id: str
|
|
2685
2685
|
The id of the request object.
|
|
2686
2686
|
:param access_control_list: List[:class:`AccessControlRequest`] (optional)
|
databricks/sdk/service/jobs.py
CHANGED
|
@@ -171,7 +171,10 @@ class BaseRun:
|
|
|
171
171
|
scheduled to run on a new cluster, this is the time the cluster creation call is issued."""
|
|
172
172
|
|
|
173
173
|
state: Optional[RunState] = None
|
|
174
|
-
"""
|
|
174
|
+
"""Deprecated. Please use the `status` field instead."""
|
|
175
|
+
|
|
176
|
+
status: Optional[RunStatus] = None
|
|
177
|
+
"""The current status of the run"""
|
|
175
178
|
|
|
176
179
|
tasks: Optional[List[RunTask]] = None
|
|
177
180
|
"""The list of tasks performed by the run. Each task has its own `run_id` which you can use to call
|
|
@@ -222,6 +225,7 @@ class BaseRun:
|
|
|
222
225
|
if self.setup_duration is not None: body['setup_duration'] = self.setup_duration
|
|
223
226
|
if self.start_time is not None: body['start_time'] = self.start_time
|
|
224
227
|
if self.state: body['state'] = self.state.as_dict()
|
|
228
|
+
if self.status: body['status'] = self.status.as_dict()
|
|
225
229
|
if self.tasks: body['tasks'] = [v.as_dict() for v in self.tasks]
|
|
226
230
|
if self.trigger is not None: body['trigger'] = self.trigger.value
|
|
227
231
|
if self.trigger_info: body['trigger_info'] = self.trigger_info.as_dict()
|
|
@@ -257,6 +261,7 @@ class BaseRun:
|
|
|
257
261
|
setup_duration=d.get('setup_duration', None),
|
|
258
262
|
start_time=d.get('start_time', None),
|
|
259
263
|
state=_from_dict(d, 'state', RunState),
|
|
264
|
+
status=_from_dict(d, 'status', RunStatus),
|
|
260
265
|
tasks=_repeated_dict(d, 'tasks', RunTask),
|
|
261
266
|
trigger=_enum(d, 'trigger', TriggerType),
|
|
262
267
|
trigger_info=_from_dict(d, 'trigger_info', TriggerInfo))
|
|
@@ -2314,6 +2319,44 @@ class PythonWheelTask:
|
|
|
2314
2319
|
parameters=d.get('parameters', None))
|
|
2315
2320
|
|
|
2316
2321
|
|
|
2322
|
+
@dataclass
|
|
2323
|
+
class QueueDetails:
|
|
2324
|
+
code: Optional[QueueDetailsCodeCode] = None
|
|
2325
|
+
"""The reason for queuing the run. * `ACTIVE_RUNS_LIMIT_REACHED`: The run was queued due to
|
|
2326
|
+
reaching the workspace limit of active task runs. * `MAX_CONCURRENT_RUNS_REACHED`: The run was
|
|
2327
|
+
queued due to reaching the per-job limit of concurrent job runs. *
|
|
2328
|
+
`ACTIVE_RUN_JOB_TASKS_LIMIT_REACHED`: The run was queued due to reaching the workspace limit of
|
|
2329
|
+
active run job tasks."""
|
|
2330
|
+
|
|
2331
|
+
message: Optional[str] = None
|
|
2332
|
+
"""A descriptive message with the queuing details. This field is unstructured, and its exact format
|
|
2333
|
+
is subject to change."""
|
|
2334
|
+
|
|
2335
|
+
def as_dict(self) -> dict:
|
|
2336
|
+
"""Serializes the QueueDetails into a dictionary suitable for use as a JSON request body."""
|
|
2337
|
+
body = {}
|
|
2338
|
+
if self.code is not None: body['code'] = self.code.value
|
|
2339
|
+
if self.message is not None: body['message'] = self.message
|
|
2340
|
+
return body
|
|
2341
|
+
|
|
2342
|
+
@classmethod
|
|
2343
|
+
def from_dict(cls, d: Dict[str, any]) -> QueueDetails:
|
|
2344
|
+
"""Deserializes the QueueDetails from a dictionary."""
|
|
2345
|
+
return cls(code=_enum(d, 'code', QueueDetailsCodeCode), message=d.get('message', None))
|
|
2346
|
+
|
|
2347
|
+
|
|
2348
|
+
class QueueDetailsCodeCode(Enum):
|
|
2349
|
+
"""The reason for queuing the run. * `ACTIVE_RUNS_LIMIT_REACHED`: The run was queued due to
|
|
2350
|
+
reaching the workspace limit of active task runs. * `MAX_CONCURRENT_RUNS_REACHED`: The run was
|
|
2351
|
+
queued due to reaching the per-job limit of concurrent job runs. *
|
|
2352
|
+
`ACTIVE_RUN_JOB_TASKS_LIMIT_REACHED`: The run was queued due to reaching the workspace limit of
|
|
2353
|
+
active run job tasks."""
|
|
2354
|
+
|
|
2355
|
+
ACTIVE_RUNS_LIMIT_REACHED = 'ACTIVE_RUNS_LIMIT_REACHED'
|
|
2356
|
+
ACTIVE_RUN_JOB_TASKS_LIMIT_REACHED = 'ACTIVE_RUN_JOB_TASKS_LIMIT_REACHED'
|
|
2357
|
+
MAX_CONCURRENT_RUNS_REACHED = 'MAX_CONCURRENT_RUNS_REACHED'
|
|
2358
|
+
|
|
2359
|
+
|
|
2317
2360
|
@dataclass
|
|
2318
2361
|
class QueueSettings:
|
|
2319
2362
|
enabled: bool
|
|
@@ -2343,7 +2386,10 @@ class RepairHistoryItem:
|
|
|
2343
2386
|
"""The start time of the (repaired) run."""
|
|
2344
2387
|
|
|
2345
2388
|
state: Optional[RunState] = None
|
|
2346
|
-
"""
|
|
2389
|
+
"""Deprecated. Please use the `status` field instead."""
|
|
2390
|
+
|
|
2391
|
+
status: Optional[RunStatus] = None
|
|
2392
|
+
"""The current status of the run"""
|
|
2347
2393
|
|
|
2348
2394
|
task_run_ids: Optional[List[int]] = None
|
|
2349
2395
|
"""The run IDs of the task runs that ran as part of this repair history item."""
|
|
@@ -2358,6 +2404,7 @@ class RepairHistoryItem:
|
|
|
2358
2404
|
if self.id is not None: body['id'] = self.id
|
|
2359
2405
|
if self.start_time is not None: body['start_time'] = self.start_time
|
|
2360
2406
|
if self.state: body['state'] = self.state.as_dict()
|
|
2407
|
+
if self.status: body['status'] = self.status.as_dict()
|
|
2361
2408
|
if self.task_run_ids: body['task_run_ids'] = [v for v in self.task_run_ids]
|
|
2362
2409
|
if self.type is not None: body['type'] = self.type.value
|
|
2363
2410
|
return body
|
|
@@ -2369,6 +2416,7 @@ class RepairHistoryItem:
|
|
|
2369
2416
|
id=d.get('id', None),
|
|
2370
2417
|
start_time=d.get('start_time', None),
|
|
2371
2418
|
state=_from_dict(d, 'state', RunState),
|
|
2419
|
+
status=_from_dict(d, 'status', RunStatus),
|
|
2372
2420
|
task_run_ids=d.get('task_run_ids', None),
|
|
2373
2421
|
type=_enum(d, 'type', RepairHistoryItemType))
|
|
2374
2422
|
|
|
@@ -2873,7 +2921,10 @@ class Run:
|
|
|
2873
2921
|
scheduled to run on a new cluster, this is the time the cluster creation call is issued."""
|
|
2874
2922
|
|
|
2875
2923
|
state: Optional[RunState] = None
|
|
2876
|
-
"""
|
|
2924
|
+
"""Deprecated. Please use the `status` field instead."""
|
|
2925
|
+
|
|
2926
|
+
status: Optional[RunStatus] = None
|
|
2927
|
+
"""The current status of the run"""
|
|
2877
2928
|
|
|
2878
2929
|
tasks: Optional[List[RunTask]] = None
|
|
2879
2930
|
"""The list of tasks performed by the run. Each task has its own `run_id` which you can use to call
|
|
@@ -2927,6 +2978,7 @@ class Run:
|
|
|
2927
2978
|
if self.setup_duration is not None: body['setup_duration'] = self.setup_duration
|
|
2928
2979
|
if self.start_time is not None: body['start_time'] = self.start_time
|
|
2929
2980
|
if self.state: body['state'] = self.state.as_dict()
|
|
2981
|
+
if self.status: body['status'] = self.status.as_dict()
|
|
2930
2982
|
if self.tasks: body['tasks'] = [v.as_dict() for v in self.tasks]
|
|
2931
2983
|
if self.trigger is not None: body['trigger'] = self.trigger.value
|
|
2932
2984
|
if self.trigger_info: body['trigger_info'] = self.trigger_info.as_dict()
|
|
@@ -2965,6 +3017,7 @@ class Run:
|
|
|
2965
3017
|
setup_duration=d.get('setup_duration', None),
|
|
2966
3018
|
start_time=d.get('start_time', None),
|
|
2967
3019
|
state=_from_dict(d, 'state', RunState),
|
|
3020
|
+
status=_from_dict(d, 'status', RunStatus),
|
|
2968
3021
|
tasks=_repeated_dict(d, 'tasks', RunTask),
|
|
2969
3022
|
trigger=_enum(d, 'trigger', TriggerType),
|
|
2970
3023
|
trigger_info=_from_dict(d, 'trigger_info', TriggerInfo))
|
|
@@ -3216,6 +3269,17 @@ class RunLifeCycleState(Enum):
|
|
|
3216
3269
|
WAITING_FOR_RETRY = 'WAITING_FOR_RETRY'
|
|
3217
3270
|
|
|
3218
3271
|
|
|
3272
|
+
class RunLifecycleStateV2State(Enum):
|
|
3273
|
+
"""The current state of the run."""
|
|
3274
|
+
|
|
3275
|
+
BLOCKED = 'BLOCKED'
|
|
3276
|
+
PENDING = 'PENDING'
|
|
3277
|
+
QUEUED = 'QUEUED'
|
|
3278
|
+
RUNNING = 'RUNNING'
|
|
3279
|
+
TERMINATED = 'TERMINATED'
|
|
3280
|
+
TERMINATING = 'TERMINATING'
|
|
3281
|
+
|
|
3282
|
+
|
|
3219
3283
|
@dataclass
|
|
3220
3284
|
class RunNow:
|
|
3221
3285
|
job_id: int
|
|
@@ -3609,6 +3673,36 @@ class RunState:
|
|
|
3609
3673
|
user_cancelled_or_timedout=d.get('user_cancelled_or_timedout', None))
|
|
3610
3674
|
|
|
3611
3675
|
|
|
3676
|
+
@dataclass
|
|
3677
|
+
class RunStatus:
|
|
3678
|
+
"""The current status of the run"""
|
|
3679
|
+
|
|
3680
|
+
queue_details: Optional[QueueDetails] = None
|
|
3681
|
+
"""If the run was queued, details about the reason for queuing the run."""
|
|
3682
|
+
|
|
3683
|
+
state: Optional[RunLifecycleStateV2State] = None
|
|
3684
|
+
"""The current state of the run."""
|
|
3685
|
+
|
|
3686
|
+
termination_details: Optional[TerminationDetails] = None
|
|
3687
|
+
"""If the run is in a TERMINATING or TERMINATED state, details about the reason for terminating the
|
|
3688
|
+
run."""
|
|
3689
|
+
|
|
3690
|
+
def as_dict(self) -> dict:
|
|
3691
|
+
"""Serializes the RunStatus into a dictionary suitable for use as a JSON request body."""
|
|
3692
|
+
body = {}
|
|
3693
|
+
if self.queue_details: body['queue_details'] = self.queue_details.as_dict()
|
|
3694
|
+
if self.state is not None: body['state'] = self.state.value
|
|
3695
|
+
if self.termination_details: body['termination_details'] = self.termination_details.as_dict()
|
|
3696
|
+
return body
|
|
3697
|
+
|
|
3698
|
+
@classmethod
|
|
3699
|
+
def from_dict(cls, d: Dict[str, any]) -> RunStatus:
|
|
3700
|
+
"""Deserializes the RunStatus from a dictionary."""
|
|
3701
|
+
return cls(queue_details=_from_dict(d, 'queue_details', QueueDetails),
|
|
3702
|
+
state=_enum(d, 'state', RunLifecycleStateV2State),
|
|
3703
|
+
termination_details=_from_dict(d, 'termination_details', TerminationDetails))
|
|
3704
|
+
|
|
3705
|
+
|
|
3612
3706
|
@dataclass
|
|
3613
3707
|
class RunTask:
|
|
3614
3708
|
"""Used when outputting a child run, in GetRun or ListRuns."""
|
|
@@ -3773,7 +3867,10 @@ class RunTask:
|
|
|
3773
3867
|
scheduled to run on a new cluster, this is the time the cluster creation call is issued."""
|
|
3774
3868
|
|
|
3775
3869
|
state: Optional[RunState] = None
|
|
3776
|
-
"""
|
|
3870
|
+
"""Deprecated. Please use the `status` field instead."""
|
|
3871
|
+
|
|
3872
|
+
status: Optional[RunStatus] = None
|
|
3873
|
+
"""The current status of the run"""
|
|
3777
3874
|
|
|
3778
3875
|
timeout_seconds: Optional[int] = None
|
|
3779
3876
|
"""An optional timeout applied to each run of this job task. A value of `0` means no timeout."""
|
|
@@ -3821,6 +3918,7 @@ class RunTask:
|
|
|
3821
3918
|
if self.sql_task: body['sql_task'] = self.sql_task.as_dict()
|
|
3822
3919
|
if self.start_time is not None: body['start_time'] = self.start_time
|
|
3823
3920
|
if self.state: body['state'] = self.state.as_dict()
|
|
3921
|
+
if self.status: body['status'] = self.status.as_dict()
|
|
3824
3922
|
if self.task_key is not None: body['task_key'] = self.task_key
|
|
3825
3923
|
if self.timeout_seconds is not None: body['timeout_seconds'] = self.timeout_seconds
|
|
3826
3924
|
if self.webhook_notifications: body['webhook_notifications'] = self.webhook_notifications.as_dict()
|
|
@@ -3864,6 +3962,7 @@ class RunTask:
|
|
|
3864
3962
|
sql_task=_from_dict(d, 'sql_task', SqlTask),
|
|
3865
3963
|
start_time=d.get('start_time', None),
|
|
3866
3964
|
state=_from_dict(d, 'state', RunState),
|
|
3965
|
+
status=_from_dict(d, 'status', RunStatus),
|
|
3867
3966
|
task_key=d.get('task_key', None),
|
|
3868
3967
|
timeout_seconds=d.get('timeout_seconds', None),
|
|
3869
3968
|
webhook_notifications=_from_dict(d, 'webhook_notifications', WebhookNotifications))
|
|
@@ -5027,6 +5126,149 @@ class TaskNotificationSettings:
|
|
|
5027
5126
|
no_alert_for_skipped_runs=d.get('no_alert_for_skipped_runs', None))
|
|
5028
5127
|
|
|
5029
5128
|
|
|
5129
|
+
class TerminationCodeCode(Enum):
|
|
5130
|
+
"""The code indicates why the run was terminated. Additional codes might be introduced in future
|
|
5131
|
+
releases. * `SUCCESS`: The run was completed successfully. * `CANCELED`: The run was canceled
|
|
5132
|
+
during execution by the Databricks platform; for example, if the maximum run duration was
|
|
5133
|
+
exceeded. * `SKIPPED`: Run was never executed, for example, if the upstream task run failed, the
|
|
5134
|
+
dependency type condition was not met, or there were no material tasks to execute. *
|
|
5135
|
+
`INTERNAL_ERROR`: The run encountered an unexpected error. Refer to the state message for
|
|
5136
|
+
further details. * `DRIVER_ERROR`: The run encountered an error while communicating with the
|
|
5137
|
+
Spark Driver. * `CLUSTER_ERROR`: The run failed due to a cluster error. Refer to the state
|
|
5138
|
+
message for further details. * `REPOSITORY_CHECKOUT_FAILED`: Failed to complete the checkout due
|
|
5139
|
+
to an error when communicating with the third party service. * `INVALID_CLUSTER_REQUEST`: The
|
|
5140
|
+
run failed because it issued an invalid request to start the cluster. *
|
|
5141
|
+
`WORKSPACE_RUN_LIMIT_EXCEEDED`: The workspace has reached the quota for the maximum number of
|
|
5142
|
+
concurrent active runs. Consider scheduling the runs over a larger time frame. *
|
|
5143
|
+
`FEATURE_DISABLED`: The run failed because it tried to access a feature unavailable for the
|
|
5144
|
+
workspace. * `CLUSTER_REQUEST_LIMIT_EXCEEDED`: The number of cluster creation, start, and upsize
|
|
5145
|
+
requests have exceeded the allotted rate limit. Consider spreading the run execution over a
|
|
5146
|
+
larger time frame. * `STORAGE_ACCESS_ERROR`: The run failed due to an error when accessing the
|
|
5147
|
+
customer blob storage. Refer to the state message for further details. * `RUN_EXECUTION_ERROR`:
|
|
5148
|
+
The run was completed with task failures. For more details, refer to the state message or run
|
|
5149
|
+
output. * `UNAUTHORIZED_ERROR`: The run failed due to a permission issue while accessing a
|
|
5150
|
+
resource. Refer to the state message for further details. * `LIBRARY_INSTALLATION_ERROR`: The
|
|
5151
|
+
run failed while installing the user-requested library. Refer to the state message for further
|
|
5152
|
+
details. The causes might include, but are not limited to: The provided library is invalid,
|
|
5153
|
+
there are insufficient permissions to install the library, and so forth. *
|
|
5154
|
+
`MAX_CONCURRENT_RUNS_EXCEEDED`: The scheduled run exceeds the limit of maximum concurrent runs
|
|
5155
|
+
set for the job. * `MAX_SPARK_CONTEXTS_EXCEEDED`: The run is scheduled on a cluster that has
|
|
5156
|
+
already reached the maximum number of contexts it is configured to create. See: [Link]. *
|
|
5157
|
+
`RESOURCE_NOT_FOUND`: A resource necessary for run execution does not exist. Refer to the state
|
|
5158
|
+
message for further details. * `INVALID_RUN_CONFIGURATION`: The run failed due to an invalid
|
|
5159
|
+
configuration. Refer to the state message for further details. * `CLOUD_FAILURE`: The run failed
|
|
5160
|
+
due to a cloud provider issue. Refer to the state message for further details. *
|
|
5161
|
+
`MAX_JOB_QUEUE_SIZE_EXCEEDED`: The run was skipped due to reaching the job level queue size
|
|
5162
|
+
limit.
|
|
5163
|
+
|
|
5164
|
+
[Link]: https://kb.databricks.com/en_US/notebooks/too-many-execution-contexts-are-open-right-now"""
|
|
5165
|
+
|
|
5166
|
+
CANCELED = 'CANCELED'
|
|
5167
|
+
CLOUD_FAILURE = 'CLOUD_FAILURE'
|
|
5168
|
+
CLUSTER_ERROR = 'CLUSTER_ERROR'
|
|
5169
|
+
CLUSTER_REQUEST_LIMIT_EXCEEDED = 'CLUSTER_REQUEST_LIMIT_EXCEEDED'
|
|
5170
|
+
DRIVER_ERROR = 'DRIVER_ERROR'
|
|
5171
|
+
FEATURE_DISABLED = 'FEATURE_DISABLED'
|
|
5172
|
+
INTERNAL_ERROR = 'INTERNAL_ERROR'
|
|
5173
|
+
INVALID_CLUSTER_REQUEST = 'INVALID_CLUSTER_REQUEST'
|
|
5174
|
+
INVALID_RUN_CONFIGURATION = 'INVALID_RUN_CONFIGURATION'
|
|
5175
|
+
LIBRARY_INSTALLATION_ERROR = 'LIBRARY_INSTALLATION_ERROR'
|
|
5176
|
+
MAX_CONCURRENT_RUNS_EXCEEDED = 'MAX_CONCURRENT_RUNS_EXCEEDED'
|
|
5177
|
+
MAX_JOB_QUEUE_SIZE_EXCEEDED = 'MAX_JOB_QUEUE_SIZE_EXCEEDED'
|
|
5178
|
+
MAX_SPARK_CONTEXTS_EXCEEDED = 'MAX_SPARK_CONTEXTS_EXCEEDED'
|
|
5179
|
+
REPOSITORY_CHECKOUT_FAILED = 'REPOSITORY_CHECKOUT_FAILED'
|
|
5180
|
+
RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND'
|
|
5181
|
+
RUN_EXECUTION_ERROR = 'RUN_EXECUTION_ERROR'
|
|
5182
|
+
SKIPPED = 'SKIPPED'
|
|
5183
|
+
STORAGE_ACCESS_ERROR = 'STORAGE_ACCESS_ERROR'
|
|
5184
|
+
SUCCESS = 'SUCCESS'
|
|
5185
|
+
UNAUTHORIZED_ERROR = 'UNAUTHORIZED_ERROR'
|
|
5186
|
+
WORKSPACE_RUN_LIMIT_EXCEEDED = 'WORKSPACE_RUN_LIMIT_EXCEEDED'
|
|
5187
|
+
|
|
5188
|
+
|
|
5189
|
+
@dataclass
|
|
5190
|
+
class TerminationDetails:
|
|
5191
|
+
code: Optional[TerminationCodeCode] = None
|
|
5192
|
+
"""The code indicates why the run was terminated. Additional codes might be introduced in future
|
|
5193
|
+
releases. * `SUCCESS`: The run was completed successfully. * `CANCELED`: The run was canceled
|
|
5194
|
+
during execution by the Databricks platform; for example, if the maximum run duration was
|
|
5195
|
+
exceeded. * `SKIPPED`: Run was never executed, for example, if the upstream task run failed, the
|
|
5196
|
+
dependency type condition was not met, or there were no material tasks to execute. *
|
|
5197
|
+
`INTERNAL_ERROR`: The run encountered an unexpected error. Refer to the state message for
|
|
5198
|
+
further details. * `DRIVER_ERROR`: The run encountered an error while communicating with the
|
|
5199
|
+
Spark Driver. * `CLUSTER_ERROR`: The run failed due to a cluster error. Refer to the state
|
|
5200
|
+
message for further details. * `REPOSITORY_CHECKOUT_FAILED`: Failed to complete the checkout due
|
|
5201
|
+
to an error when communicating with the third party service. * `INVALID_CLUSTER_REQUEST`: The
|
|
5202
|
+
run failed because it issued an invalid request to start the cluster. *
|
|
5203
|
+
`WORKSPACE_RUN_LIMIT_EXCEEDED`: The workspace has reached the quota for the maximum number of
|
|
5204
|
+
concurrent active runs. Consider scheduling the runs over a larger time frame. *
|
|
5205
|
+
`FEATURE_DISABLED`: The run failed because it tried to access a feature unavailable for the
|
|
5206
|
+
workspace. * `CLUSTER_REQUEST_LIMIT_EXCEEDED`: The number of cluster creation, start, and upsize
|
|
5207
|
+
requests have exceeded the allotted rate limit. Consider spreading the run execution over a
|
|
5208
|
+
larger time frame. * `STORAGE_ACCESS_ERROR`: The run failed due to an error when accessing the
|
|
5209
|
+
customer blob storage. Refer to the state message for further details. * `RUN_EXECUTION_ERROR`:
|
|
5210
|
+
The run was completed with task failures. For more details, refer to the state message or run
|
|
5211
|
+
output. * `UNAUTHORIZED_ERROR`: The run failed due to a permission issue while accessing a
|
|
5212
|
+
resource. Refer to the state message for further details. * `LIBRARY_INSTALLATION_ERROR`: The
|
|
5213
|
+
run failed while installing the user-requested library. Refer to the state message for further
|
|
5214
|
+
details. The causes might include, but are not limited to: The provided library is invalid,
|
|
5215
|
+
there are insufficient permissions to install the library, and so forth. *
|
|
5216
|
+
`MAX_CONCURRENT_RUNS_EXCEEDED`: The scheduled run exceeds the limit of maximum concurrent runs
|
|
5217
|
+
set for the job. * `MAX_SPARK_CONTEXTS_EXCEEDED`: The run is scheduled on a cluster that has
|
|
5218
|
+
already reached the maximum number of contexts it is configured to create. See: [Link]. *
|
|
5219
|
+
`RESOURCE_NOT_FOUND`: A resource necessary for run execution does not exist. Refer to the state
|
|
5220
|
+
message for further details. * `INVALID_RUN_CONFIGURATION`: The run failed due to an invalid
|
|
5221
|
+
configuration. Refer to the state message for further details. * `CLOUD_FAILURE`: The run failed
|
|
5222
|
+
due to a cloud provider issue. Refer to the state message for further details. *
|
|
5223
|
+
`MAX_JOB_QUEUE_SIZE_EXCEEDED`: The run was skipped due to reaching the job level queue size
|
|
5224
|
+
limit.
|
|
5225
|
+
|
|
5226
|
+
[Link]: https://kb.databricks.com/en_US/notebooks/too-many-execution-contexts-are-open-right-now"""
|
|
5227
|
+
|
|
5228
|
+
message: Optional[str] = None
|
|
5229
|
+
"""A descriptive message with the termination details. This field is unstructured and the format
|
|
5230
|
+
might change."""
|
|
5231
|
+
|
|
5232
|
+
type: Optional[TerminationTypeType] = None
|
|
5233
|
+
"""* `SUCCESS`: The run terminated without any issues * `INTERNAL_ERROR`: An error occurred in the
|
|
5234
|
+
Databricks platform. Please look at the [status page] or contact support if the issue persists.
|
|
5235
|
+
* `CLIENT_ERROR`: The run was terminated because of an error caused by user input or the job
|
|
5236
|
+
configuration. * `CLOUD_FAILURE`: The run was terminated because of an issue with your cloud
|
|
5237
|
+
provider.
|
|
5238
|
+
|
|
5239
|
+
[status page]: https://status.databricks.com/"""
|
|
5240
|
+
|
|
5241
|
+
def as_dict(self) -> dict:
|
|
5242
|
+
"""Serializes the TerminationDetails into a dictionary suitable for use as a JSON request body."""
|
|
5243
|
+
body = {}
|
|
5244
|
+
if self.code is not None: body['code'] = self.code.value
|
|
5245
|
+
if self.message is not None: body['message'] = self.message
|
|
5246
|
+
if self.type is not None: body['type'] = self.type.value
|
|
5247
|
+
return body
|
|
5248
|
+
|
|
5249
|
+
@classmethod
|
|
5250
|
+
def from_dict(cls, d: Dict[str, any]) -> TerminationDetails:
|
|
5251
|
+
"""Deserializes the TerminationDetails from a dictionary."""
|
|
5252
|
+
return cls(code=_enum(d, 'code', TerminationCodeCode),
|
|
5253
|
+
message=d.get('message', None),
|
|
5254
|
+
type=_enum(d, 'type', TerminationTypeType))
|
|
5255
|
+
|
|
5256
|
+
|
|
5257
|
+
class TerminationTypeType(Enum):
|
|
5258
|
+
"""* `SUCCESS`: The run terminated without any issues * `INTERNAL_ERROR`: An error occurred in the
|
|
5259
|
+
Databricks platform. Please look at the [status page] or contact support if the issue persists.
|
|
5260
|
+
* `CLIENT_ERROR`: The run was terminated because of an error caused by user input or the job
|
|
5261
|
+
configuration. * `CLOUD_FAILURE`: The run was terminated because of an issue with your cloud
|
|
5262
|
+
provider.
|
|
5263
|
+
|
|
5264
|
+
[status page]: https://status.databricks.com/"""
|
|
5265
|
+
|
|
5266
|
+
CLIENT_ERROR = 'CLIENT_ERROR'
|
|
5267
|
+
CLOUD_FAILURE = 'CLOUD_FAILURE'
|
|
5268
|
+
INTERNAL_ERROR = 'INTERNAL_ERROR'
|
|
5269
|
+
SUCCESS = 'SUCCESS'
|
|
5270
|
+
|
|
5271
|
+
|
|
5030
5272
|
@dataclass
|
|
5031
5273
|
class TriggerInfo:
|
|
5032
5274
|
"""Additional details about what triggered the run"""
|
databricks/sdk/service/ml.py
CHANGED
|
@@ -4143,10 +4143,16 @@ class ExperimentsAPI:
|
|
|
4143
4143
|
"""Get all artifacts.
|
|
4144
4144
|
|
|
4145
4145
|
List artifacts for a run. Takes an optional `artifact_path` prefix. If it is specified, the response
|
|
4146
|
-
contains only artifacts with the specified prefix.
|
|
4146
|
+
contains only artifacts with the specified prefix. This API does not support pagination when listing
|
|
4147
|
+
artifacts in UC Volumes. A maximum of 1000 artifacts will be retrieved for UC Volumes. Please call
|
|
4148
|
+
`/api/2.0/fs/directories{directory_path}` for listing artifacts in UC Volumes, which supports
|
|
4149
|
+
pagination. See [List directory contents | Files API](/api/workspace/files/listdirectorycontents).
|
|
4147
4150
|
|
|
4148
4151
|
:param page_token: str (optional)
|
|
4149
|
-
Token indicating the page of artifact results to fetch
|
|
4152
|
+
Token indicating the page of artifact results to fetch. `page_token` is not supported when listing
|
|
4153
|
+
artifacts in UC Volumes. A maximum of 1000 artifacts will be retrieved for UC Volumes. Please call
|
|
4154
|
+
`/api/2.0/fs/directories{directory_path}` for listing artifacts in UC Volumes, which supports
|
|
4155
|
+
pagination. See [List directory contents | Files API](/api/workspace/files/listdirectorycontents).
|
|
4150
4156
|
:param path: str (optional)
|
|
4151
4157
|
Filter artifacts matching this path (a relative path from the root artifact directory).
|
|
4152
4158
|
:param run_id: str (optional)
|
|
@@ -1629,14 +1629,6 @@ class ServedModelInput:
|
|
|
1629
1629
|
model_version: str
|
|
1630
1630
|
"""The version of the model in Databricks Model Registry or Unity Catalog to be served."""
|
|
1631
1631
|
|
|
1632
|
-
workload_size: ServedModelInputWorkloadSize
|
|
1633
|
-
"""The workload size of the served model. The workload size corresponds to a range of provisioned
|
|
1634
|
-
concurrency that the compute will autoscale between. A single unit of provisioned concurrency
|
|
1635
|
-
can process one request at a time. Valid workload sizes are "Small" (4 - 4 provisioned
|
|
1636
|
-
concurrency), "Medium" (8 - 16 provisioned concurrency), and "Large" (16 - 64 provisioned
|
|
1637
|
-
concurrency). If scale-to-zero is enabled, the lower bound of the provisioned concurrency for
|
|
1638
|
-
each workload size will be 0."""
|
|
1639
|
-
|
|
1640
1632
|
scale_to_zero_enabled: bool
|
|
1641
1633
|
"""Whether the compute resources for the served model should scale down to zero."""
|
|
1642
1634
|
|
|
@@ -1649,11 +1641,25 @@ class ServedModelInput:
|
|
|
1649
1641
|
instance_profile_arn: Optional[str] = None
|
|
1650
1642
|
"""ARN of the instance profile that the served model will use to access AWS resources."""
|
|
1651
1643
|
|
|
1644
|
+
max_provisioned_throughput: Optional[int] = None
|
|
1645
|
+
"""The maximum tokens per second that the endpoint can scale up to."""
|
|
1646
|
+
|
|
1647
|
+
min_provisioned_throughput: Optional[int] = None
|
|
1648
|
+
"""The minimum tokens per second that the endpoint can scale down to."""
|
|
1649
|
+
|
|
1652
1650
|
name: Optional[str] = None
|
|
1653
1651
|
"""The name of a served model. It must be unique across an endpoint. If not specified, this field
|
|
1654
1652
|
will default to <model-name>-<model-version>. A served model name can consist of alphanumeric
|
|
1655
1653
|
characters, dashes, and underscores."""
|
|
1656
1654
|
|
|
1655
|
+
workload_size: Optional[ServedModelInputWorkloadSize] = None
|
|
1656
|
+
"""The workload size of the served model. The workload size corresponds to a range of provisioned
|
|
1657
|
+
concurrency that the compute will autoscale between. A single unit of provisioned concurrency
|
|
1658
|
+
can process one request at a time. Valid workload sizes are "Small" (4 - 4 provisioned
|
|
1659
|
+
concurrency), "Medium" (8 - 16 provisioned concurrency), and "Large" (16 - 64 provisioned
|
|
1660
|
+
concurrency). If scale-to-zero is enabled, the lower bound of the provisioned concurrency for
|
|
1661
|
+
each workload size will be 0."""
|
|
1662
|
+
|
|
1657
1663
|
workload_type: Optional[ServedModelInputWorkloadType] = None
|
|
1658
1664
|
"""The workload type of the served model. The workload type selects which type of compute to use in
|
|
1659
1665
|
the endpoint. The default value for this parameter is "CPU". For deep learning workloads, GPU
|
|
@@ -1667,6 +1673,10 @@ class ServedModelInput:
|
|
|
1667
1673
|
body = {}
|
|
1668
1674
|
if self.environment_vars: body['environment_vars'] = self.environment_vars
|
|
1669
1675
|
if self.instance_profile_arn is not None: body['instance_profile_arn'] = self.instance_profile_arn
|
|
1676
|
+
if self.max_provisioned_throughput is not None:
|
|
1677
|
+
body['max_provisioned_throughput'] = self.max_provisioned_throughput
|
|
1678
|
+
if self.min_provisioned_throughput is not None:
|
|
1679
|
+
body['min_provisioned_throughput'] = self.min_provisioned_throughput
|
|
1670
1680
|
if self.model_name is not None: body['model_name'] = self.model_name
|
|
1671
1681
|
if self.model_version is not None: body['model_version'] = self.model_version
|
|
1672
1682
|
if self.name is not None: body['name'] = self.name
|
|
@@ -1680,6 +1690,8 @@ class ServedModelInput:
|
|
|
1680
1690
|
"""Deserializes the ServedModelInput from a dictionary."""
|
|
1681
1691
|
return cls(environment_vars=d.get('environment_vars', None),
|
|
1682
1692
|
instance_profile_arn=d.get('instance_profile_arn', None),
|
|
1693
|
+
max_provisioned_throughput=d.get('max_provisioned_throughput', None),
|
|
1694
|
+
min_provisioned_throughput=d.get('min_provisioned_throughput', None),
|
|
1683
1695
|
model_name=d.get('model_name', None),
|
|
1684
1696
|
model_version=d.get('model_version', None),
|
|
1685
1697
|
name=d.get('name', None),
|
|
@@ -231,6 +231,11 @@ class DeleteIndexResponse:
|
|
|
231
231
|
|
|
232
232
|
@dataclass
|
|
233
233
|
class DeltaSyncVectorIndexSpecRequest:
|
|
234
|
+
columns_to_sync: Optional[List[str]] = None
|
|
235
|
+
"""[Optional] Select the columns to sync with the vector index. If you leave this field blank, all
|
|
236
|
+
columns from the source table are synced with the index. The primary key column and embedding
|
|
237
|
+
source column or embedding vector column are always synced."""
|
|
238
|
+
|
|
234
239
|
embedding_source_columns: Optional[List[EmbeddingSourceColumn]] = None
|
|
235
240
|
"""The columns that contain the embedding source."""
|
|
236
241
|
|
|
@@ -256,6 +261,7 @@ class DeltaSyncVectorIndexSpecRequest:
|
|
|
256
261
|
def as_dict(self) -> dict:
|
|
257
262
|
"""Serializes the DeltaSyncVectorIndexSpecRequest into a dictionary suitable for use as a JSON request body."""
|
|
258
263
|
body = {}
|
|
264
|
+
if self.columns_to_sync: body['columns_to_sync'] = [v for v in self.columns_to_sync]
|
|
259
265
|
if self.embedding_source_columns:
|
|
260
266
|
body['embedding_source_columns'] = [v.as_dict() for v in self.embedding_source_columns]
|
|
261
267
|
if self.embedding_vector_columns:
|
|
@@ -269,7 +275,8 @@ class DeltaSyncVectorIndexSpecRequest:
|
|
|
269
275
|
@classmethod
|
|
270
276
|
def from_dict(cls, d: Dict[str, any]) -> DeltaSyncVectorIndexSpecRequest:
|
|
271
277
|
"""Deserializes the DeltaSyncVectorIndexSpecRequest from a dictionary."""
|
|
272
|
-
return cls(
|
|
278
|
+
return cls(columns_to_sync=d.get('columns_to_sync', None),
|
|
279
|
+
embedding_source_columns=_repeated_dict(d, 'embedding_source_columns',
|
|
273
280
|
EmbeddingSourceColumn),
|
|
274
281
|
embedding_vector_columns=_repeated_dict(d, 'embedding_vector_columns',
|
|
275
282
|
EmbeddingVectorColumn),
|
databricks/sdk/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '0.
|
|
1
|
+
__version__ = '0.32.0'
|
|
@@ -5,7 +5,7 @@ databricks/sdk/azure.py,sha256=8P7nEdun0hbQCap9Ojo7yZse_JHxnhYsE6ApojnPz7Q,1009
|
|
|
5
5
|
databricks/sdk/casing.py,sha256=NKYPrfPbQjM7lU4hhNQK3z1jb_VEA29BfH4FEdby2tg,1137
|
|
6
6
|
databricks/sdk/clock.py,sha256=Ivlow0r_TkXcTJ8UXkxSA0czKrY0GvwHAeOvjPkJnAQ,1360
|
|
7
7
|
databricks/sdk/config.py,sha256=FWEiIY34C_4Mmv8B9w284BR2FHug2T2ySpmtyg51ttA,21139
|
|
8
|
-
databricks/sdk/core.py,sha256=
|
|
8
|
+
databricks/sdk/core.py,sha256=7zjTSCUNrI1R4WFvQ-243tKyuDhBPQdg1rrJB-3IU04,15636
|
|
9
9
|
databricks/sdk/credentials_provider.py,sha256=1y5Very59gwWIJkL3183PwPaYtiYJDAycn1hp2JZVx4,29282
|
|
10
10
|
databricks/sdk/data_plane.py,sha256=Er2z2fT-KVupJKzGozGGZ-jCQ3AmDWq-DZppahIK6tU,2591
|
|
11
11
|
databricks/sdk/dbutils.py,sha256=HFCuB-el6SFKhF8qRfJxYANtyLTm-VG9GtQuQgZXFkM,15741
|
|
@@ -14,17 +14,20 @@ databricks/sdk/oauth.py,sha256=KzcJPYLL3JL6RDvf_Q8SDAaF9xSaoYNCRD4rYInZDuo,18319
|
|
|
14
14
|
databricks/sdk/py.typed,sha256=pSvaHpbY1UPNEXyVFUjlgBhjPFZMmVC_UNrPC7eMOHI,74
|
|
15
15
|
databricks/sdk/retries.py,sha256=WgLh12bwdBc6fCQlaig3kKu18cVhPzFDGsspvq629Ew,2454
|
|
16
16
|
databricks/sdk/useragent.py,sha256=I2-VnJSE6cg9QV4GXkoQSkHsEB3bDvRGgkawbBNl4G0,5540
|
|
17
|
-
databricks/sdk/version.py,sha256=
|
|
17
|
+
databricks/sdk/version.py,sha256=Mhyb-htYwxK6GrdhYyT56CJeGp4A5jZLmueZGXkszEY,23
|
|
18
18
|
databricks/sdk/_widgets/__init__.py,sha256=Qm3JB8LmdPgEn_-VgxKkodTO4gn6OdaDPwsYcDmeIRI,2667
|
|
19
19
|
databricks/sdk/_widgets/default_widgets_utils.py,sha256=Rk59AFzVYVpOektB_yC_7j-vSt5OdtZA85IlG0kw0xA,1202
|
|
20
20
|
databricks/sdk/_widgets/ipywidgets_utils.py,sha256=P-AyGeahPiX3S59mxpAMgffi4gyJ0irEOY7Ekkn9nQ0,2850
|
|
21
|
-
databricks/sdk/errors/__init__.py,sha256=
|
|
22
|
-
databricks/sdk/errors/base.py,sha256=
|
|
23
|
-
databricks/sdk/errors/mapper.py,sha256=
|
|
21
|
+
databricks/sdk/errors/__init__.py,sha256=S_xkqeqBtYrW-QeFL007woajSA07TLwDKCgD0h3zxAI,211
|
|
22
|
+
databricks/sdk/errors/base.py,sha256=eSOKUZ5t8e_S6OFrsEyzx-vraQ0PYemsP98H9Md53M4,4893
|
|
23
|
+
databricks/sdk/errors/mapper.py,sha256=G52KAcRfDFUOjgS-gvh8_X_3FXqN1P5Mmgi6F0VAb5k,1162
|
|
24
24
|
databricks/sdk/errors/overrides.py,sha256=u1fZ1X2gPRv_zf1u_4EqVzbWHiFsPzm_X0sMNOCMwAE,1649
|
|
25
|
+
databricks/sdk/errors/parser.py,sha256=_R8Gd5IMlGQbwsVxDKjTchA46YKAulIENAQm_HjIwyU,6085
|
|
25
26
|
databricks/sdk/errors/platform.py,sha256=0EwGUTcmoobAK41KsFAnRkT6AlOY_umzr4jWEgd-6hY,3113
|
|
26
|
-
databricks/sdk/errors/private_link.py,sha256
|
|
27
|
+
databricks/sdk/errors/private_link.py,sha256=-cDxHSm7MBpdaEFgDGvbrW4dxCRVQwSunGhwe5Ay80g,2314
|
|
27
28
|
databricks/sdk/errors/sdk.py,sha256=_euMruhvquB0v_SKtgqxJUiyXHWuTb4Jl7ji6_h0E_A,109
|
|
29
|
+
databricks/sdk/logger/__init__.py,sha256=0_sSQfDkaFGqMHZUVw-g_Ax-RFmOv0Z6NjxCVAeUSO0,41
|
|
30
|
+
databricks/sdk/logger/round_trip_logger.py,sha256=c33VEVdy_tifQ62lF-2U39nvaRfGaahFqULb0Z7g3mk,4746
|
|
28
31
|
databricks/sdk/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
32
|
databricks/sdk/mixins/compute.py,sha256=khb00BzBckc4RLUF4-GnNMCSO5lXKt_XYMM3IhiUxlA,11237
|
|
30
33
|
databricks/sdk/mixins/files.py,sha256=bLGFu1kVIQECTmuc_9jUf-n_Cth4COBMbmKqAYxkEkM,20542
|
|
@@ -35,26 +38,26 @@ databricks/sdk/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
35
38
|
databricks/sdk/service/_internal.py,sha256=nWbJfW5eJCQgAZ3TmA26xoWb6SNZ5N76ZA8bO1N4AsU,1961
|
|
36
39
|
databricks/sdk/service/apps.py,sha256=536HvScC96edq9EXMUcyVh1h2jE5zCeCMa_l7HZiu20,38170
|
|
37
40
|
databricks/sdk/service/billing.py,sha256=Ru6GumI-M4_X71HTMj2VSVBQ7tRMTrwKzhdwNyiC3fA,69733
|
|
38
|
-
databricks/sdk/service/catalog.py,sha256=
|
|
41
|
+
databricks/sdk/service/catalog.py,sha256=CUm4OCGgvTUNDLXKURsp-Fj5Cx7A-iKTNnQ2dcGSsZ0,434746
|
|
39
42
|
databricks/sdk/service/compute.py,sha256=u8iVnqGFS7WGrLYQ0CrhwQEXs0WkjoPbHsHeVA6-h6g,433402
|
|
40
43
|
databricks/sdk/service/dashboards.py,sha256=-nrRkNLBDJU4w0OAy-EjZkI8I5ktYqX475YTAW65u9I,76081
|
|
41
44
|
databricks/sdk/service/files.py,sha256=VCt83YSI9rhQexmxaQdrUXHq2UCYfZcDMLvJx5X6n1M,38162
|
|
42
|
-
databricks/sdk/service/iam.py,sha256=
|
|
43
|
-
databricks/sdk/service/jobs.py,sha256=
|
|
45
|
+
databricks/sdk/service/iam.py,sha256=P_2k7_MDV-Iw4heUD78i3XQriSoYZX1Jhhfnn4gS4Zk,148548
|
|
46
|
+
databricks/sdk/service/jobs.py,sha256=vcwp6ZaMJ1xo5HPkGg63k-RYVulQmA4zaXcEbJcpGwI,332433
|
|
44
47
|
databricks/sdk/service/marketplace.py,sha256=Fgk_8V9zbQ8QcNPUw-yZehHv8LgnDtFJUe-YixjxkYo,136405
|
|
45
|
-
databricks/sdk/service/ml.py,sha256=
|
|
48
|
+
databricks/sdk/service/ml.py,sha256=KG5nG9ap1IJejha2JFhX13f61C6tShO0AnHvLNDz0KE,236858
|
|
46
49
|
databricks/sdk/service/oauth2.py,sha256=67pr6gUnYwO6BaGNQfjW1qvcEB3ejdNbI9Pmvqs5bSE,39928
|
|
47
50
|
databricks/sdk/service/pipelines.py,sha256=tGCo1F3tW1GxB9Q63qsh2AyisJmXqYSsGkJK0OdS06Q,119378
|
|
48
51
|
databricks/sdk/service/provisioning.py,sha256=DP4Df4X-p0JEUk4zAJQhjX_wxpMi673OKLXFhxl6YSE,142678
|
|
49
|
-
databricks/sdk/service/serving.py,sha256=
|
|
52
|
+
databricks/sdk/service/serving.py,sha256=DfgyhXi1UB88pYJnxXqzYoAZ8vqBCbr5OFitYdHOztA,140737
|
|
50
53
|
databricks/sdk/service/settings.py,sha256=7PXxsrXUe7exM35O7_iUp9r78zn5oGnPbhX_sh3v1_0,193732
|
|
51
54
|
databricks/sdk/service/sharing.py,sha256=kalJYd0v1SwuGhlCaq4l2ZhzNlev9OwNbCXFIOKIMXU,113253
|
|
52
55
|
databricks/sdk/service/sql.py,sha256=RaXIYMDtHbhvB7gtSMyvQsqiO_E0cMz5NXeTsrqtPVk,334558
|
|
53
|
-
databricks/sdk/service/vectorsearch.py,sha256=
|
|
56
|
+
databricks/sdk/service/vectorsearch.py,sha256=a5Y4vrS_oAJJqa69XwKMANhGuZi5glS0PSXBXz1bKGU,62961
|
|
54
57
|
databricks/sdk/service/workspace.py,sha256=FKLf5esRmfFstIXo7HQg6HQCzQ2svrb6ulr8yzZ7-8U,101182
|
|
55
|
-
databricks_sdk-0.
|
|
56
|
-
databricks_sdk-0.
|
|
57
|
-
databricks_sdk-0.
|
|
58
|
-
databricks_sdk-0.
|
|
59
|
-
databricks_sdk-0.
|
|
60
|
-
databricks_sdk-0.
|
|
58
|
+
databricks_sdk-0.32.0.dist-info/LICENSE,sha256=afBgTZo-JsYqj4VOjnejBetMuHKcFR30YobDdpVFkqY,11411
|
|
59
|
+
databricks_sdk-0.32.0.dist-info/METADATA,sha256=5bGVpoXLejnZgLyT7jHHe5zK-7iW7ISiKOVyThA3Il0,37967
|
|
60
|
+
databricks_sdk-0.32.0.dist-info/NOTICE,sha256=Qnc0m8JjZNTDV80y0h1aJGvsr4GqM63m1nr2VTypg6E,963
|
|
61
|
+
databricks_sdk-0.32.0.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
|
|
62
|
+
databricks_sdk-0.32.0.dist-info/top_level.txt,sha256=7kRdatoSgU0EUurRQJ_3F1Nv4EOSHWAr6ng25tJOJKU,11
|
|
63
|
+
databricks_sdk-0.32.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|