databricks-sdk 0.29.0__py3-none-any.whl → 0.31.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 +89 -21
  2. databricks/sdk/config.py +61 -75
  3. databricks/sdk/core.py +16 -9
  4. databricks/sdk/credentials_provider.py +15 -15
  5. databricks/sdk/data_plane.py +65 -0
  6. databricks/sdk/errors/overrides.py +8 -0
  7. databricks/sdk/errors/platform.py +5 -0
  8. databricks/sdk/mixins/files.py +12 -4
  9. databricks/sdk/service/apps.py +977 -0
  10. databricks/sdk/service/billing.py +602 -218
  11. databricks/sdk/service/catalog.py +324 -34
  12. databricks/sdk/service/compute.py +766 -81
  13. databricks/sdk/service/dashboards.py +628 -18
  14. databricks/sdk/service/iam.py +99 -88
  15. databricks/sdk/service/jobs.py +332 -23
  16. databricks/sdk/service/marketplace.py +2 -122
  17. databricks/sdk/service/oauth2.py +127 -70
  18. databricks/sdk/service/pipelines.py +72 -52
  19. databricks/sdk/service/serving.py +303 -750
  20. databricks/sdk/service/settings.py +423 -4
  21. databricks/sdk/service/sharing.py +235 -25
  22. databricks/sdk/service/sql.py +2328 -544
  23. databricks/sdk/useragent.py +151 -0
  24. databricks/sdk/version.py +1 -1
  25. {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.31.0.dist-info}/METADATA +36 -16
  26. {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.31.0.dist-info}/RECORD +30 -27
  27. {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.31.0.dist-info}/WHEEL +1 -1
  28. {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.31.0.dist-info}/LICENSE +0 -0
  29. {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.31.0.dist-info}/NOTICE +0 -0
  30. {databricks_sdk-0.29.0.dist-info → databricks_sdk-0.31.0.dist-info}/top_level.txt +0 -0
@@ -3,14 +3,20 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import logging
6
+ import random
7
+ import time
6
8
  from dataclasses import dataclass
9
+ from datetime import timedelta
7
10
  from enum import Enum
8
- from typing import Dict, Iterator, List, Optional
11
+ from typing import Callable, Dict, Iterator, List, Optional
9
12
 
10
- from ._internal import _enum, _from_dict, _repeated_dict
13
+ from ..errors import OperationFailed
14
+ from ._internal import Wait, _enum, _from_dict, _repeated_dict
11
15
 
12
16
  _LOG = logging.getLogger('databricks.sdk')
13
17
 
18
+ from databricks.sdk.service import sql
19
+
14
20
  # all definitions in this file are in alphabetical order
15
21
 
16
22
 
@@ -21,10 +27,11 @@ class CreateDashboardRequest:
21
27
 
22
28
  parent_path: Optional[str] = None
23
29
  """The workspace path of the folder containing the dashboard. Includes leading slash and no
24
- trailing slash."""
30
+ trailing slash. This field is excluded in List Dashboards responses."""
25
31
 
26
32
  serialized_dashboard: Optional[str] = None
27
- """The contents of the dashboard in serialized string form."""
33
+ """The contents of the dashboard in serialized string form. This field is excluded in List
34
+ Dashboards responses."""
28
35
 
29
36
  warehouse_id: Optional[str] = None
30
37
  """The warehouse ID used to run the dashboard."""
@@ -148,23 +155,26 @@ class Dashboard:
148
155
 
149
156
  etag: Optional[str] = None
150
157
  """The etag for the dashboard. Can be optionally provided on updates to ensure that the dashboard
151
- has not been modified since the last read."""
158
+ has not been modified since the last read. This field is excluded in List Dashboards responses."""
152
159
 
153
160
  lifecycle_state: Optional[LifecycleState] = None
154
161
  """The state of the dashboard resource. Used for tracking trashed status."""
155
162
 
156
163
  parent_path: Optional[str] = None
