Skip to content

Commit 71d4b6b

Browse files
committed
Merge branch 'main' of github.com:databricks/databricks-sdk-py into JOBS-22486-getrun-fix
2 parents ed32c31 + b64ef18 commit 71d4b6b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2720
-495
lines changed

.codegen/_openapi_sha

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
58905570a9928fc9ed31fba14a2edaf9a7c55b08
1+
c72c58f97b950fcb924a90ef164bcb10cfcd5ece

CHANGELOG.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,61 @@
11
# Version changelog
22

3+
## [Release] Release v0.43.0
4+
5+
### API Changes:
6+
7+
* Added [w.lakeview_embedded](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/lakeview_embedded.html) workspace-level service and [w.query_execution](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/query_execution.html) workspace-level service.
8+
* Added [w.redash_config](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/redash_config.html) workspace-level service.
9+
* Added `gcp_oauth_token` field for `databricks.sdk.service.catalog.TemporaryCredentials`.
10+
* Added `options` field for `databricks.sdk.service.catalog.UpdateCatalog`.
11+
* Added `disabled` field for `databricks.sdk.service.jobs.RunTask`.
12+
13+
OpenAPI SHA: c72c58f97b950fcb924a90ef164bcb10cfcd5ece, Date: 2025-02-03
14+
15+
### Bug Fixes
16+
17+
* Fix docs generation when two services have the same name ([#872](https://github.com/databricks/databricks-sdk-py/pull/872)).
18+
19+
### Internal Changes
20+
21+
* Add CICD environment to the User Agent ([#866](https://github.com/databricks/databricks-sdk-py/pull/866)).
22+
* Add unit tests for retriable requests ([#879](https://github.com/databricks/databricks-sdk-py/pull/879)).
23+
* Extract "before retry" handler, use it to rewind the stream ([#878](https://github.com/databricks/databricks-sdk-py/pull/878)).
24+
* Update Model Serving `http_request` mixin to correctly use the underlying API. ([#876](https://github.com/databricks/databricks-sdk-py/pull/876)).
25+
26+
### Backward Incompatible Changes
27+
28+
* Changed `create()` method for [w.serving_endpoints](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/serving/serving_endpoints.html) workspace-level service with new required argument order.
29+
* Changed `http_request()` method for [w.serving_endpoints](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/serving/serving_endpoints.html) workspace-level service to type `http_request()` method for [w.serving_endpoints](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/serving/serving_endpoints.html) workspace-level service.
30+
* Changed `http_request()` method for [w.serving_endpoints](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/serving/serving_endpoints.html) workspace-level service to return `databricks.sdk.service.serving.HttpRequestResponse` dataclass.
31+
* Changed `config` field for `databricks.sdk.service.serving.CreateServingEndpoint` to no longer be required.
32+
* Removed `securable_kind` field for `databricks.sdk.service.catalog.CatalogInfo`.
33+
* Removed `securable_kind` field for `databricks.sdk.service.catalog.ConnectionInfo`.
34+
* Removed `status_code` and `text` fields for `databricks.sdk.service.serving.ExternalFunctionResponse`.
35+
36+
### API Changes:
37+
38+
* Added [a.budget_policy](https://databricks-sdk-py.readthedocs.io/en/latest/account/billing/budget_policy.html) account-level service.
39+
* Added [a.enable_ip_access_lists](https://databricks-sdk-py.readthedocs.io/en/latest/account/settings/settings/enable_ip_access_lists.html) account-level service.
40+
* Added `review_state`, `reviews` and `runner_collaborators` fields for `databricks.sdk.service.cleanrooms.CleanRoomAssetNotebook`.
41+
* Added `statement_id` field for `databricks.sdk.service.dashboards.QueryAttachment`.
42+
* Added `effective_performance_target` field for `databricks.sdk.service.jobs.BaseRun`.
43+
* Added `performance_target` field for `databricks.sdk.service.jobs.CreateJob`.
44+
* Added `performance_target` field for `databricks.sdk.service.jobs.JobSettings`.
45+
* Added `effective_performance_target` field for `databricks.sdk.service.jobs.Run`.
46+
* Added `performance_target` field for `databricks.sdk.service.jobs.RunNow`.
47+
* Added `effective_performance_target` field for `databricks.sdk.service.jobs.RunTask`.
48+
* Added `run_as_repl` field for `databricks.sdk.service.jobs.SparkJarTask`.
49+
* Added `user_authorized_scopes` field for `databricks.sdk.service.oauth2.CreateCustomAppIntegration`.
50+
* Added `user_authorized_scopes` field for `databricks.sdk.service.oauth2.GetCustomAppIntegrationOutput`.
51+
* Added `user_authorized_scopes` field for `databricks.sdk.service.oauth2.UpdateCustomAppIntegration`.
52+
* Added `contents` field for `databricks.sdk.service.serving.HttpRequestResponse`.
53+
* Added `clean_room` enum value for `databricks.sdk.service.catalog.SecurableType`.
54+
* Added `budget_policy_limit_exceeded` enum value for `databricks.sdk.service.jobs.TerminationCodeCode`.
55+
* Added `arclight_azure_exchange_token_with_user_delegation_key` enum value for `databricks.sdk.service.settings.TokenType`.
56+
57+
OpenAPI SHA: 840c660106f820a1a5dff931d51fa5f65cd9fdd9, Date: 2025-01-28
58+
359
## [Release] Release v0.41.0
460

561
### New Features and Improvements

databricks/sdk/__init__.py

Lines changed: 33 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

databricks/sdk/_base_client.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,29 @@ def do(self,
159159
if isinstance(data, (str, bytes)):
160160
data = io.BytesIO(data.encode('utf-8') if isinstance(data, str) else data)
161161

162-
# Only retry if the request is not a stream or if the stream is seekable and
163-
# we can rewind it. This is necessary to avoid bugs where the retry doesn't
164-
# re-read already read data from the body.
165-
if data is not None and not self._is_seekable_stream(data):
166-
logger.debug(f"Retry disabled for non-seekable stream: type={type(data)}")
167-
call = self._perform
168-
else:
162+
if not data:
163+
# The request is not a stream.
169164
call = retried(timeout=timedelta(seconds=self._retry_timeout_seconds),
170165
is_retryable=self._is_retryable,
171166
clock=self._clock)(self._perform)
167+
elif self._is_seekable_stream(data):
168+
# Keep track of the initial position of the stream so that we can rewind to it
169+
# if we need to retry the request.
170+
initial_data_position = data.tell()
171+
172+
def rewind():
173+
logger.debug(f"Rewinding input data to offset {initial_data_position} before retry")
174+
data.seek(initial_data_position)
175+
176+
call = retried(timeout=timedelta(seconds=self._retry_timeout_seconds),
177+
is_retryable=self._is_retryable,
178+
clock=self._clock,
179+
before_retry=rewind)(self._perform)
180+
else:
181+
# Do not retry if the stream is not seekable. This is necessary to avoid bugs
182+
# where the retry doesn't re-read already read data from the stream.
183+
logger.debug(f"Retry disabled for non-seekable stream: type={type(data)}")
184+
call = self._perform
172185

173186
response = call(method,
174187
url,
@@ -249,12 +262,6 @@ def _perform(self,
249262
files=None,
250263
data=None,
251264
auth: Callable[[requests.PreparedRequest], requests.PreparedRequest] = None):
252-
# Keep track of the initial position of the stream so that we can rewind it if
253-
# we need to retry the request.
254-
initial_data_position = 0
255-
if self._is_seekable_stream(data):
256-
initial_data_position = data.tell()
257-
258265
response = self._session.request(method,
259266
url,
260267
params=self._fix_query_string(query),
@@ -266,16 +273,8 @@ def _perform(self,
266273
stream=raw,
267274
timeout=self._http_timeout_seconds)
268275
self._record_request_log(response, raw=raw or data is not None or files is not None)
269-
270276
error = self._error_parser.get_api_error(response)
271277
if error is not None:
272-
# If the request body is a seekable stream, rewind it so that it is ready
273-
# to be read again in case of a retry.
274-
#
275-
# TODO: This should be moved into a "before-retry" hook to avoid one
276-
# unnecessary seek on the last failed retry before aborting.
277-
if self._is_seekable_stream(data):
278-
data.seek(initial_data_position)
279278
raise error from None
280279

281280
return response

databricks/sdk/credentials_provider.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -676,12 +676,18 @@ def __init__(self, cfg: 'Config'):
676676
self.host = cfg.host
677677

678678
def refresh(self) -> Token:
679-
resp = requests.get(self.url,
680-
timeout=self._metadata_service_timeout,
681-
headers={
682-
self.METADATA_SERVICE_VERSION_HEADER: self.METADATA_SERVICE_VERSION,
683-
self.METADATA_SERVICE_HOST_HEADER: self.host
684-
})
679+
resp = requests.get(
680+
self.url,
681+
timeout=self._metadata_service_timeout,
682+
headers={
683+
self.METADATA_SERVICE_VERSION_HEADER: self.METADATA_SERVICE_VERSION,
684+
self.METADATA_SERVICE_HOST_HEADER: self.host
685+
},
686+
proxies={
687+
# Explicitly exclude localhost from being proxied. This is necessary
688+
# for Metadata URLs which typically point to localhost.
689+
"no_proxy": "localhost,127.0.0.1"
690+
})
685691
json_resp: dict[str, Union[str, float]] = resp.json()
686692
access_token = json_resp.get("access_token", None)
687693
if access_token is None:

databricks/sdk/mixins/open_ai_client.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import json as js
22
from typing import Dict, Optional
33

4+
from requests import Response
5+
46
from databricks.sdk.service.serving import (ExternalFunctionRequestHttpMethod,
5-
ExternalFunctionResponse,
67
ServingEndpointsAPI)
78

89

@@ -63,7 +64,7 @@ def http_request(self,
6364
*,
6465
headers: Optional[Dict[str, str]] = None,
6566
json: Optional[Dict[str, str]] = None,
66-
params: Optional[Dict[str, str]] = None) -> ExternalFunctionResponse:
67+
params: Optional[Dict[str, str]] = None) -> Response:
6768
"""Make external services call using the credentials stored in UC Connection.
6869
**NOTE:** Experimental: This API may change or be removed in a future release without warning.
6970
:param conn: str
@@ -79,13 +80,27 @@ def http_request(self,
7980
JSON payload for the request.
8081
:param params: Dict[str,str] (optional)
8182
Query parameters for the request.
82-
:returns: :class:`ExternalFunctionResponse`
83+
:returns: :class:`Response`
8384
"""
85+
response = Response()
86+
response.status_code = 200
87+
server_response = super().http_request(connection_name=conn,
88+
method=method,
89+
path=path,
90+
headers=js.dumps(headers) if headers is not None else None,
91+
json=js.dumps(json) if json is not None else None,
92+
params=js.dumps(params) if params is not None else None)
93+
94+
# Read the content from the HttpRequestResponse object
95+
if hasattr(server_response, "contents") and hasattr(server_response.contents, "read"):
96+
raw_content = server_response.contents.read() # Read the bytes
97+
else:
98+
raise ValueError("Invalid response from the server.")
99+
100+
# Set the raw content
101+
if isinstance(raw_content, bytes):
102+
response._content = raw_content
103+
else:
104+
raise ValueError("Contents must be bytes.")
84105

85-
return super.http_request(connection_name=conn,
86-
method=method,
87-
path=path,
88-
headers=js.dumps(headers),
89-
json=js.dumps(json),
90-
params=js.dumps(params),
91-
)
106+
return response

databricks/sdk/retries.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ def retried(*,
1313
on: Sequence[Type[BaseException]] = None,
1414
is_retryable: Callable[[BaseException], Optional[str]] = None,
1515
timeout=timedelta(minutes=20),
16-
clock: Clock = None):
16+
clock: Clock = None,
17+
before_retry: Callable = None):
1718
has_allowlist = on is not None
1819
has_callback = is_retryable is not None
1920
if not (has_allowlist or has_callback) or (has_allowlist and has_callback):
@@ -54,6 +55,9 @@ def wrapper(*args, **kwargs):
5455
raise err
5556

5657
logger.debug(f'Retrying: {retry_reason} (sleeping ~{sleep}s)')
58+
if before_retry:
59+
before_retry()
60+
5761
clock.sleep(sleep + random())
5862
attempt += 1
5963
raise TimeoutError(f'Timed out after {timeout}') from last_err

0 commit comments

Comments
 (0)