databricks-sdk 0.54.0__py3-none-any.whl → 0.56.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.

Files changed (30) hide show
  1. databricks/sdk/__init__.py +304 -278
  2. databricks/sdk/config.py +15 -4
  3. databricks/sdk/credentials_provider.py +101 -55
  4. databricks/sdk/oauth.py +0 -5
  5. databricks/sdk/oidc.py +206 -0
  6. databricks/sdk/service/aibuilder.py +364 -0
  7. databricks/sdk/service/billing.py +150 -169
  8. databricks/sdk/service/catalog.py +263 -835
  9. databricks/sdk/service/cleanrooms.py +15 -10
  10. databricks/sdk/service/compute.py +12 -22
  11. databricks/sdk/service/dashboards.py +59 -451
  12. databricks/sdk/service/database.py +1256 -0
  13. databricks/sdk/service/files.py +2 -0
  14. databricks/sdk/service/iam.py +6 -6
  15. databricks/sdk/service/jobs.py +238 -0
  16. databricks/sdk/service/ml.py +8 -271
  17. databricks/sdk/service/pipelines.py +45 -1
  18. databricks/sdk/service/provisioning.py +0 -3
  19. databricks/sdk/service/qualitymonitorv2.py +275 -0
  20. databricks/sdk/service/serving.py +76 -4
  21. databricks/sdk/service/settings.py +982 -99
  22. databricks/sdk/service/sharing.py +3 -2
  23. databricks/sdk/service/sql.py +218 -1
  24. databricks/sdk/version.py +1 -1
  25. {databricks_sdk-0.54.0.dist-info → databricks_sdk-0.56.0.dist-info}/METADATA +1 -1
  26. {databricks_sdk-0.54.0.dist-info → databricks_sdk-0.56.0.dist-info}/RECORD +30 -26
  27. {databricks_sdk-0.54.0.dist-info → databricks_sdk-0.56.0.dist-info}/WHEEL +1 -1
  28. {databricks_sdk-0.54.0.dist-info → databricks_sdk-0.56.0.dist-info}/licenses/LICENSE +0 -0
  29. {databricks_sdk-0.54.0.dist-info → databricks_sdk-0.56.0.dist-info}/licenses/NOTICE +0 -0
  30. {databricks_sdk-0.54.0.dist-info → databricks_sdk-0.56.0.dist-info}/top_level.txt +0 -0