157
164
  """The workspace path of the folder containing the dashboard. Includes leading slash and no
158
- trailing slash."""
165
+ trailing slash. This field is excluded in List Dashboards responses."""
159
166
 
160
167
  path: Optional[str] = None
161
- """The workspace path of the dashboard asset, including the file name."""
168
+ """The workspace path of the dashboard asset, including the file name. This field is excluded in
169
+ List Dashboards responses."""
162
170
 
163
171
  serialized_dashboard: Optional[str] = None
164
- """The contents of the dashboard in serialized string form."""
172
+ """The contents of the dashboard in serialized string form. This field is excluded in List
173
+ Dashboards responses."""
165
174
 
166
175
  update_time: Optional[str] = None
167
- """The timestamp of when the dashboard was last updated by the user."""
176
+ """The timestamp of when the dashboard was last updated by the user. This field is excluded in List
177
+ Dashboards responses."""
168
178
 
169
179
  warehouse_id: Optional[str] = None
170
180
  """The warehouse ID used to run the dashboard."""
@@ -202,7 +212,6 @@ class Dashboard:
202
212
  class DashboardView(Enum):
203
213
 
204
214
  DASHBOARD_VIEW_BASIC = 'DASHBOARD_VIEW_BASIC'
205
- DASHBOARD_VIEW_FULL = 'DASHBOARD_VIEW_FULL'
206
215
 
207
216
 
208
217
  @dataclass
@@ -233,6 +242,244 @@ class DeleteSubscriptionResponse:
233
242
  return cls()
234
243
 
235
244
 
245
+ @dataclass
246
+ class GenieAttachment:
247
+ """Genie AI Response"""
248
+
249
+ query: Optional[QueryAttachment] = None
250
+
251
+ text: Optional[TextAttachment] = None
252
+
253
+ def as_dict(self) -> dict:
254
+ """Serializes the GenieAttachment into a dictionary suitable for use as a JSON request body."""
255
+ body = {}
256
+ if self.query: body['query'] = self.query.as_dict()
257
+ if self.text: body['text'] = self.text.as_dict()
258
+ return body
259
+
260
+ @classmethod
261
+ def from_dict(cls, d: Dict[str, any]) -> GenieAttachment:
262
+ """Deserializes the GenieAttachment from a dictionary."""
263
+ return cls(query=_from_dict(d, 'query', QueryAttachment), text=_from_dict(d, 'text', TextAttachment))
264
+
265
+
266
+ @dataclass
267
+ class GenieConversation:
268
+ id: str
269
+ """Conversation ID"""
270
+
271
+ space_id: str
272
+ """Genie space ID"""
273
+
274
+ user_id: int
275
+ """ID of the user who created the conversation"""
276
+
277
+ title: str
278
+ """Conversation title"""
279
+
280
+ created_timestamp: Optional[int] = None
281
+ """Timestamp when the message was created"""
282
+
283
+ last_updated_timestamp: Optional[int] = None
284
+ """Timestamp when the message was last updated"""
285
+
286
+ def as_dict(self) -> dict:
287
+ """Serializes the GenieConversation into a dictionary suitable for use as a JSON request body."""
288
+ body = {}
289
+ if self.created_timestamp is not None: body['created_timestamp'] = self.created_timestamp
290
+ if self.id is not None: body['id'] = self.id
291
+ if self.last_updated_timestamp is not None:
292
+ body['last_updated_timestamp'] = self.last_updated_timestamp
293
+ if self.space_id is not None: body['space_id'] = self.space_id
294
+ if self.title is not None: body['title'] = self.title
295
+ if self.user_id is not None: body['user_id'] = self.user_id
296
+ return body
297
+
298
+ @classmethod
299
+ def from_dict(cls, d: Dict[str, any]) -> GenieConversation:
300
+ """Deserializes the GenieConversation from a dictionary."""
301
+ return cls(created_timestamp=d.get('created_timestamp', None),
302
+ id=d.get('id', None),
303
+ last_updated_timestamp=d.get('last_updated_timestamp', None),
304
+ space_id=d.get('space_id', None),
305
+ title=d.get('title', None),
306
+ user_id=d.get('user_id', None))
307
+
308
+
309
+ @dataclass
310
+ class GenieCreateConversationMessageRequest:
311
+ content: str
312
+ """User message content."""
313
+
314
+ conversation_id: Optional[str] = None
315
+ """The ID associated with the conversation."""
316
+
317
+ space_id: Optional[str] = None
318
+ """The ID associated with the Genie space where the conversation is started."""
319
+
320
+ def as_dict(self) -> dict:
321
+ """Serializes the GenieCreateConversationMessageRequest into a dictionary suitable for use as a JSON request body."""
322
+ body = {}
323
+ if self.content is not None: body['content'] = self.content
324
+ if self.conversation_id is not None: body['conversation_id'] = self.conversation_id
325
+ if self.space_id is not None: body['space_id'] = self.space_id
326
+ return body
327
+
328
+ @classmethod
329
+ def from_dict(cls, d: Dict[str, any]) -> GenieCreateConversationMessageRequest:
330
+ """Deserializes the GenieCreateConversationMessageRequest from a dictionary."""
331
+ return cls(content=d.get('content', None),
332
+ conversation_id=d.get('conversation_id', None),
333
+ space_id=d.get('space_id', None))
334
+
335
+
336
+ @dataclass
337
+ class GenieGetMessageQueryResultResponse:
338
+ statement_response: Optional[sql.StatementResponse] = None
339
+ """SQL Statement Execution response. See [Get status, manifest, and result first
340
+ chunk](:method:statementexecution/getstatement) for more details."""
341
+
342
+ def as_dict(self) -> dict:
343
+ """Serializes the GenieGetMessageQueryResultResponse into a dictionary suitable for use as a JSON request body."""
344
+ body = {}
345
+ if self.statement_response: body['statement_response'] = self.statement_response.as_dict()
346
+ return body
347
+
348
+ @classmethod
349
+ def from_dict(cls, d: Dict[str, any]) -> GenieGetMessageQueryResultResponse:
350
+ """Deserializes the GenieGetMessageQueryResultResponse from a dictionary."""
351
+ return cls(statement_response=_from_dict(d, 'statement_response', sql.StatementResponse))
352
+
353
+
354
+ @dataclass
355
+ class GenieMessage:
356
+ id: str
357
+ """Message ID"""
358
+
359
+ space_id: str
360
+ """Genie space ID"""
361
+
362
+ conversation_id: str
363
+ """Conversation ID"""
364
+
365
+ content: str
366
+ """User message content"""
367
+
368
+ attachments: Optional[List[GenieAttachment]] = None
369
+ """AI produced response to the message"""
370
+
371
+ created_timestamp: Optional[int] = None
372
+ """Timestamp when the message was created"""
373
+
374
+ error: Optional[MessageError] = None
375
+ """Error message if AI failed to respond to the message"""
376
+
377
+ last_updated_timestamp: Optional[int] = None
378
+ """Timestamp when the message was last updated"""
379
+
380
+ query_result: Optional[Result] = None
381
+ """The result of SQL query if the message has a query attachment"""
382
+
383
+ status: Optional[MessageStatus] = None
384
+ """MesssageStatus. The possible values are: * `FETCHING_METADATA`: Fetching metadata from the data
385
+ sources. * `ASKING_AI`: Waiting for the LLM to respond to the users question. *
386
+ `EXECUTING_QUERY`: Executing AI provided SQL query. Get the SQL query result by calling
387
+ [getMessageQueryResult](:method:genie/getMessageQueryResult) API. **Important: The message
388
+ status will stay in the `EXECUTING_QUERY` until a client calls
389
+ [getMessageQueryResult](:method:genie/getMessageQueryResult)**. * `FAILED`: Generating a
390
+ response or the executing the query failed. Please see `error` field. * `COMPLETED`: Message
391
+ processing is completed. Results are in the `attachments` field. Get the SQL query result by
392
+ calling [getMessageQueryResult](:method:genie/getMessageQueryResult) API. * `SUBMITTED`: Message
393
+ has been submitted. * `QUERY_RESULT_EXPIRED`: SQL result is not available anymore. The user
394
+ needs to execute the query again. * `CANCELLED`: Message has been cancelled."""
395
+
396
+ user_id: Optional[int] = None
397
+ """ID of the user who created the message"""
398
+
399
+ def as_dict(self) -> dict:
400
+ """Serializes the GenieMessage into a dictionary suitable for use as a JSON request body."""
401
+ body = {}
402
+ if self.attachments: body['attachments'] = [v.as_dict() for v in self.attachments]
403
+ if self.content is not None: body['content'] = self.content
404
+ if self.conversation_id is not None: body['conversation_id'] = self.conversation_id
405
+ if self.created_timestamp is not None: body['created_timestamp'] = self.created_timestamp
406
+ if self.error: body['error'] = self.error.as_dict()
407
+ if self.id is not None: body['id'] = self.id
408
+ if self.last_updated_timestamp is not None:
409
+ body['last_updated_timestamp'] = self.last_updated_timestamp
410
+ if self.query_result: body['query_result'] = self.query_result.as_dict()
411
+ if self.space_id is not None: body['space_id'] = self.space_id
412
+ if self.status is not None: body['status'] = self.status.value
413
+ if self.user_id is not None: body['user_id'] = self.user_id
414
+ return body
415
+
416
+ @classmethod
417
+ def from_dict(cls, d: Dict[str, any]) -> GenieMessage:
418
+ """Deserializes the GenieMessage from a dictionary."""
419
+ return cls(attachments=_repeated_dict(d, 'attachments', GenieAttachment),
420
+ content=d.get('content', None),
421
+ conversation_id=d.get('conversation_id', None),
422
+ created_timestamp=d.get('created_timestamp', None),
423
+ error=_from_dict(d, 'error', MessageError),
424
+ id=d.get('id', None),
425
+ last_updated_timestamp=d.get('last_updated_timestamp', None),
426
+ query_result=_from_dict(d, 'query_result', Result),
427
+ space_id=d.get('space_id', None),
428
+ status=_enum(d, 'status', MessageStatus),
429
+ user_id=d.get('user_id', None))
430
+
431
+
432
+ @dataclass
433
+ class GenieStartConversationMessageRequest:
434
+ content: str
435
+ """The text of the message that starts the conversation."""
436
+
437
+ space_id: Optional[str] = None
438
+ """The ID associated with the Genie space where you want to start a conversation."""
439
+
440
+ def as_dict(self) -> dict:
441
+ """Serializes the GenieStartConversationMessageRequest into a dictionary suitable for use as a JSON request body."""
442
+ body = {}
443
+ if self.content is not None: body['content'] = self.content
444
+ if self.space_id is not None: body['space_id'] = self.space_id
445
+ return body
446
+
447
+ @classmethod
448
+ def from_dict(cls, d: Dict[str, any]) -> GenieStartConversationMessageRequest:
449
+ """Deserializes the GenieStartConversationMessageRequest from a dictionary."""
450
+ return cls(content=d.get('content', None), space_id=d.get('space_id', None))
451
+
452
+
453
+ @dataclass
454
+ class GenieStartConversationResponse:
455
+ message_id: str
456
+ """Message ID"""
457
+
458
+ conversation_id: str
459
+ """Conversation ID"""
460
+
461
+ conversation: Optional[GenieConversation] = None
462
+
463
+ message: Optional[GenieMessage] = None
464
+
465
+ def as_dict(self) -> dict:
466
+ """Serializes the GenieStartConversationResponse into a dictionary suitable for use as a JSON request body."""
467
+ body = {}
468
+ if self.conversation: body['conversation'] = self.conversation.as_dict()
469
+ if self.conversation_id is not None: body['conversation_id'] = self.conversation_id
470
+ if self.message: body['message'] = self.message.as_dict()
471
+ if self.message_id is not None: body['message_id'] = self.message_id
472
+ return body
473
+
474
+ @classmethod
475
+ def from_dict(cls, d: Dict[str, any]) -> GenieStartConversationResponse:
476
+ """Deserializes the GenieStartConversationResponse from a dictionary."""
477
+ return cls(conversation=_from_dict(d, 'conversation', GenieConversation),
478
+ conversation_id=d.get('conversation_id', None),
479
+ message=_from_dict(d, 'message', GenieMessage),
480
+ message_id=d.get('message_id', None))
481
+
482
+
236
483
  class LifecycleState(Enum):
237
484
 
238
485
  ACTIVE = 'ACTIVE'
@@ -305,6 +552,90 @@ class ListSubscriptionsResponse:
305
552
  subscriptions=_repeated_dict(d, 'subscriptions', Subscription))
306
553
 
307
554
 
555
+ @dataclass
556
+ class MessageError:
557
+ error: Optional[str] = None
558
+
559
+ type: Optional[MessageErrorType] = None
560
+
561
+ def as_dict(self) -> dict:
562
+ """Serializes the MessageError into a dictionary suitable for use as a JSON request body."""
563
+ body = {}
564
+ if self.error is not None: body['error'] = self.error
565
+ if self.type is not None: body['type'] = self.type.value
566
+ return body
567
+
568
+ @classmethod
569
+ def from_dict(cls, d: Dict[str, any]) -> MessageError:
570
+ """Deserializes the MessageError from a dictionary."""
571
+ return cls(error=d.get('error', None), type=_enum(d, 'type', MessageErrorType))
572
+
573
+
574
+ class MessageErrorType(Enum):
575
+
576
+ BLOCK_MULTIPLE_EXECUTIONS_EXCEPTION = 'BLOCK_MULTIPLE_EXECUTIONS_EXCEPTION'
577
+ CHAT_COMPLETION_CLIENT_EXCEPTION = 'CHAT_COMPLETION_CLIENT_EXCEPTION'
578
+ CHAT_COMPLETION_CLIENT_TIMEOUT_EXCEPTION = 'CHAT_COMPLETION_CLIENT_TIMEOUT_EXCEPTION'
579
+ CHAT_COMPLETION_NETWORK_EXCEPTION = 'CHAT_COMPLETION_NETWORK_EXCEPTION'
580
+ CONTENT_FILTER_EXCEPTION = 'CONTENT_FILTER_EXCEPTION'
581
+ CONTEXT_EXCEEDED_EXCEPTION = 'CONTEXT_EXCEEDED_EXCEPTION'
582
+ COULD_NOT_GET_UC_SCHEMA_EXCEPTION = 'COULD_NOT_GET_UC_SCHEMA_EXCEPTION'
583
+ DEPLOYMENT_NOT_FOUND_EXCEPTION = 'DEPLOYMENT_NOT_FOUND_EXCEPTION'
584
+ FUNCTIONS_NOT_AVAILABLE_EXCEPTION = 'FUNCTIONS_NOT_AVAILABLE_EXCEPTION'
585
+ FUNCTION_ARGUMENTS_INVALID_EXCEPTION = 'FUNCTION_ARGUMENTS_INVALID_EXCEPTION'
586
+ FUNCTION_ARGUMENTS_INVALID_JSON_EXCEPTION = 'FUNCTION_ARGUMENTS_INVALID_JSON_EXCEPTION'
587
+ FUNCTION_CALL_MISSING_PARAMETER_EXCEPTION = 'FUNCTION_CALL_MISSING_PARAMETER_EXCEPTION'
588
+ GENERIC_CHAT_COMPLETION_EXCEPTION = 'GENERIC_CHAT_COMPLETION_EXCEPTION'
589
+ GENERIC_CHAT_COMPLETION_SERVICE_EXCEPTION = 'GENERIC_CHAT_COMPLETION_SERVICE_EXCEPTION'
590
+ GENERIC_SQL_EXEC_API_CALL_EXCEPTION = 'GENERIC_SQL_EXEC_API_CALL_EXCEPTION'
591
+ ILLEGAL_PARAMETER_DEFINITION_EXCEPTION = 'ILLEGAL_PARAMETER_DEFINITION_EXCEPTION'
592
+ INVALID_CERTIFIED_ANSWER_FUNCTION_EXCEPTION = 'INVALID_CERTIFIED_ANSWER_FUNCTION_EXCEPTION'
593
+ INVALID_CERTIFIED_ANSWER_IDENTIFIER_EXCEPTION = 'INVALID_CERTIFIED_ANSWER_IDENTIFIER_EXCEPTION'
594
+ INVALID_CHAT_COMPLETION_JSON_EXCEPTION = 'INVALID_CHAT_COMPLETION_JSON_EXCEPTION'
595
+ INVALID_COMPLETION_REQUEST_EXCEPTION = 'INVALID_COMPLETION_REQUEST_EXCEPTION'
596
+ INVALID_FUNCTION_CALL_EXCEPTION = 'INVALID_FUNCTION_CALL_EXCEPTION'
597
+ INVALID_TABLE_IDENTIFIER_EXCEPTION = 'INVALID_TABLE_IDENTIFIER_EXCEPTION'
598
+ LOCAL_CONTEXT_EXCEEDED_EXCEPTION = 'LOCAL_CONTEXT_EXCEEDED_EXCEPTION'
599
+ MESSAGE_DELETED_WHILE_EXECUTING_EXCEPTION = 'MESSAGE_DELETED_WHILE_EXECUTING_EXCEPTION'
600
+ MESSAGE_UPDATED_WHILE_EXECUTING_EXCEPTION = 'MESSAGE_UPDATED_WHILE_EXECUTING_EXCEPTION'
601
+ NO_TABLES_TO_QUERY_EXCEPTION = 'NO_TABLES_TO_QUERY_EXCEPTION'
602
+ RATE_LIMIT_EXCEEDED_GENERIC_EXCEPTION = 'RATE_LIMIT_EXCEEDED_GENERIC_EXCEPTION'
603
+ RATE_LIMIT_EXCEEDED_SPECIFIED_WAIT_EXCEPTION = 'RATE_LIMIT_EXCEEDED_SPECIFIED_WAIT_EXCEPTION'
604
+ REPLY_PROCESS_TIMEOUT_EXCEPTION = 'REPLY_PROCESS_TIMEOUT_EXCEPTION'
605
+ RETRYABLE_PROCESSING_EXCEPTION = 'RETRYABLE_PROCESSING_EXCEPTION'
606
+ SQL_EXECUTION_EXCEPTION = 'SQL_EXECUTION_EXCEPTION'
607
+ TABLES_MISSING_EXCEPTION = 'TABLES_MISSING_EXCEPTION'
608
+ TOO_MANY_CERTIFIED_ANSWERS_EXCEPTION = 'TOO_MANY_CERTIFIED_ANSWERS_EXCEPTION'
609
+ TOO_MANY_TABLES_EXCEPTION = 'TOO_MANY_TABLES_EXCEPTION'
610
+ UNEXPECTED_REPLY_PROCESS_EXCEPTION = 'UNEXPECTED_REPLY_PROCESS_EXCEPTION'
611
+ UNKNOWN_AI_MODEL = 'UNKNOWN_AI_MODEL'
612
+ WAREHOUSE_ACCESS_MISSING_EXCEPTION = 'WAREHOUSE_ACCESS_MISSING_EXCEPTION'
613
+ WAREHOUSE_NOT_FOUND_EXCEPTION = 'WAREHOUSE_NOT_FOUND_EXCEPTION'
614
+
615
+
616
+ class MessageStatus(Enum):
617
+ """MesssageStatus. The possible values are: * `FETCHING_METADATA`: Fetching metadata from the data
618
+ sources. * `ASKING_AI`: Waiting for the LLM to respond to the users question. *
619
+ `EXECUTING_QUERY`: Executing AI provided SQL query. Get the SQL query result by calling
620
+ [getMessageQueryResult](:method:genie/getMessageQueryResult) API. **Important: The message
621
+ status will stay in the `EXECUTING_QUERY` until a client calls
622
+ [getMessageQueryResult](:method:genie/getMessageQueryResult)**. * `FAILED`: Generating a
623
+ response or the executing the query failed. Please see `error` field. * `COMPLETED`: Message
624
+ processing is completed. Results are in the `attachments` field. Get the SQL query result by
625
+ calling [getMessageQueryResult](:method:genie/getMessageQueryResult) API. * `SUBMITTED`: Message
626
+ has been submitted. * `QUERY_RESULT_EXPIRED`: SQL result is not available anymore. The user
627
+ needs to execute the query again. * `CANCELLED`: Message has been cancelled."""
628
+
629
+ ASKING_AI = 'ASKING_AI'
630
+ CANCELLED = 'CANCELLED'
631
+ COMPLETED = 'COMPLETED'
632
+ EXECUTING_QUERY = 'EXECUTING_QUERY'
633
+ FAILED = 'FAILED'
634
+ FETCHING_METADATA = 'FETCHING_METADATA'
635
+ QUERY_RESULT_EXPIRED = 'QUERY_RESULT_EXPIRED'
636
+ SUBMITTED = 'SUBMITTED'
637
+
638
+
308
639
  @dataclass
309
640
  class MigrateDashboardRequest:
310
641
  source_dashboard_id: str
@@ -392,6 +723,76 @@ class PublishedDashboard:
392
723
  warehouse_id=d.get('warehouse_id', None))
393
724
 
394
725
 
726
+ @dataclass
727
+ class QueryAttachment:
728
+ description: Optional[str] = None
729
+ """Description of the query"""
730
+
731
+ id: Optional[str] = None
732
+
733
+ instruction_id: Optional[str] = None
734
+ """If the query was created on an instruction (trusted asset) we link to the id"""
735
+
736
+ instruction_title: Optional[str] = None
737
+ """Always store the title next to the id in case the original instruction title changes or the
738
+ instruction is deleted."""
739
+
740
+ last_updated_timestamp: Optional[int] = None
741
+ """Time when the user updated the query last"""
742
+
743
+ query: Optional[str] = None
744
+ """AI generated SQL query"""
745
+
746
+ title: Optional[str] = None
747
+ """Name of the query"""
748
+
749
+ def as_dict(self) -> dict:
750
+ """Serializes the QueryAttachment into a dictionary suitable for use as a JSON request body."""
751
+ body = {}
752
+ if self.description is not None: body['description'] = self.description
753
+ if self.id is not None: body['id'] = self.id
754
+ if self.instruction_id is not None: body['instruction_id'] = self.instruction_id
755
+ if self.instruction_title is not None: body['instruction_title'] = self.instruction_title
756
+ if self.last_updated_timestamp is not None:
757
+ body['last_updated_timestamp'] = self.last_updated_timestamp
758
+ if self.query is not None: body['query'] = self.query
759
+ if self.title is not None: body['title'] = self.title
760
+ return body
761
+
762
+ @classmethod
763
+ def from_dict(cls, d: Dict[str, any]) -> QueryAttachment:
764
+ """Deserializes the QueryAttachment from a dictionary."""
765
+ return cls(description=d.get('description', None),
766
+ id=d.get('id', None),
767
+ instruction_id=d.get('instruction_id', None),
768
+ instruction_title=d.get('instruction_title', None),
769
+ last_updated_timestamp=d.get('last_updated_timestamp', None),
770
+ query=d.get('query', None),
771
+ title=d.get('title', None))
772
+
773
+
774
+ @dataclass
775
+ class Result:
776
+ row_count: Optional[int] = None
777
+ """Row count of the result"""
778
+
779
+ statement_id: Optional[str] = None
780
+ """Statement Execution API statement id. Use [Get status, manifest, and result first
781
+ chunk](:method:statementexecution/getstatement) to get the full result data."""
782
+
783
+ def as_dict(self) -> dict:
784
+ """Serializes the Result into a dictionary suitable for use as a JSON request body."""
785
+ body = {}
786
+ if self.row_count is not None: body['row_count'] = self.row_count
787
+ if self.statement_id is not None: body['statement_id'] = self.statement_id
788
+ return body
789
+
790
+ @classmethod
791
+ def from_dict(cls, d: Dict[str, any]) -> Result:
792
+ """Deserializes the Result from a dictionary."""
793
+ return cls(row_count=d.get('row_count', None), statement_id=d.get('statement_id', None))
794
+
795
+
395
796
  @dataclass
396
797
  class Schedule:
397
798
  cron_schedule: CronSchedule
@@ -565,6 +966,26 @@ class SubscriptionSubscriberUser:
565
966
  return cls(user_id=d.get('user_id', None))
566
967
 
567
968
 
969
+ @dataclass
970
+ class TextAttachment:
971
+ content: Optional[str] = None
972
+ """AI generated message"""
973
+
974
+ id: Optional[str] = None
975
+
976
+ def as_dict(self) -> dict:
977
+ """Serializes the TextAttachment into a dictionary suitable for use as a JSON request body."""
978
+ body = {}
979
+ if self.content is not None: body['content'] = self.content
980
+ if self.id is not None: body['id'] = self.id
981
+ return body
982
+
983
+ @classmethod
984
+ def from_dict(cls, d: Dict[str, any]) -> TextAttachment:
985
+ """Deserializes the TextAttachment from a dictionary."""
986
+ return cls(content=d.get('content', None), id=d.get('id', None))
987
+
988
+
568
989
  @dataclass
569
990
  class TrashDashboardResponse:
570
991
 
@@ -603,10 +1024,11 @@ class UpdateDashboardRequest:
603
1024
 
604
1025
  etag: Optional[str] = None
605
1026
  """The etag for the dashboard. Can be optionally provided on updates to ensure that the dashboard
