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 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, error_mapper
16
- from .errors.private_link import _is_private_link_redirect
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
- try:
266
- self._record_request_log(response, raw=raw or data is not None or files is not None)
267
- if not response.ok: # internally calls response.raise_for_status()
268
- # TODO: experiment with traceback pruning for better readability
269
- # See https://stackoverflow.com/a/58821552/277035
270
- payload = response.json()
271
- raise self._make_nicer_error(response=response, **payload) from None
272
- # Private link failures happen via a redirect to the login page. From a requests-perspective, the request
273
- # is successful, but the response is not what we expect. We need to handle this case separately.
274
- if _is_private_link_redirect(response):
275
- raise self._make_nicer_error(response=response) from None
276
- return response
277
- except requests.exceptions.JSONDecodeError:
278
- message = self._make_sense_from_html(response.text)
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
- request = response.request
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):
@@ -1,5 +1,6 @@
1
1
  from .base import DatabricksError, ErrorDetail
2
- from .mapper import error_mapper
2
+ from .mapper import _error_mapper
3
+ from .parser import get_api_error
3
4
  from .platform import *
4
5
  from .private_link import PrivateLinkValidationError
5
6
  from .sdk import *
@@ -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
- # API 1.2 has different response format, let's adapt
46
- message = error
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
@@ -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 error_mapper(response: requests.Response, raw: dict) -> DatabricksError:
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) -> _PrivateLinkInfo:
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 for the metastore."""
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 for the metastore.
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
 
@@ -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, jobs,
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, jobs,
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, jobs,
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, jobs,
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)
@@ -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
- """The current state of the run."""
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
- """The current state of the run."""
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
- """The current state of the run."""
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
- """The current state of the run."""
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"""
@@ -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(embedding_source_columns=_repeated_dict(d, 'embedding_source_columns',
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.31.1'
1
+ __version__ = '0.32.0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: databricks-sdk
3
- Version: 0.31.1
3
+ Version: 0.32.0
4
4
  Summary: Databricks SDK for Python (Beta)
5
5
  Home-page: https://databricks-sdk-py.readthedocs.io
6
6
  Author: Serge Smertin
@@ -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=PWU2kTHXOF6x7i9_yRUFGj-iusr_Mo7awROiBpA9nJQ,20398
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=tRB_zFsl50GcGW0VJzWbf3saZdjvFdafbOBwklaz9EU,23
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=3l_wHB0S9Y6mDc_c5mUHb-TndDQxa-tdPeWmTbnBNAo,176
22
- databricks/sdk/errors/base.py,sha256=oawBxpuoyImsLu29ntpAgOc6RQ7kD-UcuFFER9jB3iI,3880
23
- databricks/sdk/errors/mapper.py,sha256=sK4aoloV-F8h1J4YHFrcNVAUBLLQQFti-ceXVmm6HpU,1386
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=6wVRJQqousGQC7qfT0pV8LqujqfR3XLbSix_XjqVC8s,2304
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=pJ3LWcHaljhfXKAJoHnbJpaiSOUpGymsWLHfSYaDOdo,430741
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=fj1RQtCdg8E8oUt1SEnm6PzMR6UB-jaCn8M354KiB-o,148500
43
- databricks/sdk/service/jobs.py,sha256=c9m2GoNfMBCGSfr82MZd6zf2aDIza6Ip0jaaW8E_3hQ,318698
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=vohBdESClI3EOpO-ZZ44W-CMz1alq5Tw4oJnWa99Z2M,236128
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=BfShf0ceupXgLccU5zp1CZyBW1260Ga73USM2T5KxXs,140008
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=ZfiTEpTNg8nnzPuw24MeiDn8eq6PHmEWqTHS0zdDdEo,62484
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.31.1.dist-info/LICENSE,sha256=afBgTZo-JsYqj4VOjnejBetMuHKcFR30YobDdpVFkqY,11411
56
- databricks_sdk-0.31.1.dist-info/METADATA,sha256=pXe1gIePCrKpmVF1TtO18KrN6u7DTwWjbi1a2vXWpc4,37967
57
- databricks_sdk-0.31.1.dist-info/NOTICE,sha256=Qnc0m8JjZNTDV80y0h1aJGvsr4GqM63m1nr2VTypg6E,963
58
- databricks_sdk-0.31.1.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
59
- databricks_sdk-0.31.1.dist-info/top_level.txt,sha256=7kRdatoSgU0EUurRQJ_3F1Nv4EOSHWAr6ng25tJOJKU,11
60
- databricks_sdk-0.31.1.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.0.0)
2
+ Generator: setuptools (74.1.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5