databricks/sdk/oidc.py ADDED
@@ -0,0 +1,206 @@
1
+ """
2
+ Package oidc provides utilities for working with OIDC ID tokens.
3
+
4
+ This package is experimental and subject to change.
5
+ """
6
+
7
+ import logging
8
+ import os
9
+ from abc import ABC, abstractmethod
10
+ from dataclasses import dataclass
11
+ from typing import Optional
12
+
13
+ from . import oauth
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class IdToken:
20
+ """Represents an OIDC ID token that can be exchanged for a Databricks access token.
21
+
22
+ Parameters
23
+ ----------
24
+ jwt : str
25
+ The signed JWT token string.
26
+ """
27
+
28
+ jwt: str
29
+
30
+
31
+ class IdTokenSource(ABC):
32
+ """Abstract base class representing anything that returns an IDToken.
33
+
34
+ This class defines the interface for token sources that can provide OIDC ID tokens.
35
+ """
36
+
37
+ @abstractmethod
38
+ def id_token(self) -> IdToken:
39
+ """Get an ID token.
40
+
41
+ Returns
42
+ -------
43
+ IdToken
44
+ An ID token.
45
+
46
+ Raises
47
+ ------
48
+ Exception
49
+ Implementation specific exceptions.
50
+ """
51
+
52
+
53
+ class EnvIdTokenSource(IdTokenSource):
54
+ """IDTokenSource that reads the ID token from an environment variable.
55
+
56
+ Parameters
57
+ ----------
58
+ env_var : str
59
+ The name of the environment variable containing the ID token.
60
+ """
61
+
62
+ def __init__(self, env_var: str):
63
+ self.env_var = env_var
64
+
65
+ def id_token(self) -> IdToken:
66
+ """Get an ID token from an environment variable.
67
+
68
+ Returns
69
+ -------
70
+ IdToken
71
+ An ID token.
72
+
73
+ Raises
74
+ ------
75
+ ValueError
76
+ If the environment variable is not set.
77
+ """
78
+ token = os.getenv(self.env_var)
79
+ if not token:
80
+ raise ValueError(f"Missing env var {self.env_var!r}")
81
+ return IdToken(jwt=token)
82
+
83
+
84
+ class FileIdTokenSource(IdTokenSource):
85
+ """IDTokenSource that reads the ID token from a file.
86
+
87
+ Parameters
88
+ ----------
89
+ path : str
90
+ The path to the file containing the ID token.
91
+ """
92
+
93
+ def __init__(self, path: str):
94
+ self.path = path
95
+
96
+ def id_token(self) -> IdToken:
97
+ """Get an ID token from a file.
98
+
99
+ Returns
100
+ -------
101
+ IdToken
102
+ An ID token.
103
+
104
+ Raises
105
+ ------
106
+ ValueError
107
+ If the file is empty, does not exist, or cannot be read.
108
+ """
109
+ if not self.path:
110
+ raise ValueError("Missing path")
111
+
112
+ token = None
113
+ try:
114
+ with open(self.path, "r") as f:
115
+ token = f.read().strip()
116
+ except FileNotFoundError:
117
+ raise ValueError(f"File {self.path!r} does not exist")
118
+ except Exception as e:
119
+ raise ValueError(f"Error reading token file: {str(e)}")
120
+
121
+ if not token:
122
+ raise ValueError(f"File {self.path!r} is empty")
123
+ return IdToken(jwt=token)
124
+
125
+
126
+ class DatabricksOidcTokenSource(oauth.TokenSource):
127
+ """A TokenSource which exchanges a token using Workload Identity Federation.
128
+
129
+ Parameters
130
+ ----------
131
+ host : str
132
+ The host of the Databricks account or workspace.
133
+ id_token_source : IdTokenSource
134
+ IDTokenSource that returns the IDToken to be used for the token exchange.
135
+ token_endpoint_provider : Callable[[], dict]
136
+ Returns the token endpoint for the Databricks OIDC application.
137
+ client_id : Optional[str], optional
138
+ ClientID of the Databricks OIDC application. It corresponds to the
139
+ Application ID of the Databricks Service Principal. Only required for
140
+ Workload Identity Federation and should be empty for Account-wide token
141
+ federation.
142
+ account_id : Optional[str], optional
143
+ The account ID of the Databricks Account. Only required for
144
+ Account-wide token federation.
145
+ audience : Optional[str], optional
146
+ The audience of the Databricks OIDC application. Only used for
147
+ Workspace level tokens.
148
+ """
149
+
150
+ def __init__(
151
+ self,
152
+ host: str,
153
+ token_endpoint: str,
154
+ id_token_source: IdTokenSource,
155
+ client_id: Optional[str] = None,
156
+ account_id: Optional[str] = None,
157
+ audience: Optional[str] = None,
158
+ disable_async: bool = False,
159
+ ):
160
+ self._host = host
161
+ self._id_token_source = id_token_source
162
+ self._token_endpoint = token_endpoint
163
+ self._client_id = client_id
164
+ self._account_id = account_id
165
+ self._audience = audience
166
+ self._disable_async = disable_async
167
+
168
+ def token(self) -> oauth.Token:
169
+ """Get a token by exchanging the ID token.
170
+
171
+ Returns
172
+ -------
173
+ dict
174
+ The exchanged token.
175
+
176
+ Raises
177
+ ------
178
+ ValueError
179
+ If the host is missing or other configuration errors occur.
180
+ """
181
+ if not self._host:
182
+ logger.debug("Missing Host")
183
+ raise ValueError("missing Host")
184
+
185
+ if not self._client_id:
186
+ logger.debug("No ClientID provided, authenticating with Account-wide token federation")
187
+ else:
188
+ logger.debug("Client ID provided, authenticating with Workload Identity Federation")
189
+
190
+ id_token = self._id_token_source.id_token()
191
+
192
+ client = oauth.ClientCredentials(
193
+ client_id=self._client_id,
194
+ client_secret="", # we have no (rotatable) secrets in OIDC flow
195
+ token_url=self._token_endpoint,
196
+ endpoint_params={
197
+ "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
198
+ "subject_token": id_token,
199
+ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
200
+ },
201
+ scopes=["all-apis"],
202
+ use_params=True,
203
+ disable_async=self._disable_async,
204
+ )
205
+
206
+ return client.token()
@@ -0,0 +1,364 @@
1
+ # Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ from ._internal import _enum, _from_dict, _repeated_dict
11
+
12
+ _LOG = logging.getLogger("databricks.sdk")
13
+
14
+
15
+ # all definitions in this file are in alphabetical order
16
+
17
+
18
+ @dataclass
19
+ class CancelCustomLlmOptimizationRunRequest:
20
+ id: Optional[str] = None
21
+
22
+
23
+ @dataclass
24
+ class CancelResponse:
25
+ def as_dict(self) -> dict:
26
+ """Serializes the CancelResponse into a dictionary suitable for use as a JSON request body."""
27
+ body = {}
28
+ return body
29
+
30
+ def as_shallow_dict(self) -> dict:
31
+ """Serializes the CancelResponse into a shallow dictionary of its immediate attributes."""
32
+ body = {}
33
+ return body
34
+
35
+ @classmethod
36
+ def from_dict(cls, d: Dict[str, Any]) -> CancelResponse:
37
+ """Deserializes the CancelResponse from a dictionary."""
38
+ return cls()
39
+
40
+
41
+ @dataclass
42
+ class CustomLlm:
43
+ name: str
44
+ """Name of the custom LLM"""
45
+
46
+ instructions: str
47
+ """Instructions for the custom LLM to follow"""
48
+
49
+ optimization_state: State
50
+ """If optimization is kicked off, tracks the state of the custom LLM"""
51
+
52
+ agent_artifact_path: Optional[str] = None
53
+
54
+ creation_time: Optional[str] = None
55
+ """Creation timestamp of the custom LLM"""
56
+
57
+ creator: Optional[str] = None
58
+ """Creator of the custom LLM"""
59
+
60
+ datasets: Optional[List[Dataset]] = None
61
+ """Datasets used for training and evaluating the model, not for inference"""
62
+
63
+ endpoint_name: Optional[str] = None
64
+ """Name of the endpoint that will be used to serve the custom LLM"""
65
+
66
+ guidelines: Optional[List[str]] = None
67
+ """Guidelines for the custom LLM to adhere to"""
68
+
69
+ id: Optional[str] = None
70
+
71
+ def as_dict(self) -> dict:
72
+ """Serializes the CustomLlm into a dictionary suitable for use as a JSON request body."""
73
+ body = {}
74
+ if self.agent_artifact_path is not None:
75
+ body["agent_artifact_path"] = self.agent_artifact_path
76
+ if self.creation_time is not None:
77
+ body["creation_time"] = self.creation_time
78
+ if self.creator is not None:
79
+ body["creator"] = self.creator
80
+ if self.datasets:
81
+ body["datasets"] = [v.as_dict() for v in self.datasets]
82
+ if self.endpoint_name is not None:
83
+ body["endpoint_name"] = self.endpoint_name
84
+ if self.guidelines:
85
+ body["guidelines"] = [v for v in self.guidelines]
86
+ if self.id is not None:
87
+ body["id"] = self.id
88
+ if self.instructions is not None:
89
+ body["instructions"] = self.instructions
90
+ if self.name is not None:
91
+ body["name"] = self.name
92
+ if self.optimization_state is not None:
93
+ body["optimization_state"] = self.optimization_state.value
94
+ return body
95
+
96
+ def as_shallow_dict(self) -> dict:
97
+ """Serializes the CustomLlm into a shallow dictionary of its immediate attributes."""
98
+ body = {}
99
+ if self.agent_artifact_path is not None:
100
+ body["agent_artifact_path"] = self.agent_artifact_path
101
+ if self.creation_time is not None:
102
+ body["creation_time"] = self.creation_time
103
+ if self.creator is not None:
104
+ body["creator"] = self.creator
105
+ if self.datasets:
106
+ body["datasets"] = self.datasets
107
+ if self.endpoint_name is not None:
108
+ body["endpoint_name"] = self.endpoint_name
109
+ if self.guidelines:
110
+ body["guidelines"] = self.guidelines
111
+ if self.id is not None:
112
+ body["id"] = self.id
113
+ if self.instructions is not None:
114
+ body["instructions"] = self.instructions
115
+ if self.name is not None:
116
+ body["name"] = self.name
117
+ if self.optimization_state is not None:
118
+ body["optimization_state"] = self.optimization_state
119
+ return body
120
+
121
+ @classmethod
122
+ def from_dict(cls, d: Dict[str, Any]) -> CustomLlm:
123
+ """Deserializes the CustomLlm from a dictionary."""
124
+ return cls(
125
+ agent_artifact_path=d.get("agent_artifact_path", None),
126
+ creation_time=d.get("creation_time", None),
127
+ creator=d.get("creator", None),
128
+ datasets=_repeated_dict(d, "datasets", Dataset),
129
+ endpoint_name=d.get("endpoint_name", None),
130
+ guidelines=d.get("guidelines", None),
131
+ id=d.get("id", None),
132
+ instructions=d.get("instructions", None),
133
+ name=d.get("name", None),
134
+ optimization_state=_enum(d, "optimization_state", State),
135
+ )
136
+
137
+
138
+ @dataclass
139
+ class Dataset:
140
+ table: Table
141
+
142
+ def as_dict(self) -> dict:
143
+ """Serializes the Dataset into a dictionary suitable for use as a JSON request body."""
144
+ body = {}
145
+ if self.table:
146
+ body["table"] = self.table.as_dict()
147
+ return body
148
+
149
+ def as_shallow_dict(self) -> dict:
150
+ """Serializes the Dataset into a shallow dictionary of its immediate attributes."""
151
+ body = {}
152
+ if self.table:
153
+ body["table"] = self.table
154
+ return body
155
+
156
+ @classmethod
157
+ def from_dict(cls, d: Dict[str, Any]) -> Dataset:
158
+ """Deserializes the Dataset from a dictionary."""
159
+ return cls(table=_from_dict(d, "table", Table))
160
+
161
+
162
+ @dataclass
163
+ class StartCustomLlmOptimizationRunRequest:
164
+ id: Optional[str] = None
165
+ """The Id of the tile."""
166
+
167
+
168
+ class State(Enum):
169
+ """States of Custom LLM optimization lifecycle."""
170
+
171
+ CANCELLED = "CANCELLED"
172
+ COMPLETED = "COMPLETED"
173
+ CREATED = "CREATED"
174
+ FAILED = "FAILED"
175
+ PENDING = "PENDING"
176
+ RUNNING = "RUNNING"
177
+
178
+
179
+ @dataclass
180
+ class Table:
181
+ table_path: str
182
+ """Full UC table path in catalog.schema.table_name format"""
183
+
184
+ request_col: str
185
+ """Name of the request column"""
186
+
187
+ response_col: Optional[str] = None
188
+ """Optional: Name of the response column if the data is labeled"""
189
+
190
+ def as_dict(self) -> dict:
191
+ """Serializes the Table into a dictionary suitable for use as a JSON request body."""
192
+ body = {}
193
+ if self.request_col is not None:
194
+ body["request_col"] = self.request_col
195
+ if self.response_col is not None:
196
+ body["response_col"] = self.response_col
197
+ if self.table_path is not None:
198
+ body["table_path"] = self.table_path
199
+ return body
200
+
201
+ def as_shallow_dict(self) -> dict:
202
+ """Serializes the Table into a shallow dictionary of its immediate attributes."""
203
+ body = {}
204
+ if self.request_col is not None:
205
+ body["request_col"] = self.request_col
206
+ if self.response_col is not None:
207
+ body["response_col"] = self.response_col
208
+ if self.table_path is not None:
209
+ body["table_path"] = self.table_path
210
+ return body
211
+
212
+ @classmethod
213
+ def from_dict(cls, d: Dict[str, Any]) -> Table:
214
+ """Deserializes the Table from a dictionary."""
215
+ return cls(
216
+ request_col=d.get("request_col", None),
217
+ response_col=d.get("response_col", None),
218
+ table_path=d.get("table_path", None),
219
+ )
220
+
221
+
222
+ @dataclass
223
+ class UpdateCustomLlmRequest:
224
+ custom_llm: CustomLlm
225
+ """The CustomLlm containing the fields which should be updated."""
226
+
227
+ update_mask: str
228
+ """The list of the CustomLlm fields to update. These should correspond to the values (or lack
229
+ thereof) present in `custom_llm`.
230
+
231
+ The field mask must be a single string, with multiple fields separated by commas (no spaces).
232
+ The field path is relative to the resource object, using a dot (`.`) to navigate sub-fields
233
+ (e.g., `author.given_name`). Specification of elements in sequence or map fields is not allowed,
234
+ as only the entire collection field can be specified. Field names must exactly match the
235
+ resource field names.
236
+
237
+ A field mask of `*` indicates full replacement. It’s recommended to always explicitly list the
238
+ fields being updated and avoid using `*` wildcards, as it can lead to unintended results if the
239
+ API changes in the future."""
240
+
241
+ id: Optional[str] = None
242
+ """The id of the custom llm"""
243
+
244
+ def as_dict(self) -> dict:
245
+ """Serializes the UpdateCustomLlmRequest into a dictionary suitable for use as a JSON request body."""
246
+ body = {}
247
+ if self.custom_llm:
248
+ body["custom_llm"] = self.custom_llm.as_dict()
249
+ if self.id is not None:
250
+ body["id"] = self.id
251
+ if self.update_mask is not None:
252
+ body["update_mask"] = self.update_mask
253
+ return body
254
+
255
+ def as_shallow_dict(self) -> dict:
256
+ """Serializes the UpdateCustomLlmRequest into a shallow dictionary of its immediate attributes."""
257
+ body = {}
258
+ if self.custom_llm:
259
+ body["custom_llm"] = self.custom_llm
260
+ if self.id is not None:
261
+ body["id"] = self.id
262
+ if self.update_mask is not None:
263
+ body["update_mask"] = self.update_mask
264
+ return body
265
+
266
+ @classmethod
267
+ def from_dict(cls, d: Dict[str, Any]) -> UpdateCustomLlmRequest:
268
+ """Deserializes the UpdateCustomLlmRequest from a dictionary."""
269
+ return cls(
270
+ custom_llm=_from_dict(d, "custom_llm", CustomLlm),
271
+ id=d.get("id", None),
272
+ update_mask=d.get("update_mask", None),
273
+ )
274
+
275
+
276
+ class CustomLlmsAPI:
277
+ """The Custom LLMs service manages state and powers the UI for the Custom LLM product."""
278
+
279
+ def __init__(self, api_client):
280
+ self._api = api_client
281
+
282
+ def cancel(self, id: str):
283
+ """Cancel a Custom LLM Optimization Run.
284
+
285
+ :param id: str
286
+
287
+
288
+ """
289
+
290
+ headers = {
291
+ "Accept": "application/json",
292
+ "Content-Type": "application/json",
293
+ }
294
+
295
+ self._api.do("POST", f"/api/2.0/custom-llms/{id}/optimize/cancel", headers=headers)
296
+
297
+ def create(self, id: str) -> CustomLlm:
298
+ """Start a Custom LLM Optimization Run.
299
+
300
+ :param id: str
301
+ The Id of the tile.
302
+
303
+ :returns: :class:`CustomLlm`
304
+ """
305
+
306
+ headers = {
307
+ "Accept": "application/json",
308
+ "Content-Type": "application/json",
309
+ }
310
+
311
+ res = self._api.do("POST", f"/api/2.0/custom-llms/{id}/optimize", headers=headers)
312
+ return CustomLlm.from_dict(res)
313
+
314
+ def get(self, id: str) -> CustomLlm:
315
+ """Get a Custom LLM.
316
+
317
+ :param id: str
318
+ The id of the custom llm
319
+
320
+ :returns: :class:`CustomLlm`
321
+ """
322
+
323
+ headers = {
324
+ "Accept": "application/json",
325
+ }
326
+
327
+ res = self._api.do("GET", f"/api/2.0/custom-llms/{id}", headers=headers)
328
+ return CustomLlm.from_dict(res)
329
+
330
+ def update(self, id: str, custom_llm: CustomLlm, update_mask: str) -> CustomLlm:
331
+ """Update a Custom LLM.
332
+
333
+ :param id: str
334
+ The id of the custom llm
335
+ :param custom_llm: :class:`CustomLlm`
336
+ The CustomLlm containing the fields which should be updated.
337
+ :param update_mask: str
338
+ The list of the CustomLlm fields to update. These should correspond to the values (or lack thereof)
339
+ present in `custom_llm`.
340
+
341
+ The field mask must be a single string, with multiple fields separated by commas (no spaces). The
342
+ field path is relative to the resource object, using a dot (`.`) to navigate sub-fields (e.g.,
343
+ `author.given_name`). Specification of elements in sequence or map fields is not allowed, as only
344
+ the entire collection field can be specified. Field names must exactly match the resource field
345
+ names.
346
+
347
+ A field mask of `*` indicates full replacement. It’s recommended to always explicitly list the
348
+ fields being updated and avoid using `*` wildcards, as it can lead to unintended results if the API
349
+ changes in the future.
350
+
351
+ :returns: :class:`CustomLlm`
352
+ """
353
+ body = {}
354
+ if custom_llm is not None:
355
+ body["custom_llm"] = custom_llm.as_dict()
356
+ if update_mask is not None:
357
+ body["update_mask"] = update_mask
358
+ headers = {
359
+ "Accept": "application/json",
360
+ "Content-Type": "application/json",
361
+ }
362
+
363
+ res = self._api.do("PATCH", f"/api/2.0/custom-llms/{id}", body=body, headers=headers)
364
+ return CustomLlm.from_dict(res)