606
- has not been modified since the last read."""
1027
+ has not been modified since the last read. This field is excluded in List Dashboards responses."""
607
1028
 
608
1029
  serialized_dashboard: Optional[str] = None
609
- """The contents of the dashboard in serialized string form."""
1030
+ """The contents of the dashboard in serialized string form. This field is excluded in List
1031
+ Dashboards responses."""
610
1032
 
611
1033
  warehouse_id: Optional[str] = None
612
1034
  """The warehouse ID used to run the dashboard."""
@@ -675,6 +1097,193 @@ class UpdateScheduleRequest:
675
1097
  schedule_id=d.get('schedule_id', None))
676
1098
 
677
1099
 
1100
+ class GenieAPI:
1101
+ """Genie provides a no-code experience for business users, powered by AI/BI. Analysts set up spaces that
1102
+ business users can use to ask questions using natural language. Genie uses data registered to Unity
1103
+ Catalog and requires at least CAN USE permission on a Pro or Serverless SQL warehouse. Also, Databricks
1104
+ Assistant must be enabled."""
1105
+
1106
+ def __init__(self, api_client):
1107
+ self._api = api_client
1108
+
1109
+ def wait_get_message_genie_completed(
1110
+ self,
1111
+ conversation_id: str,
1112
+ message_id: str,
1113
+ space_id: str,
1114
+ timeout=timedelta(minutes=20),
1115
+ callback: Optional[Callable[[GenieMessage], None]] = None) -> GenieMessage:
1116
+ deadline = time.time() + timeout.total_seconds()
1117
+ target_states = (MessageStatus.COMPLETED, )
1118
+ failure_states = (MessageStatus.FAILED, )
1119
+ status_message = 'polling...'
1120
+ attempt = 1
1121
+ while time.time() < deadline:
1122
+ poll = self.get_message(conversation_id=conversation_id, message_id=message_id, space_id=space_id)
1123
+ status = poll.status
1124
+ status_message = f'current status: {status}'
1125
+ if status in target_states:
1126
+ return poll
1127
+ if callback:
1128
+ callback(poll)
1129
+ if status in failure_states:
1130
+ msg = f'failed to reach COMPLETED, got {status}: {status_message}'
1131
+ raise OperationFailed(msg)
1132
+ prefix = f"conversation_id={conversation_id}, message_id={message_id}, space_id={space_id}"
1133
+ sleep = attempt
1134
+ if sleep > 10:
1135
+ # sleep 10s max per attempt
1136
+ sleep = 10
1137
+ _LOG.debug(f'{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)')
1138
+ time.sleep(sleep + random.random())
1139
+ attempt += 1
1140
+ raise TimeoutError(f'timed out after {timeout}: {status_message}')
1141
+
1142
+ def create_message(self, space_id: str, conversation_id: str, content: str) -> Wait[GenieMessage]:
1143
+ """Create conversation message.
1144
+
1145
+ Create new message in [conversation](:method:genie/startconversation). The AI response uses all
1146
+ previously created messages in the conversation to respond.
1147
+
1148
+ :param space_id: str
1149
+ The ID associated with the Genie space where the conversation is started.
1150
+ :param conversation_id: str
1151
+ The ID associated with the conversation.
1152
+ :param content: str
1153
+ User message content.
1154
+
1155
+ :returns:
1156
+ Long-running operation waiter for :class:`GenieMessage`.
1157
+ See :method:wait_get_message_genie_completed for more details.
1158
+ """
1159
+ body = {}
1160
+ if content is not None: body['content'] = content
1161
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
1162
+
1163
+ op_response = self._api.do(
1164
+ 'POST',
1165
+ f'/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages',
1166
+ body=body,
1167
+ headers=headers)
1168
+ return Wait(self.wait_get_message_genie_completed,
1169
+ response=GenieMessage.from_dict(op_response),
1170
+ conversation_id=conversation_id,
1171
+ message_id=op_response['id'],
1172
+ space_id=space_id)
1173
+
1174
+ def create_message_and_wait(self,
1175
+ space_id: str,
1176
+ conversation_id: str,
1177
+ content: str,
1178
+ timeout=timedelta(minutes=20)) -> GenieMessage:
1179
+ return self.create_message(content=content, conversation_id=conversation_id,
1180
+ space_id=space_id).result(timeout=timeout)
1181
+
1182
+ def execute_message_query(self, space_id: str, conversation_id: str,
1183
+ message_id: str) -> GenieGetMessageQueryResultResponse:
1184
+ """Execute SQL query in a conversation message.
1185
+
1186
+ Execute the SQL query in the message.
1187
+
1188
+ :param space_id: str
1189
+ Genie space ID
1190
+ :param conversation_id: str
1191
+ Conversation ID
1192
+ :param message_id: str
1193
+ Message ID
1194
+
1195
+ :returns: :class:`GenieGetMessageQueryResultResponse`
1196
+ """
1197
+
1198
+ headers = {'Accept': 'application/json', }
1199
+
1200
+ res = self._api.do(
1201
+ 'POST',
1202
+ f'/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/execute-query',
1203
+ headers=headers)
1204
+ return GenieGetMessageQueryResultResponse.from_dict(res)
1205
+
1206
+ def get_message(self, space_id: str, conversation_id: str, message_id: str) -> GenieMessage:
1207
+ """Get conversation message.
1208
+
1209
+ Get message from conversation.
1210
+
1211
+ :param space_id: str
1212
+ The ID associated with the Genie space where the target conversation is located.
1213
+ :param conversation_id: str
1214
+ The ID associated with the target conversation.
1215
+ :param message_id: str
1216
+ The ID associated with the target message from the identified conversation.
1217
+
1218
+ :returns: :class:`GenieMessage`
1219
+ """
1220
+
1221
+ headers = {'Accept': 'application/json', }
1222
+
1223
+ res = self._api.do(
1224
+ 'GET',
1225
+ f'/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}',
1226
+ headers=headers)
1227
+ return GenieMessage.from_dict(res)
1228
+
1229
+ def get_message_query_result(self, space_id: str, conversation_id: str,
1230
+ message_id: str) -> GenieGetMessageQueryResultResponse:
1231
+ """Get conversation message SQL query result.
1232
+
1233
+ Get the result of SQL query if the message has a query attachment. This is only available if a message
1234
+ has a query attachment and the message status is `EXECUTING_QUERY`.
1235
+
1236
+ :param space_id: str
1237
+ Genie space ID
1238
+ :param conversation_id: str
1239
+ Conversation ID
1240
+ :param message_id: str
1241
+ Message ID
1242
+
1243
+ :returns: :class:`GenieGetMessageQueryResultResponse`
1244
+ """
1245
+
1246
+ headers = {'Accept': 'application/json', }
1247
+
1248
+ res = self._api.do(
1249
+ 'GET',
1250
+ f'/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/query-result',
1251
+ headers=headers)
1252
+ return GenieGetMessageQueryResultResponse.from_dict(res)
1253
+
1254
+ def start_conversation(self, space_id: str, content: str) -> Wait[GenieMessage]:
1255
+ """Start conversation.
1256
+
1257
+ Start a new conversation.
1258
+
1259
+ :param space_id: str
1260
+ The ID associated with the Genie space where you want to start a conversation.
1261
+ :param content: str
1262
+ The text of the message that starts the conversation.
1263
+
1264
+ :returns:
1265
+ Long-running operation waiter for :class:`GenieMessage`.
1266
+ See :method:wait_get_message_genie_completed for more details.
1267
+ """
1268
+ body = {}
1269
+ if content is not None: body['content'] = content
1270
+ headers = {'Accept': 'application/json', 'Content-Type': 'application/json', }
1271
+
1272
+ op_response = self._api.do('POST',
1273
+ f'/api/2.0/genie/spaces/{space_id}/start-conversation',
1274
+ body=body,
1275
+ headers=headers)
1276
+ return Wait(self.wait_get_message_genie_completed,
1277
+ response=GenieStartConversationResponse.from_dict(op_response),
1278
+ conversation_id=op_response['conversation_id'],
1279
+ message_id=op_response['message_id'],
1280
+ space_id=space_id)
1281
+
1282
+ def start_conversation_and_wait(self, space_id: str, content: str,
1283
+ timeout=timedelta(minutes=20)) -> GenieMessage:
1284
+ return self.start_conversation(content=content, space_id=space_id).result(timeout=timeout)
1285
+
1286
+
678
1287
  class LakeviewAPI:
679
1288
  """These APIs provide specific management operations for Lakeview dashboards. Generic resource management can
680
1289
  be done with Workspace API (import, export, get-status, list, delete)."""
@@ -696,9 +1305,10 @@ class LakeviewAPI:
696
1305
  The display name of the dashboard.
697
1306
  :param parent_path: str (optional)
698
1307
  The workspace path of the folder containing the dashboard. Includes leading slash and no trailing
699
- slash.
1308
+ slash. This field is excluded in List Dashboards responses.
700
1309
  :param serialized_dashboard: str (optional)
701
- The contents of the dashboard in serialized string form.
1310
+ The contents of the dashboard in serialized string form. This field is excluded in List Dashboards
1311
+ responses.
702
1312
  :param warehouse_id: str (optional)
703
1313
  The warehouse ID used to run the dashboard.
704
1314
 
@@ -911,8 +1521,7 @@ class LakeviewAPI:
911
1521
  The flag to include dashboards located in the trash. If unspecified, only active dashboards will be
912
1522
  returned.
913
1523
  :param view: :class:`DashboardView` (optional)
914
- Indicates whether to include all metadata from the dashboard in the response. If unset, the response
915
- defaults to `DASHBOARD_VIEW_BASIC` which only includes summary metadata from the dashboard.
1524
+ `DASHBOARD_VIEW_BASIC`only includes summary metadata from the dashboard.
916
1525
 
917
1526
  :returns: Iterator over :class:`Dashboard`
918
1527
  """
@@ -1111,9 +1720,10 @@ class LakeviewAPI:
1111
1720
  The display name of the dashboard.
1112
1721
  :param etag: str (optional)
1113
1722
  The etag for the dashboard. Can be optionally provided on updates to ensure that the dashboard has
1114
- not been modified since the last read.
1723
+ not been modified since the last read. This field is excluded in List Dashboards responses.
1115
1724
  :param serialized_dashboard: str (optional)
1116
- The contents of the dashboard in serialized string form.
1725
+ The contents of the dashboard in serialized string form. This field is excluded in List Dashboards
1726
+ responses.
1117
1727
  :param warehouse_id: str (optional)
1118
1728
  The warehouse ID used to run the dashboard.
1119
1729