Files
zenml/venv/lib/python3.9/site-packages/databricks/sdk/service/dashboards.py
Christian Mantha 2ca0b9ef7c star
2026-03-02 19:10:52 -05:00

3190 lines
121 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT.
from __future__ import annotations
import logging
import random
import time
from dataclasses import dataclass
from datetime import timedelta
from enum import Enum
from typing import Any, Callable, Dict, Iterator, List, Optional
from databricks.sdk.client_types import HostType
from databricks.sdk.service import sql
from databricks.sdk.service._internal import (Wait, _enum, _from_dict,
_repeated_dict)
from ..errors import OperationFailed
_LOG = logging.getLogger("databricks.sdk")
# all definitions in this file are in alphabetical order
@dataclass
class AuthorizationDetails:
grant_rules: Optional[List[AuthorizationDetailsGrantRule]] = None
"""Represents downscoped permission rules with specific access rights. This field is specific to
`workspace_rule_set` constraint."""
resource_legacy_acl_path: Optional[str] = None
"""The acl path of the tree store resource resource."""
resource_name: Optional[str] = None
"""The resource name to which the authorization rule applies. This field is specific to
`workspace_rule_set` constraint. Format: `workspaces/{workspace_id}/dashboards/{dashboard_id}`"""
type: Optional[str] = None
"""The type of authorization downscoping policy. Ex: `workspace_rule_set` defines access rules for
a specific workspace resource"""
def as_dict(self) -> dict:
"""Serializes the AuthorizationDetails into a dictionary suitable for use as a JSON request body."""
body = {}
if self.grant_rules:
body["grant_rules"] = [v.as_dict() for v in self.grant_rules]
if self.resource_legacy_acl_path is not None:
body["resource_legacy_acl_path"] = self.resource_legacy_acl_path
if self.resource_name is not None:
body["resource_name"] = self.resource_name
if self.type is not None:
body["type"] = self.type
return body
def as_shallow_dict(self) -> dict:
"""Serializes the AuthorizationDetails into a shallow dictionary of its immediate attributes."""
body = {}
if self.grant_rules:
body["grant_rules"] = self.grant_rules
if self.resource_legacy_acl_path is not None:
body["resource_legacy_acl_path"] = self.resource_legacy_acl_path
if self.resource_name is not None:
body["resource_name"] = self.resource_name
if self.type is not None:
body["type"] = self.type
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> AuthorizationDetails:
"""Deserializes the AuthorizationDetails from a dictionary."""
return cls(
grant_rules=_repeated_dict(d, "grant_rules", AuthorizationDetailsGrantRule),
resource_legacy_acl_path=d.get("resource_legacy_acl_path", None),
resource_name=d.get("resource_name", None),
type=d.get("type", None),
)
@dataclass
class AuthorizationDetailsGrantRule:
permission_set: Optional[str] = None
"""Permission sets for dashboard are defined in
iam-common/rbac-common/permission-sets/definitions/TreeStoreBasePermissionSets Ex:
`permissionSets/dashboard.runner`"""
def as_dict(self) -> dict:
"""Serializes the AuthorizationDetailsGrantRule into a dictionary suitable for use as a JSON request body."""
body = {}
if self.permission_set is not None:
body["permission_set"] = self.permission_set
return body
def as_shallow_dict(self) -> dict:
"""Serializes the AuthorizationDetailsGrantRule into a shallow dictionary of its immediate attributes."""
body = {}
if self.permission_set is not None:
body["permission_set"] = self.permission_set
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> AuthorizationDetailsGrantRule:
"""Deserializes the AuthorizationDetailsGrantRule from a dictionary."""
return cls(permission_set=d.get("permission_set", None))
@dataclass
class CronSchedule:
quartz_cron_expression: str
"""A cron expression using quartz syntax. EX: `0 0 8 * * ?` represents everyday at 8am. See [Cron
Trigger] for details.
[Cron Trigger]: http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html"""
timezone_id: str
"""A Java timezone id. The schedule will be resolved with respect to this timezone. See [Java
TimeZone] for details.
[Java TimeZone]: https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html"""
def as_dict(self) -> dict:
"""Serializes the CronSchedule into a dictionary suitable for use as a JSON request body."""
body = {}
if self.quartz_cron_expression is not None:
body["quartz_cron_expression"] = self.quartz_cron_expression
if self.timezone_id is not None:
body["timezone_id"] = self.timezone_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the CronSchedule into a shallow dictionary of its immediate attributes."""
body = {}
if self.quartz_cron_expression is not None:
body["quartz_cron_expression"] = self.quartz_cron_expression
if self.timezone_id is not None:
body["timezone_id"] = self.timezone_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> CronSchedule:
"""Deserializes the CronSchedule from a dictionary."""
return cls(quartz_cron_expression=d.get("quartz_cron_expression", None), timezone_id=d.get("timezone_id", None))
@dataclass
class Dashboard:
create_time: Optional[str] = None
"""The timestamp of when the dashboard was created."""
dashboard_id: Optional[str] = None
"""UUID identifying the dashboard."""
display_name: Optional[str] = None
"""The display name of the dashboard."""
etag: Optional[str] = None
"""The etag for the dashboard. Can be optionally provided on updates to ensure that the dashboard
has not been modified since the last read. This field is excluded in List Dashboards responses."""
lifecycle_state: Optional[LifecycleState] = None
"""The state of the dashboard resource. Used for tracking trashed status."""
parent_path: Optional[str] = None
"""The workspace path of the folder containing the dashboard. Includes leading slash and no
trailing slash. This field is excluded in List Dashboards responses."""
path: Optional[str] = None
"""The workspace path of the dashboard asset, including the file name. Exported dashboards always
have the file extension `.lvdash.json`. This field is excluded in List Dashboards responses."""
serialized_dashboard: Optional[str] = None
"""The contents of the dashboard in serialized string form. This field is excluded in List
Dashboards responses. Use the [get dashboard API] to retrieve an example response, which
includes the `serialized_dashboard` field. This field provides the structure of the JSON string
that represents the dashboard's layout and components.
[get dashboard API]: https://docs.databricks.com/api/workspace/lakeview/get"""
update_time: Optional[str] = None
"""The timestamp of when the dashboard was last updated by the user. This field is excluded in List
Dashboards responses."""
warehouse_id: Optional[str] = None
"""The warehouse ID used to run the dashboard."""
def as_dict(self) -> dict:
"""Serializes the Dashboard into a dictionary suitable for use as a JSON request body."""
body = {}
if self.create_time is not None:
body["create_time"] = self.create_time
if self.dashboard_id is not None:
body["dashboard_id"] = self.dashboard_id
if self.display_name is not None:
body["display_name"] = self.display_name
if self.etag is not None:
body["etag"] = self.etag
if self.lifecycle_state is not None:
body["lifecycle_state"] = self.lifecycle_state.value
if self.parent_path is not None:
body["parent_path"] = self.parent_path
if self.path is not None:
body["path"] = self.path
if self.serialized_dashboard is not None:
body["serialized_dashboard"] = self.serialized_dashboard
if self.update_time is not None:
body["update_time"] = self.update_time
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the Dashboard into a shallow dictionary of its immediate attributes."""
body = {}
if self.create_time is not None:
body["create_time"] = self.create_time
if self.dashboard_id is not None:
body["dashboard_id"] = self.dashboard_id
if self.display_name is not None:
body["display_name"] = self.display_name
if self.etag is not None:
body["etag"] = self.etag
if self.lifecycle_state is not None:
body["lifecycle_state"] = self.lifecycle_state
if self.parent_path is not None:
body["parent_path"] = self.parent_path
if self.path is not None:
body["path"] = self.path
if self.serialized_dashboard is not None:
body["serialized_dashboard"] = self.serialized_dashboard
if self.update_time is not None:
body["update_time"] = self.update_time
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> Dashboard:
"""Deserializes the Dashboard from a dictionary."""
return cls(
create_time=d.get("create_time", None),
dashboard_id=d.get("dashboard_id", None),
display_name=d.get("display_name", None),
etag=d.get("etag", None),
lifecycle_state=_enum(d, "lifecycle_state", LifecycleState),
parent_path=d.get("parent_path", None),
path=d.get("path", None),
serialized_dashboard=d.get("serialized_dashboard", None),
update_time=d.get("update_time", None),
warehouse_id=d.get("warehouse_id", None),
)
class DashboardView(Enum):
DASHBOARD_VIEW_BASIC = "DASHBOARD_VIEW_BASIC"
@dataclass
class GenieAttachment:
"""Genie AI Response"""
attachment_id: Optional[str] = None
"""Attachment ID"""
query: Optional[GenieQueryAttachment] = None
"""Query Attachment if Genie responds with a SQL query"""
suggested_questions: Optional[GenieSuggestedQuestionsAttachment] = None
"""Follow-up questions suggested by Genie"""
text: Optional[TextAttachment] = None
"""Text Attachment if Genie responds with text This also contains the final summary when available."""
def as_dict(self) -> dict:
"""Serializes the GenieAttachment into a dictionary suitable for use as a JSON request body."""
body = {}
if self.attachment_id is not None:
body["attachment_id"] = self.attachment_id
if self.query:
body["query"] = self.query.as_dict()
if self.suggested_questions:
body["suggested_questions"] = self.suggested_questions.as_dict()
if self.text:
body["text"] = self.text.as_dict()
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieAttachment into a shallow dictionary of its immediate attributes."""
body = {}
if self.attachment_id is not None:
body["attachment_id"] = self.attachment_id
if self.query:
body["query"] = self.query
if self.suggested_questions:
body["suggested_questions"] = self.suggested_questions
if self.text:
body["text"] = self.text
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieAttachment:
"""Deserializes the GenieAttachment from a dictionary."""
return cls(
attachment_id=d.get("attachment_id", None),
query=_from_dict(d, "query", GenieQueryAttachment),
suggested_questions=_from_dict(d, "suggested_questions", GenieSuggestedQuestionsAttachment),
text=_from_dict(d, "text", TextAttachment),
)
@dataclass
class GenieConversation:
space_id: str
"""Genie space ID"""
title: str
"""Conversation title"""
conversation_id: str
"""Conversation ID"""
created_timestamp: Optional[int] = None
"""Timestamp when the message was created"""
id: Optional[str] = None
"""Conversation ID. Legacy identifier, use conversation_id instead"""
last_updated_timestamp: Optional[int] = None
"""Timestamp when the message was last updated"""
user_id: Optional[int] = None
"""ID of the user who created the conversation"""
def as_dict(self) -> dict:
"""Serializes the GenieConversation into a dictionary suitable for use as a JSON request body."""
body = {}
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.created_timestamp is not None:
body["created_timestamp"] = self.created_timestamp
if self.id is not None:
body["id"] = self.id
if self.last_updated_timestamp is not None:
body["last_updated_timestamp"] = self.last_updated_timestamp
if self.space_id is not None:
body["space_id"] = self.space_id
if self.title is not None:
body["title"] = self.title
if self.user_id is not None:
body["user_id"] = self.user_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieConversation into a shallow dictionary of its immediate attributes."""
body = {}
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.created_timestamp is not None:
body["created_timestamp"] = self.created_timestamp
if self.id is not None:
body["id"] = self.id
if self.last_updated_timestamp is not None:
body["last_updated_timestamp"] = self.last_updated_timestamp
if self.space_id is not None:
body["space_id"] = self.space_id
if self.title is not None:
body["title"] = self.title
if self.user_id is not None:
body["user_id"] = self.user_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieConversation:
"""Deserializes the GenieConversation from a dictionary."""
return cls(
conversation_id=d.get("conversation_id", None),
created_timestamp=d.get("created_timestamp", None),
id=d.get("id", None),
last_updated_timestamp=d.get("last_updated_timestamp", None),
space_id=d.get("space_id", None),
title=d.get("title", None),
user_id=d.get("user_id", None),
)
@dataclass
class GenieConversationSummary:
conversation_id: str
created_timestamp: Optional[int] = None
title: Optional[str] = None
def as_dict(self) -> dict:
"""Serializes the GenieConversationSummary into a dictionary suitable for use as a JSON request body."""
body = {}
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.created_timestamp is not None:
body["created_timestamp"] = self.created_timestamp
if self.title is not None:
body["title"] = self.title
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieConversationSummary into a shallow dictionary of its immediate attributes."""
body = {}
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.created_timestamp is not None:
body["created_timestamp"] = self.created_timestamp
if self.title is not None:
body["title"] = self.title
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieConversationSummary:
"""Deserializes the GenieConversationSummary from a dictionary."""
return cls(
conversation_id=d.get("conversation_id", None),
created_timestamp=d.get("created_timestamp", None),
title=d.get("title", None),
)
@dataclass
class GenieFeedback:
"""Feedback containing rating and optional comment"""
rating: Optional[GenieFeedbackRating] = None
"""The feedback rating"""
def as_dict(self) -> dict:
"""Serializes the GenieFeedback into a dictionary suitable for use as a JSON request body."""
body = {}
if self.rating is not None:
body["rating"] = self.rating.value
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieFeedback into a shallow dictionary of its immediate attributes."""
body = {}
if self.rating is not None:
body["rating"] = self.rating
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieFeedback:
"""Deserializes the GenieFeedback from a dictionary."""
return cls(rating=_enum(d, "rating", GenieFeedbackRating))
class GenieFeedbackRating(Enum):
"""Feedback rating for Genie messages"""
NEGATIVE = "NEGATIVE"
NONE = "NONE"
POSITIVE = "POSITIVE"
@dataclass
class GenieGenerateDownloadFullQueryResultResponse:
download_id: Optional[str] = None
"""Download ID. Use this ID to track the download request in subsequent polling calls"""
download_id_signature: Optional[str] = None
"""JWT signature for the download_id to ensure secure access to query results"""
def as_dict(self) -> dict:
"""Serializes the GenieGenerateDownloadFullQueryResultResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.download_id is not None:
body["download_id"] = self.download_id
if self.download_id_signature is not None:
body["download_id_signature"] = self.download_id_signature
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieGenerateDownloadFullQueryResultResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.download_id is not None:
body["download_id"] = self.download_id
if self.download_id_signature is not None:
body["download_id_signature"] = self.download_id_signature
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieGenerateDownloadFullQueryResultResponse:
"""Deserializes the GenieGenerateDownloadFullQueryResultResponse from a dictionary."""
return cls(download_id=d.get("download_id", None), download_id_signature=d.get("download_id_signature", None))
@dataclass
class GenieGetDownloadFullQueryResultResponse:
statement_response: Optional[sql.StatementResponse] = None
"""SQL Statement Execution response. See [Get status, manifest, and result first
chunk](:method:statementexecution/getstatement) for more details."""
def as_dict(self) -> dict:
"""Serializes the GenieGetDownloadFullQueryResultResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.statement_response:
body["statement_response"] = self.statement_response.as_dict()
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieGetDownloadFullQueryResultResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.statement_response:
body["statement_response"] = self.statement_response
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieGetDownloadFullQueryResultResponse:
"""Deserializes the GenieGetDownloadFullQueryResultResponse from a dictionary."""
return cls(statement_response=_from_dict(d, "statement_response", sql.StatementResponse))
@dataclass
class GenieGetMessageQueryResultResponse:
statement_response: Optional[sql.StatementResponse] = None
"""SQL Statement Execution response. See [Get status, manifest, and result first
chunk](:method:statementexecution/getstatement) for more details."""
def as_dict(self) -> dict:
"""Serializes the GenieGetMessageQueryResultResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.statement_response:
body["statement_response"] = self.statement_response.as_dict()
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieGetMessageQueryResultResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.statement_response:
body["statement_response"] = self.statement_response
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieGetMessageQueryResultResponse:
"""Deserializes the GenieGetMessageQueryResultResponse from a dictionary."""
return cls(statement_response=_from_dict(d, "statement_response", sql.StatementResponse))
@dataclass
class GenieListConversationMessagesResponse:
messages: Optional[List[GenieMessage]] = None
"""List of messages in the conversation."""
next_page_token: Optional[str] = None
"""The token to use for retrieving the next page of results."""
def as_dict(self) -> dict:
"""Serializes the GenieListConversationMessagesResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.messages:
body["messages"] = [v.as_dict() for v in self.messages]
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieListConversationMessagesResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.messages:
body["messages"] = self.messages
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieListConversationMessagesResponse:
"""Deserializes the GenieListConversationMessagesResponse from a dictionary."""
return cls(messages=_repeated_dict(d, "messages", GenieMessage), next_page_token=d.get("next_page_token", None))
@dataclass
class GenieListConversationsResponse:
conversations: Optional[List[GenieConversationSummary]] = None
"""List of conversations in the Genie space"""
next_page_token: Optional[str] = None
"""Token to get the next page of results"""
def as_dict(self) -> dict:
"""Serializes the GenieListConversationsResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.conversations:
body["conversations"] = [v.as_dict() for v in self.conversations]
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieListConversationsResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.conversations:
body["conversations"] = self.conversations
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieListConversationsResponse:
"""Deserializes the GenieListConversationsResponse from a dictionary."""
return cls(
conversations=_repeated_dict(d, "conversations", GenieConversationSummary),
next_page_token=d.get("next_page_token", None),
)
@dataclass
class GenieListSpacesResponse:
next_page_token: Optional[str] = None
"""Token to get the next page of results"""
spaces: Optional[List[GenieSpace]] = None
"""List of Genie spaces"""
def as_dict(self) -> dict:
"""Serializes the GenieListSpacesResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
if self.spaces:
body["spaces"] = [v.as_dict() for v in self.spaces]
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieListSpacesResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
if self.spaces:
body["spaces"] = self.spaces
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieListSpacesResponse:
"""Deserializes the GenieListSpacesResponse from a dictionary."""
return cls(next_page_token=d.get("next_page_token", None), spaces=_repeated_dict(d, "spaces", GenieSpace))
@dataclass
class GenieMessage:
space_id: str
"""Genie space ID"""
conversation_id: str
"""Conversation ID"""
content: str
"""User message content"""
message_id: str
"""Message ID"""
attachments: Optional[List[GenieAttachment]] = None
"""AI-generated response to the message"""
created_timestamp: Optional[int] = None
"""Timestamp when the message was created"""
error: Optional[MessageError] = None
"""Error message if Genie failed to respond to the message"""
feedback: Optional[GenieFeedback] = None
"""User feedback for the message if provided"""
id: Optional[str] = None
"""Message ID. Legacy identifier, use message_id instead"""
last_updated_timestamp: Optional[int] = None
"""Timestamp when the message was last updated"""
query_result: Optional[Result] = None
"""The result of SQL query if the message includes a query attachment. Deprecated. Use
`query_result_metadata` in `GenieQueryAttachment` instead."""
status: Optional[MessageStatus] = None
user_id: Optional[int] = None
"""ID of the user who created the message"""
def as_dict(self) -> dict:
"""Serializes the GenieMessage into a dictionary suitable for use as a JSON request body."""
body = {}
if self.attachments:
body["attachments"] = [v.as_dict() for v in self.attachments]
if self.content is not None:
body["content"] = self.content
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.created_timestamp is not None:
body["created_timestamp"] = self.created_timestamp
if self.error:
body["error"] = self.error.as_dict()
if self.feedback:
body["feedback"] = self.feedback.as_dict()
if self.id is not None:
body["id"] = self.id
if self.last_updated_timestamp is not None:
body["last_updated_timestamp"] = self.last_updated_timestamp
if self.message_id is not None:
body["message_id"] = self.message_id
if self.query_result:
body["query_result"] = self.query_result.as_dict()
if self.space_id is not None:
body["space_id"] = self.space_id
if self.status is not None:
body["status"] = self.status.value
if self.user_id is not None:
body["user_id"] = self.user_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieMessage into a shallow dictionary of its immediate attributes."""
body = {}
if self.attachments:
body["attachments"] = self.attachments
if self.content is not None:
body["content"] = self.content
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.created_timestamp is not None:
body["created_timestamp"] = self.created_timestamp
if self.error:
body["error"] = self.error
if self.feedback:
body["feedback"] = self.feedback
if self.id is not None:
body["id"] = self.id
if self.last_updated_timestamp is not None:
body["last_updated_timestamp"] = self.last_updated_timestamp
if self.message_id is not None:
body["message_id"] = self.message_id
if self.query_result:
body["query_result"] = self.query_result
if self.space_id is not None:
body["space_id"] = self.space_id
if self.status is not None:
body["status"] = self.status
if self.user_id is not None:
body["user_id"] = self.user_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieMessage:
"""Deserializes the GenieMessage from a dictionary."""
return cls(
attachments=_repeated_dict(d, "attachments", GenieAttachment),
content=d.get("content", None),
conversation_id=d.get("conversation_id", None),
created_timestamp=d.get("created_timestamp", None),
error=_from_dict(d, "error", MessageError),
feedback=_from_dict(d, "feedback", GenieFeedback),
id=d.get("id", None),
last_updated_timestamp=d.get("last_updated_timestamp", None),
message_id=d.get("message_id", None),
query_result=_from_dict(d, "query_result", Result),
space_id=d.get("space_id", None),
status=_enum(d, "status", MessageStatus),
user_id=d.get("user_id", None),
)
@dataclass
class GenieQueryAttachment:
description: Optional[str] = None
"""Description of the query"""
id: Optional[str] = None
last_updated_timestamp: Optional[int] = None
"""Time when the user updated the query last"""
parameters: Optional[List[QueryAttachmentParameter]] = None
query: Optional[str] = None
"""AI generated SQL query"""
query_result_metadata: Optional[GenieResultMetadata] = None
"""Metadata associated with the query result."""
statement_id: Optional[str] = None
"""Statement Execution API statement id. Use [Get status, manifest, and result first
chunk](:method:statementexecution/getstatement) to get the full result data."""
title: Optional[str] = None
"""Name of the query"""
def as_dict(self) -> dict:
"""Serializes the GenieQueryAttachment into a dictionary suitable for use as a JSON request body."""
body = {}
if self.description is not None:
body["description"] = self.description
if self.id is not None:
body["id"] = self.id
if self.last_updated_timestamp is not None:
body["last_updated_timestamp"] = self.last_updated_timestamp
if self.parameters:
body["parameters"] = [v.as_dict() for v in self.parameters]
if self.query is not None:
body["query"] = self.query
if self.query_result_metadata:
body["query_result_metadata"] = self.query_result_metadata.as_dict()
if self.statement_id is not None:
body["statement_id"] = self.statement_id
if self.title is not None:
body["title"] = self.title
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieQueryAttachment into a shallow dictionary of its immediate attributes."""
body = {}
if self.description is not None:
body["description"] = self.description
if self.id is not None:
body["id"] = self.id
if self.last_updated_timestamp is not None:
body["last_updated_timestamp"] = self.last_updated_timestamp
if self.parameters:
body["parameters"] = self.parameters
if self.query is not None:
body["query"] = self.query
if self.query_result_metadata:
body["query_result_metadata"] = self.query_result_metadata
if self.statement_id is not None:
body["statement_id"] = self.statement_id
if self.title is not None:
body["title"] = self.title
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieQueryAttachment:
"""Deserializes the GenieQueryAttachment from a dictionary."""
return cls(
description=d.get("description", None),
id=d.get("id", None),
last_updated_timestamp=d.get("last_updated_timestamp", None),
parameters=_repeated_dict(d, "parameters", QueryAttachmentParameter),
query=d.get("query", None),
query_result_metadata=_from_dict(d, "query_result_metadata", GenieResultMetadata),
statement_id=d.get("statement_id", None),
title=d.get("title", None),
)
@dataclass
class GenieResultMetadata:
is_truncated: Optional[bool] = None
"""Indicates whether the result set is truncated."""
row_count: Optional[int] = None
"""The number of rows in the result set."""
def as_dict(self) -> dict:
"""Serializes the GenieResultMetadata into a dictionary suitable for use as a JSON request body."""
body = {}
if self.is_truncated is not None:
body["is_truncated"] = self.is_truncated
if self.row_count is not None:
body["row_count"] = self.row_count
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieResultMetadata into a shallow dictionary of its immediate attributes."""
body = {}
if self.is_truncated is not None:
body["is_truncated"] = self.is_truncated
if self.row_count is not None:
body["row_count"] = self.row_count
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieResultMetadata:
"""Deserializes the GenieResultMetadata from a dictionary."""
return cls(is_truncated=d.get("is_truncated", None), row_count=d.get("row_count", None))
@dataclass
class GenieSpace:
space_id: str
"""Genie space ID"""
title: str
"""Title of the Genie Space"""
description: Optional[str] = None
"""Description of the Genie Space"""
serialized_space: Optional[str] = None
"""The contents of the Genie Space in serialized string form. This field is excluded in List Genie
spaces responses. Use the [Get Genie Space](:method:genie/getspace) API to retrieve an example
response, which includes the `serialized_space` field. This field provides the structure of the
JSON string that represents the space's layout and components."""
warehouse_id: Optional[str] = None
"""Warehouse associated with the Genie Space"""
def as_dict(self) -> dict:
"""Serializes the GenieSpace into a dictionary suitable for use as a JSON request body."""
body = {}
if self.description is not None:
body["description"] = self.description
if self.serialized_space is not None:
body["serialized_space"] = self.serialized_space
if self.space_id is not None:
body["space_id"] = self.space_id
if self.title is not None:
body["title"] = self.title
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieSpace into a shallow dictionary of its immediate attributes."""
body = {}
if self.description is not None:
body["description"] = self.description
if self.serialized_space is not None:
body["serialized_space"] = self.serialized_space
if self.space_id is not None:
body["space_id"] = self.space_id
if self.title is not None:
body["title"] = self.title
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieSpace:
"""Deserializes the GenieSpace from a dictionary."""
return cls(
description=d.get("description", None),
serialized_space=d.get("serialized_space", None),
space_id=d.get("space_id", None),
title=d.get("title", None),
warehouse_id=d.get("warehouse_id", None),
)
@dataclass
class GenieStartConversationResponse:
message_id: str
"""Message ID"""
conversation_id: str
"""Conversation ID"""
conversation: Optional[GenieConversation] = None
message: Optional[GenieMessage] = None
def as_dict(self) -> dict:
"""Serializes the GenieStartConversationResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.conversation:
body["conversation"] = self.conversation.as_dict()
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.message:
body["message"] = self.message.as_dict()
if self.message_id is not None:
body["message_id"] = self.message_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieStartConversationResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.conversation:
body["conversation"] = self.conversation
if self.conversation_id is not None:
body["conversation_id"] = self.conversation_id
if self.message:
body["message"] = self.message
if self.message_id is not None:
body["message_id"] = self.message_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieStartConversationResponse:
"""Deserializes the GenieStartConversationResponse from a dictionary."""
return cls(
conversation=_from_dict(d, "conversation", GenieConversation),
conversation_id=d.get("conversation_id", None),
message=_from_dict(d, "message", GenieMessage),
message_id=d.get("message_id", None),
)
@dataclass
class GenieSuggestedQuestionsAttachment:
"""Follow-up questions suggested by Genie"""
questions: Optional[List[str]] = None
"""The suggested follow-up questions"""
def as_dict(self) -> dict:
"""Serializes the GenieSuggestedQuestionsAttachment into a dictionary suitable for use as a JSON request body."""
body = {}
if self.questions:
body["questions"] = [v for v in self.questions]
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GenieSuggestedQuestionsAttachment into a shallow dictionary of its immediate attributes."""
body = {}
if self.questions:
body["questions"] = self.questions
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GenieSuggestedQuestionsAttachment:
"""Deserializes the GenieSuggestedQuestionsAttachment from a dictionary."""
return cls(questions=d.get("questions", None))
@dataclass
class GetPublishedDashboardTokenInfoResponse:
authorization_details: Optional[List[AuthorizationDetails]] = None
"""Authorization constraints for accessing the published dashboard. Currently includes
`workspace_rule_set` and could be enriched with `unity_catalog_privileges` before oAuth token
generation."""
custom_claim: Optional[str] = None
"""Custom claim generated from external_value and external_viewer_id. Format:
`urn:aibi:external_data:<external_value>:<external_viewer_id>:<dashboard_id>`"""
scope: Optional[str] = None
"""Scope defining access permissions."""
def as_dict(self) -> dict:
"""Serializes the GetPublishedDashboardTokenInfoResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.authorization_details:
body["authorization_details"] = [v.as_dict() for v in self.authorization_details]
if self.custom_claim is not None:
body["custom_claim"] = self.custom_claim
if self.scope is not None:
body["scope"] = self.scope
return body
def as_shallow_dict(self) -> dict:
"""Serializes the GetPublishedDashboardTokenInfoResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.authorization_details:
body["authorization_details"] = self.authorization_details
if self.custom_claim is not None:
body["custom_claim"] = self.custom_claim
if self.scope is not None:
body["scope"] = self.scope
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> GetPublishedDashboardTokenInfoResponse:
"""Deserializes the GetPublishedDashboardTokenInfoResponse from a dictionary."""
return cls(
authorization_details=_repeated_dict(d, "authorization_details", AuthorizationDetails),
custom_claim=d.get("custom_claim", None),
scope=d.get("scope", None),
)
class LifecycleState(Enum):
ACTIVE = "ACTIVE"
TRASHED = "TRASHED"
@dataclass
class ListDashboardsResponse:
dashboards: Optional[List[Dashboard]] = None
next_page_token: Optional[str] = None
"""A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted,
there are no subsequent dashboards."""
def as_dict(self) -> dict:
"""Serializes the ListDashboardsResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.dashboards:
body["dashboards"] = [v.as_dict() for v in self.dashboards]
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
return body
def as_shallow_dict(self) -> dict:
"""Serializes the ListDashboardsResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.dashboards:
body["dashboards"] = self.dashboards
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> ListDashboardsResponse:
"""Deserializes the ListDashboardsResponse from a dictionary."""
return cls(
dashboards=_repeated_dict(d, "dashboards", Dashboard), next_page_token=d.get("next_page_token", None)
)
@dataclass
class ListSchedulesResponse:
next_page_token: Optional[str] = None
"""A token that can be used as a `page_token` in subsequent requests to retrieve the next page of
results. If this field is omitted, there are no subsequent schedules."""
schedules: Optional[List[Schedule]] = None
def as_dict(self) -> dict:
"""Serializes the ListSchedulesResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
if self.schedules:
body["schedules"] = [v.as_dict() for v in self.schedules]
return body
def as_shallow_dict(self) -> dict:
"""Serializes the ListSchedulesResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
if self.schedules:
body["schedules"] = self.schedules
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> ListSchedulesResponse:
"""Deserializes the ListSchedulesResponse from a dictionary."""
return cls(next_page_token=d.get("next_page_token", None), schedules=_repeated_dict(d, "schedules", Schedule))
@dataclass
class ListSubscriptionsResponse:
next_page_token: Optional[str] = None
"""A token that can be used as a `page_token` in subsequent requests to retrieve the next page of
results. If this field is omitted, there are no subsequent subscriptions."""
subscriptions: Optional[List[Subscription]] = None
def as_dict(self) -> dict:
"""Serializes the ListSubscriptionsResponse into a dictionary suitable for use as a JSON request body."""
body = {}
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
if self.subscriptions:
body["subscriptions"] = [v.as_dict() for v in self.subscriptions]
return body
def as_shallow_dict(self) -> dict:
"""Serializes the ListSubscriptionsResponse into a shallow dictionary of its immediate attributes."""
body = {}
if self.next_page_token is not None:
body["next_page_token"] = self.next_page_token
if self.subscriptions:
body["subscriptions"] = self.subscriptions
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> ListSubscriptionsResponse:
"""Deserializes the ListSubscriptionsResponse from a dictionary."""
return cls(
next_page_token=d.get("next_page_token", None),
subscriptions=_repeated_dict(d, "subscriptions", Subscription),
)
@dataclass
class MessageError:
error: Optional[str] = None
type: Optional[MessageErrorType] = None
def as_dict(self) -> dict:
"""Serializes the MessageError into a dictionary suitable for use as a JSON request body."""
body = {}
if self.error is not None:
body["error"] = self.error
if self.type is not None:
body["type"] = self.type.value
return body
def as_shallow_dict(self) -> dict:
"""Serializes the MessageError into a shallow dictionary of its immediate attributes."""
body = {}
if self.error is not None:
body["error"] = self.error
if self.type is not None:
body["type"] = self.type
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> MessageError:
"""Deserializes the MessageError from a dictionary."""
return cls(error=d.get("error", None), type=_enum(d, "type", MessageErrorType))
class MessageErrorType(Enum):
BLOCK_MULTIPLE_EXECUTIONS_EXCEPTION = "BLOCK_MULTIPLE_EXECUTIONS_EXCEPTION"
CHAT_COMPLETION_CLIENT_EXCEPTION = "CHAT_COMPLETION_CLIENT_EXCEPTION"
CHAT_COMPLETION_CLIENT_TIMEOUT_EXCEPTION = "CHAT_COMPLETION_CLIENT_TIMEOUT_EXCEPTION"
CHAT_COMPLETION_NETWORK_EXCEPTION = "CHAT_COMPLETION_NETWORK_EXCEPTION"
CONTENT_FILTER_EXCEPTION = "CONTENT_FILTER_EXCEPTION"
CONTEXT_EXCEEDED_EXCEPTION = "CONTEXT_EXCEEDED_EXCEPTION"
COULD_NOT_GET_DASHBOARD_SCHEMA_EXCEPTION = "COULD_NOT_GET_DASHBOARD_SCHEMA_EXCEPTION"
COULD_NOT_GET_MODEL_DEPLOYMENTS_EXCEPTION = "COULD_NOT_GET_MODEL_DEPLOYMENTS_EXCEPTION"
COULD_NOT_GET_UC_SCHEMA_EXCEPTION = "COULD_NOT_GET_UC_SCHEMA_EXCEPTION"
DEPLOYMENT_NOT_FOUND_EXCEPTION = "DEPLOYMENT_NOT_FOUND_EXCEPTION"
DESCRIBE_QUERY_INVALID_SQL_ERROR = "DESCRIBE_QUERY_INVALID_SQL_ERROR"
DESCRIBE_QUERY_TIMEOUT = "DESCRIBE_QUERY_TIMEOUT"
DESCRIBE_QUERY_UNEXPECTED_FAILURE = "DESCRIBE_QUERY_UNEXPECTED_FAILURE"
EXCEEDED_MAX_TOKEN_LENGTH_EXCEPTION = "EXCEEDED_MAX_TOKEN_LENGTH_EXCEPTION"
FUNCTIONS_NOT_AVAILABLE_EXCEPTION = "FUNCTIONS_NOT_AVAILABLE_EXCEPTION"
FUNCTION_ARGUMENTS_INVALID_EXCEPTION = "FUNCTION_ARGUMENTS_INVALID_EXCEPTION"
FUNCTION_ARGUMENTS_INVALID_JSON_EXCEPTION = "FUNCTION_ARGUMENTS_INVALID_JSON_EXCEPTION"
FUNCTION_ARGUMENTS_INVALID_TYPE_EXCEPTION = "FUNCTION_ARGUMENTS_INVALID_TYPE_EXCEPTION"
FUNCTION_CALL_MISSING_PARAMETER_EXCEPTION = "FUNCTION_CALL_MISSING_PARAMETER_EXCEPTION"
GENERATED_SQL_QUERY_TOO_LONG_EXCEPTION = "GENERATED_SQL_QUERY_TOO_LONG_EXCEPTION"
GENERIC_CHAT_COMPLETION_EXCEPTION = "GENERIC_CHAT_COMPLETION_EXCEPTION"
GENERIC_CHAT_COMPLETION_SERVICE_EXCEPTION = "GENERIC_CHAT_COMPLETION_SERVICE_EXCEPTION"
GENERIC_SQL_EXEC_API_CALL_EXCEPTION = "GENERIC_SQL_EXEC_API_CALL_EXCEPTION"
ILLEGAL_PARAMETER_DEFINITION_EXCEPTION = "ILLEGAL_PARAMETER_DEFINITION_EXCEPTION"
INTERNAL_CATALOG_ASSET_CREATION_FAILED_EXCEPTION = "INTERNAL_CATALOG_ASSET_CREATION_FAILED_EXCEPTION"
INTERNAL_CATALOG_ASSET_CREATION_ONGOING_EXCEPTION = "INTERNAL_CATALOG_ASSET_CREATION_ONGOING_EXCEPTION"
INTERNAL_CATALOG_ASSET_CREATION_UNSUPPORTED_EXCEPTION = "INTERNAL_CATALOG_ASSET_CREATION_UNSUPPORTED_EXCEPTION"
INTERNAL_CATALOG_MISSING_UC_PATH_EXCEPTION = "INTERNAL_CATALOG_MISSING_UC_PATH_EXCEPTION"
INTERNAL_CATALOG_PATH_OVERLAP_EXCEPTION = "INTERNAL_CATALOG_PATH_OVERLAP_EXCEPTION"
INVALID_CERTIFIED_ANSWER_FUNCTION_EXCEPTION = "INVALID_CERTIFIED_ANSWER_FUNCTION_EXCEPTION"
INVALID_CERTIFIED_ANSWER_IDENTIFIER_EXCEPTION = "INVALID_CERTIFIED_ANSWER_IDENTIFIER_EXCEPTION"
INVALID_CHAT_COMPLETION_JSON_EXCEPTION = "INVALID_CHAT_COMPLETION_JSON_EXCEPTION"
INVALID_COMPLETION_REQUEST_EXCEPTION = "INVALID_COMPLETION_REQUEST_EXCEPTION"
INVALID_FUNCTION_CALL_EXCEPTION = "INVALID_FUNCTION_CALL_EXCEPTION"
INVALID_SQL_MULTIPLE_DATASET_REFERENCES_EXCEPTION = "INVALID_SQL_MULTIPLE_DATASET_REFERENCES_EXCEPTION"
INVALID_SQL_MULTIPLE_STATEMENTS_EXCEPTION = "INVALID_SQL_MULTIPLE_STATEMENTS_EXCEPTION"
INVALID_SQL_UNKNOWN_TABLE_EXCEPTION = "INVALID_SQL_UNKNOWN_TABLE_EXCEPTION"
INVALID_TABLE_IDENTIFIER_EXCEPTION = "INVALID_TABLE_IDENTIFIER_EXCEPTION"
LOCAL_CONTEXT_EXCEEDED_EXCEPTION = "LOCAL_CONTEXT_EXCEEDED_EXCEPTION"
MESSAGE_ATTACHMENT_TOO_LONG_ERROR = "MESSAGE_ATTACHMENT_TOO_LONG_ERROR"
MESSAGE_CANCELLED_WHILE_EXECUTING_EXCEPTION = "MESSAGE_CANCELLED_WHILE_EXECUTING_EXCEPTION"
MESSAGE_DELETED_WHILE_EXECUTING_EXCEPTION = "MESSAGE_DELETED_WHILE_EXECUTING_EXCEPTION"
MESSAGE_UPDATED_WHILE_EXECUTING_EXCEPTION = "MESSAGE_UPDATED_WHILE_EXECUTING_EXCEPTION"
MISSING_SQL_QUERY_EXCEPTION = "MISSING_SQL_QUERY_EXCEPTION"
NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE = "NO_DEPLOYMENTS_AVAILABLE_TO_WORKSPACE"
NO_QUERY_TO_VISUALIZE_EXCEPTION = "NO_QUERY_TO_VISUALIZE_EXCEPTION"
NO_TABLES_TO_QUERY_EXCEPTION = "NO_TABLES_TO_QUERY_EXCEPTION"
RATE_LIMIT_EXCEEDED_GENERIC_EXCEPTION = "RATE_LIMIT_EXCEEDED_GENERIC_EXCEPTION"
RATE_LIMIT_EXCEEDED_SPECIFIED_WAIT_EXCEPTION = "RATE_LIMIT_EXCEEDED_SPECIFIED_WAIT_EXCEPTION"
REPLY_PROCESS_TIMEOUT_EXCEPTION = "REPLY_PROCESS_TIMEOUT_EXCEPTION"
RETRYABLE_PROCESSING_EXCEPTION = "RETRYABLE_PROCESSING_EXCEPTION"
SQL_EXECUTION_EXCEPTION = "SQL_EXECUTION_EXCEPTION"
STOP_PROCESS_DUE_TO_AUTO_REGENERATE = "STOP_PROCESS_DUE_TO_AUTO_REGENERATE"
TABLES_MISSING_EXCEPTION = "TABLES_MISSING_EXCEPTION"
TOO_MANY_CERTIFIED_ANSWERS_EXCEPTION = "TOO_MANY_CERTIFIED_ANSWERS_EXCEPTION"
TOO_MANY_TABLES_EXCEPTION = "TOO_MANY_TABLES_EXCEPTION"
UNEXPECTED_REPLY_PROCESS_EXCEPTION = "UNEXPECTED_REPLY_PROCESS_EXCEPTION"
UNKNOWN_AI_MODEL = "UNKNOWN_AI_MODEL"
UNSUPPORTED_CONVERSATION_TYPE_EXCEPTION = "UNSUPPORTED_CONVERSATION_TYPE_EXCEPTION"
WAREHOUSE_ACCESS_MISSING_EXCEPTION = "WAREHOUSE_ACCESS_MISSING_EXCEPTION"
WAREHOUSE_NOT_FOUND_EXCEPTION = "WAREHOUSE_NOT_FOUND_EXCEPTION"
class MessageStatus(Enum):
"""MessageStatus. The possible values are: * `FETCHING_METADATA`: Fetching metadata from the data
sources. * `FILTERING_CONTEXT`: Running smart context step to determine relevant context. *
`ASKING_AI`: Waiting for the LLM to respond to the user's question. * `PENDING_WAREHOUSE`:
Waiting for warehouse before the SQL query can start executing. * `EXECUTING_QUERY`: Executing a
generated SQL query. Get the SQL query result by calling
[getMessageAttachmentQueryResult](:method:genie/getMessageAttachmentQueryResult) API. *
`FAILED`: The response generation or query execution failed. See `error` field. * `COMPLETED`:
Message processing is completed. Results are in the `attachments` field. Get the SQL query
result by calling
[getMessageAttachmentQueryResult](:method:genie/getMessageAttachmentQueryResult) API. *
`SUBMITTED`: Message has been submitted. * `QUERY_RESULT_EXPIRED`: SQL result is not available
anymore. The user needs to rerun the query. Rerun the SQL query result by calling
[executeMessageAttachmentQuery](:method:genie/executeMessageAttachmentQuery) API. * `CANCELLED`:
Message has been cancelled."""
ASKING_AI = "ASKING_AI"
CANCELLED = "CANCELLED"
COMPLETED = "COMPLETED"
EXECUTING_QUERY = "EXECUTING_QUERY"
FAILED = "FAILED"
FETCHING_METADATA = "FETCHING_METADATA"
FILTERING_CONTEXT = "FILTERING_CONTEXT"
PENDING_WAREHOUSE = "PENDING_WAREHOUSE"
QUERY_RESULT_EXPIRED = "QUERY_RESULT_EXPIRED"
SUBMITTED = "SUBMITTED"
@dataclass
class PublishedDashboard:
display_name: Optional[str] = None
"""The display name of the published dashboard."""
embed_credentials: Optional[bool] = None
"""Indicates whether credentials are embedded in the published dashboard."""
revision_create_time: Optional[str] = None
"""The timestamp of when the published dashboard was last revised."""
warehouse_id: Optional[str] = None
"""The warehouse ID used to run the published dashboard."""
def as_dict(self) -> dict:
"""Serializes the PublishedDashboard into a dictionary suitable for use as a JSON request body."""
body = {}
if self.display_name is not None:
body["display_name"] = self.display_name
if self.embed_credentials is not None:
body["embed_credentials"] = self.embed_credentials
if self.revision_create_time is not None:
body["revision_create_time"] = self.revision_create_time
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the PublishedDashboard into a shallow dictionary of its immediate attributes."""
body = {}
if self.display_name is not None:
body["display_name"] = self.display_name
if self.embed_credentials is not None:
body["embed_credentials"] = self.embed_credentials
if self.revision_create_time is not None:
body["revision_create_time"] = self.revision_create_time
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> PublishedDashboard:
"""Deserializes the PublishedDashboard from a dictionary."""
return cls(
display_name=d.get("display_name", None),
embed_credentials=d.get("embed_credentials", None),
revision_create_time=d.get("revision_create_time", None),
warehouse_id=d.get("warehouse_id", None),
)
@dataclass
class QueryAttachmentParameter:
keyword: Optional[str] = None
sql_type: Optional[str] = None
value: Optional[str] = None
def as_dict(self) -> dict:
"""Serializes the QueryAttachmentParameter into a dictionary suitable for use as a JSON request body."""
body = {}
if self.keyword is not None:
body["keyword"] = self.keyword
if self.sql_type is not None:
body["sql_type"] = self.sql_type
if self.value is not None:
body["value"] = self.value
return body
def as_shallow_dict(self) -> dict:
"""Serializes the QueryAttachmentParameter into a shallow dictionary of its immediate attributes."""
body = {}
if self.keyword is not None:
body["keyword"] = self.keyword
if self.sql_type is not None:
body["sql_type"] = self.sql_type
if self.value is not None:
body["value"] = self.value
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> QueryAttachmentParameter:
"""Deserializes the QueryAttachmentParameter from a dictionary."""
return cls(keyword=d.get("keyword", None), sql_type=d.get("sql_type", None), value=d.get("value", None))
@dataclass
class Result:
is_truncated: Optional[bool] = None
"""If result is truncated"""
row_count: Optional[int] = None
"""Row count of the result"""
statement_id: Optional[str] = None
"""Statement Execution API statement id. Use [Get status, manifest, and result first
chunk](:method:statementexecution/getstatement) to get the full result data."""
statement_id_signature: Optional[str] = None
"""JWT corresponding to the statement contained in this result"""
def as_dict(self) -> dict:
"""Serializes the Result into a dictionary suitable for use as a JSON request body."""
body = {}
if self.is_truncated is not None:
body["is_truncated"] = self.is_truncated
if self.row_count is not None:
body["row_count"] = self.row_count
if self.statement_id is not None:
body["statement_id"] = self.statement_id
if self.statement_id_signature is not None:
body["statement_id_signature"] = self.statement_id_signature
return body
def as_shallow_dict(self) -> dict:
"""Serializes the Result into a shallow dictionary of its immediate attributes."""
body = {}
if self.is_truncated is not None:
body["is_truncated"] = self.is_truncated
if self.row_count is not None:
body["row_count"] = self.row_count
if self.statement_id is not None:
body["statement_id"] = self.statement_id
if self.statement_id_signature is not None:
body["statement_id_signature"] = self.statement_id_signature
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> Result:
"""Deserializes the Result from a dictionary."""
return cls(
is_truncated=d.get("is_truncated", None),
row_count=d.get("row_count", None),
statement_id=d.get("statement_id", None),
statement_id_signature=d.get("statement_id_signature", None),
)
@dataclass
class Schedule:
cron_schedule: CronSchedule
"""The cron expression describing the frequency of the periodic refresh for this schedule."""
create_time: Optional[str] = None
"""A timestamp indicating when the schedule was created."""
dashboard_id: Optional[str] = None
"""UUID identifying the dashboard to which the schedule belongs."""
display_name: Optional[str] = None
"""The display name for schedule."""
etag: Optional[str] = None
"""The etag for the schedule. Must be left empty on create, must be provided on updates to ensure
that the schedule has not been modified since the last read, and can be optionally provided on
delete."""
pause_status: Optional[SchedulePauseStatus] = None
"""The status indicates whether this schedule is paused or not."""
schedule_id: Optional[str] = None
"""UUID identifying the schedule."""
update_time: Optional[str] = None
"""A timestamp indicating when the schedule was last updated."""
warehouse_id: Optional[str] = None
"""The warehouse id to run the dashboard with for the schedule."""
def as_dict(self) -> dict:
"""Serializes the Schedule into a dictionary suitable for use as a JSON request body."""
body = {}
if self.create_time is not None:
body["create_time"] = self.create_time
if self.cron_schedule:
body["cron_schedule"] = self.cron_schedule.as_dict()
if self.dashboard_id is not None:
body["dashboard_id"] = self.dashboard_id
if self.display_name is not None:
body["display_name"] = self.display_name
if self.etag is not None:
body["etag"] = self.etag
if self.pause_status is not None:
body["pause_status"] = self.pause_status.value
if self.schedule_id is not None:
body["schedule_id"] = self.schedule_id
if self.update_time is not None:
body["update_time"] = self.update_time
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the Schedule into a shallow dictionary of its immediate attributes."""
body = {}
if self.create_time is not None:
body["create_time"] = self.create_time
if self.cron_schedule:
body["cron_schedule"] = self.cron_schedule
if self.dashboard_id is not None:
body["dashboard_id"] = self.dashboard_id
if self.display_name is not None:
body["display_name"] = self.display_name
if self.etag is not None:
body["etag"] = self.etag
if self.pause_status is not None:
body["pause_status"] = self.pause_status
if self.schedule_id is not None:
body["schedule_id"] = self.schedule_id
if self.update_time is not None:
body["update_time"] = self.update_time
if self.warehouse_id is not None:
body["warehouse_id"] = self.warehouse_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> Schedule:
"""Deserializes the Schedule from a dictionary."""
return cls(
create_time=d.get("create_time", None),
cron_schedule=_from_dict(d, "cron_schedule", CronSchedule),
dashboard_id=d.get("dashboard_id", None),
display_name=d.get("display_name", None),
etag=d.get("etag", None),
pause_status=_enum(d, "pause_status", SchedulePauseStatus),
schedule_id=d.get("schedule_id", None),
update_time=d.get("update_time", None),
warehouse_id=d.get("warehouse_id", None),
)
class SchedulePauseStatus(Enum):
PAUSED = "PAUSED"
UNPAUSED = "UNPAUSED"
@dataclass
class Subscriber:
destination_subscriber: Optional[SubscriptionSubscriberDestination] = None
"""The destination to receive the subscription email. This parameter is mutually exclusive with
`user_subscriber`."""
user_subscriber: Optional[SubscriptionSubscriberUser] = None
"""The user to receive the subscription email. This parameter is mutually exclusive with
`destination_subscriber`."""
def as_dict(self) -> dict:
"""Serializes the Subscriber into a dictionary suitable for use as a JSON request body."""
body = {}
if self.destination_subscriber:
body["destination_subscriber"] = self.destination_subscriber.as_dict()
if self.user_subscriber:
body["user_subscriber"] = self.user_subscriber.as_dict()
return body
def as_shallow_dict(self) -> dict:
"""Serializes the Subscriber into a shallow dictionary of its immediate attributes."""
body = {}
if self.destination_subscriber:
body["destination_subscriber"] = self.destination_subscriber
if self.user_subscriber:
body["user_subscriber"] = self.user_subscriber
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> Subscriber:
"""Deserializes the Subscriber from a dictionary."""
return cls(
destination_subscriber=_from_dict(d, "destination_subscriber", SubscriptionSubscriberDestination),
user_subscriber=_from_dict(d, "user_subscriber", SubscriptionSubscriberUser),
)
@dataclass
class Subscription:
subscriber: Subscriber
"""Subscriber details for users and destinations to be added as subscribers to the schedule."""
create_time: Optional[str] = None
"""A timestamp indicating when the subscription was created."""
created_by_user_id: Optional[int] = None
"""UserId of the user who adds subscribers (users or notification destinations) to the dashboard's
schedule."""
dashboard_id: Optional[str] = None
"""UUID identifying the dashboard to which the subscription belongs."""
etag: Optional[str] = None
"""The etag for the subscription. Must be left empty on create, can be optionally provided on
delete to ensure that the subscription has not been deleted since the last read."""
schedule_id: Optional[str] = None
"""UUID identifying the schedule to which the subscription belongs."""
skip_notify: Optional[bool] = None
"""Controls whether notifications are sent to the subscriber for scheduled dashboard refreshes. If
not defined, defaults to false in the backend to match the current behavior (refresh and notify)"""
subscription_id: Optional[str] = None
"""UUID identifying the subscription."""
update_time: Optional[str] = None
"""A timestamp indicating when the subscription was last updated."""
def as_dict(self) -> dict:
"""Serializes the Subscription into a dictionary suitable for use as a JSON request body."""
body = {}
if self.create_time is not None:
body["create_time"] = self.create_time
if self.created_by_user_id is not None:
body["created_by_user_id"] = self.created_by_user_id
if self.dashboard_id is not None:
body["dashboard_id"] = self.dashboard_id
if self.etag is not None:
body["etag"] = self.etag
if self.schedule_id is not None:
body["schedule_id"] = self.schedule_id
if self.skip_notify is not None:
body["skip_notify"] = self.skip_notify
if self.subscriber:
body["subscriber"] = self.subscriber.as_dict()
if self.subscription_id is not None:
body["subscription_id"] = self.subscription_id
if self.update_time is not None:
body["update_time"] = self.update_time
return body
def as_shallow_dict(self) -> dict:
"""Serializes the Subscription into a shallow dictionary of its immediate attributes."""
body = {}
if self.create_time is not None:
body["create_time"] = self.create_time
if self.created_by_user_id is not None:
body["created_by_user_id"] = self.created_by_user_id
if self.dashboard_id is not None:
body["dashboard_id"] = self.dashboard_id
if self.etag is not None:
body["etag"] = self.etag
if self.schedule_id is not None:
body["schedule_id"] = self.schedule_id
if self.skip_notify is not None:
body["skip_notify"] = self.skip_notify
if self.subscriber:
body["subscriber"] = self.subscriber
if self.subscription_id is not None:
body["subscription_id"] = self.subscription_id
if self.update_time is not None:
body["update_time"] = self.update_time
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> Subscription:
"""Deserializes the Subscription from a dictionary."""
return cls(
create_time=d.get("create_time", None),
created_by_user_id=d.get("created_by_user_id", None),
dashboard_id=d.get("dashboard_id", None),
etag=d.get("etag", None),
schedule_id=d.get("schedule_id", None),
skip_notify=d.get("skip_notify", None),
subscriber=_from_dict(d, "subscriber", Subscriber),
subscription_id=d.get("subscription_id", None),
update_time=d.get("update_time", None),
)
@dataclass
class SubscriptionSubscriberDestination:
destination_id: str
"""The canonical identifier of the destination to receive email notification."""
def as_dict(self) -> dict:
"""Serializes the SubscriptionSubscriberDestination into a dictionary suitable for use as a JSON request body."""
body = {}
if self.destination_id is not None:
body["destination_id"] = self.destination_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the SubscriptionSubscriberDestination into a shallow dictionary of its immediate attributes."""
body = {}
if self.destination_id is not None:
body["destination_id"] = self.destination_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> SubscriptionSubscriberDestination:
"""Deserializes the SubscriptionSubscriberDestination from a dictionary."""
return cls(destination_id=d.get("destination_id", None))
@dataclass
class SubscriptionSubscriberUser:
user_id: int
"""UserId of the subscriber."""
def as_dict(self) -> dict:
"""Serializes the SubscriptionSubscriberUser into a dictionary suitable for use as a JSON request body."""
body = {}
if self.user_id is not None:
body["user_id"] = self.user_id
return body
def as_shallow_dict(self) -> dict:
"""Serializes the SubscriptionSubscriberUser into a shallow dictionary of its immediate attributes."""
body = {}
if self.user_id is not None:
body["user_id"] = self.user_id
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> SubscriptionSubscriberUser:
"""Deserializes the SubscriptionSubscriberUser from a dictionary."""
return cls(user_id=d.get("user_id", None))
@dataclass
class TextAttachment:
content: Optional[str] = None
"""AI generated message"""
id: Optional[str] = None
purpose: Optional[TextAttachmentPurpose] = None
"""Purpose/intent of this text attachment"""
def as_dict(self) -> dict:
"""Serializes the TextAttachment into a dictionary suitable for use as a JSON request body."""
body = {}
if self.content is not None:
body["content"] = self.content
if self.id is not None:
body["id"] = self.id
if self.purpose is not None:
body["purpose"] = self.purpose.value
return body
def as_shallow_dict(self) -> dict:
"""Serializes the TextAttachment into a shallow dictionary of its immediate attributes."""
body = {}
if self.content is not None:
body["content"] = self.content
if self.id is not None:
body["id"] = self.id
if self.purpose is not None:
body["purpose"] = self.purpose
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> TextAttachment:
"""Deserializes the TextAttachment from a dictionary."""
return cls(
content=d.get("content", None), id=d.get("id", None), purpose=_enum(d, "purpose", TextAttachmentPurpose)
)
class TextAttachmentPurpose(Enum):
"""Purpose/intent of a text attachment"""
FOLLOW_UP_QUESTION = "FOLLOW_UP_QUESTION"
@dataclass
class TrashDashboardResponse:
def as_dict(self) -> dict:
"""Serializes the TrashDashboardResponse into a dictionary suitable for use as a JSON request body."""
body = {}
return body
def as_shallow_dict(self) -> dict:
"""Serializes the TrashDashboardResponse into a shallow dictionary of its immediate attributes."""
body = {}
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> TrashDashboardResponse:
"""Deserializes the TrashDashboardResponse from a dictionary."""
return cls()
@dataclass
class UnpublishDashboardResponse:
def as_dict(self) -> dict:
"""Serializes the UnpublishDashboardResponse into a dictionary suitable for use as a JSON request body."""
body = {}
return body
def as_shallow_dict(self) -> dict:
"""Serializes the UnpublishDashboardResponse into a shallow dictionary of its immediate attributes."""
body = {}
return body
@classmethod
def from_dict(cls, d: Dict[str, Any]) -> UnpublishDashboardResponse:
"""Deserializes the UnpublishDashboardResponse from a dictionary."""
return cls()
class GenieAPI:
"""Genie provides a no-code experience for business users, powered by AI/BI. Analysts set up spaces that
business users can use to ask questions using natural language. Genie uses data registered to Unity
Catalog and requires at least CAN USE permission on a Pro or Serverless SQL warehouse. Also, Databricks
Assistant must be enabled."""
def __init__(self, api_client):
self._api = api_client
def wait_get_message_genie_completed(
self,
conversation_id: str,
message_id: str,
space_id: str,
timeout=timedelta(minutes=20),
callback: Optional[Callable[[GenieMessage], None]] = None,
) -> GenieMessage:
deadline = time.time() + timeout.total_seconds()
target_states = (MessageStatus.COMPLETED,)
failure_states = (MessageStatus.FAILED,)
status_message = "polling..."
attempt = 1
while time.time() < deadline:
poll = self.get_message(conversation_id=conversation_id, message_id=message_id, space_id=space_id)
status = poll.status
status_message = f"current status: {status}"
if status in target_states:
return poll
if callback:
callback(poll)
if status in failure_states:
msg = f"failed to reach COMPLETED, got {status}: {status_message}"
raise OperationFailed(msg)
prefix = f"conversation_id={conversation_id}, message_id={message_id}, space_id={space_id}"
sleep = attempt
if sleep > 10:
# sleep 10s max per attempt
sleep = 10
_LOG.debug(f"{prefix}: ({status}) {status_message} (sleeping ~{sleep}s)")
time.sleep(sleep + random.random())
attempt += 1
raise TimeoutError(f"timed out after {timeout}: {status_message}")
def create_message(self, space_id: str, conversation_id: str, content: str) -> Wait[GenieMessage]:
"""Create new message in a [conversation](:method:genie/startconversation). The AI response uses all
previously created messages in the conversation to respond.
:param space_id: str
The ID associated with the Genie space where the conversation is started.
:param conversation_id: str
The ID associated with the conversation.
:param content: str
User message content.
:returns:
Long-running operation waiter for :class:`GenieMessage`.
See :method:wait_get_message_genie_completed for more details.
"""
body = {}
if content is not None:
body["content"] = content
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
op_response = self._api.do(
"POST",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages",
body=body,
headers=headers,
)
return Wait(
self.wait_get_message_genie_completed,
response=GenieMessage.from_dict(op_response),
conversation_id=conversation_id,
message_id=op_response["message_id"],
space_id=space_id,
)
def create_message_and_wait(
self, space_id: str, conversation_id: str, content: str, timeout=timedelta(minutes=20)
) -> GenieMessage:
return self.create_message(content=content, conversation_id=conversation_id, space_id=space_id).result(
timeout=timeout
)
def create_space(
self,
warehouse_id: str,
serialized_space: str,
*,
description: Optional[str] = None,
parent_path: Optional[str] = None,
title: Optional[str] = None,
) -> GenieSpace:
"""Creates a Genie space from a serialized payload.
:param warehouse_id: str
Warehouse to associate with the new space
:param serialized_space: str
The contents of the Genie Space in serialized string form. Use the [Get Genie
Space](:method:genie/getspace) API to retrieve an example response, which includes the
`serialized_space` field. This field provides the structure of the JSON string that represents the
space's layout and components.
:param description: str (optional)
Optional description
:param parent_path: str (optional)
Parent folder path where the space will be registered
:param title: str (optional)
Optional title override
:returns: :class:`GenieSpace`
"""
body = {}
if description is not None:
body["description"] = description
if parent_path is not None:
body["parent_path"] = parent_path
if serialized_space is not None:
body["serialized_space"] = serialized_space
if title is not None:
body["title"] = title
if warehouse_id is not None:
body["warehouse_id"] = warehouse_id
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("POST", "/api/2.0/genie/spaces", body=body, headers=headers)
return GenieSpace.from_dict(res)
def delete_conversation(self, space_id: str, conversation_id: str):
"""Delete a conversation.
:param space_id: str
The ID associated with the Genie space where the conversation is located.
:param conversation_id: str
The ID of the conversation to delete.
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do("DELETE", f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}", headers=headers)
def delete_conversation_message(self, space_id: str, conversation_id: str, message_id: str):
"""Delete a conversation message.
:param space_id: str
The ID associated with the Genie space where the message is located.
:param conversation_id: str
The ID associated with the conversation.
:param message_id: str
The ID associated with the message to delete.
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do(
"DELETE",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}",
headers=headers,
)
def execute_message_attachment_query(
self, space_id: str, conversation_id: str, message_id: str, attachment_id: str
) -> GenieGetMessageQueryResultResponse:
"""Execute the SQL for a message query attachment. Use this API when the query attachment has expired and
needs to be re-executed.
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:param attachment_id: str
Attachment ID
:returns: :class:`GenieGetMessageQueryResultResponse`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"POST",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/attachments/{attachment_id}/execute-query",
headers=headers,
)
return GenieGetMessageQueryResultResponse.from_dict(res)
def execute_message_query(
self, space_id: str, conversation_id: str, message_id: str
) -> GenieGetMessageQueryResultResponse:
"""DEPRECATED: Use [Execute Message Attachment Query](:method:genie/executemessageattachmentquery)
instead.
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:returns: :class:`GenieGetMessageQueryResultResponse`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"POST",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/execute-query",
headers=headers,
)
return GenieGetMessageQueryResultResponse.from_dict(res)
def generate_download_full_query_result(
self, space_id: str, conversation_id: str, message_id: str, attachment_id: str
) -> GenieGenerateDownloadFullQueryResultResponse:
"""Initiates a new SQL execution and returns a `download_id` and `download_id_signature` that you can use
to track the progress of the download. The query result is stored in an external link and can be
retrieved using the [Get Download Full Query Result](:method:genie/getdownloadfullqueryresult) API.
Both `download_id` and `download_id_signature` must be provided when calling the Get endpoint.
----
### **Warning: Databricks strongly recommends that you protect the URLs that are returned by the
`EXTERNAL_LINKS` disposition.**
When you use the `EXTERNAL_LINKS` disposition, a short-lived, URL is generated, which can be used to
download the results directly from . As a short-lived is embedded in this URL, you should protect the
URL.
Because URLs are already generated with embedded temporary s, you must not set an `Authorization`
header in the download requests.
See [Execute Statement](:method:statementexecution/executestatement) for more details.
----
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:param attachment_id: str
Attachment ID
:returns: :class:`GenieGenerateDownloadFullQueryResultResponse`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"POST",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/attachments/{attachment_id}/downloads",
headers=headers,
)
return GenieGenerateDownloadFullQueryResultResponse.from_dict(res)
def get_download_full_query_result(
self,
space_id: str,
conversation_id: str,
message_id: str,
attachment_id: str,
download_id: str,
download_id_signature: str,
) -> GenieGetDownloadFullQueryResultResponse:
"""After [Generating a Full Query Result Download](:method:genie/generatedownloadfullqueryresult) and
successfully receiving a `download_id` and `download_id_signature`, use this API to poll the download
progress. Both `download_id` and `download_id_signature` are required to call this endpoint. When the
download is complete, the API returns the result in the `EXTERNAL_LINKS` disposition, containing one
or more external links to the query result files.
----
### **Warning: Databricks strongly recommends that you protect the URLs that are returned by the
`EXTERNAL_LINKS` disposition.**
When you use the `EXTERNAL_LINKS` disposition, a short-lived, URL is generated, which can be used to
download the results directly from . As a short-lived is embedded in this URL, you should protect the
URL.
Because URLs are already generated with embedded temporary s, you must not set an `Authorization`
header in the download requests.
See [Execute Statement](:method:statementexecution/executestatement) for more details.
----
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:param attachment_id: str
Attachment ID
:param download_id: str
Download ID. This ID is provided by the [Generate Download
endpoint](:method:genie/generateDownloadFullQueryResult)
:param download_id_signature: str
JWT signature for the download_id to ensure secure access to query results
:returns: :class:`GenieGetDownloadFullQueryResultResponse`
"""
query = {}
if download_id_signature is not None:
query["download_id_signature"] = download_id_signature
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/attachments/{attachment_id}/downloads/{download_id}",
query=query,
headers=headers,
)
return GenieGetDownloadFullQueryResultResponse.from_dict(res)
def get_message(self, space_id: str, conversation_id: str, message_id: str) -> GenieMessage:
"""Get message from conversation.
:param space_id: str
The ID associated with the Genie space where the target conversation is located.
:param conversation_id: str
The ID associated with the target conversation.
:param message_id: str
The ID associated with the target message from the identified conversation.
:returns: :class:`GenieMessage`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}",
headers=headers,
)
return GenieMessage.from_dict(res)
def get_message_attachment_query_result(
self, space_id: str, conversation_id: str, message_id: str, attachment_id: str
) -> GenieGetMessageQueryResultResponse:
"""Get the result of SQL query if the message has a query attachment. This is only available if a message
has a query attachment and the message status is `EXECUTING_QUERY` OR `COMPLETED`.
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:param attachment_id: str
Attachment ID
:returns: :class:`GenieGetMessageQueryResultResponse`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/attachments/{attachment_id}/query-result",
headers=headers,
)
return GenieGetMessageQueryResultResponse.from_dict(res)
def get_message_query_result(
self, space_id: str, conversation_id: str, message_id: str
) -> GenieGetMessageQueryResultResponse:
"""DEPRECATED: Use [Get Message Attachment Query Result](:method:genie/getmessageattachmentqueryresult)
instead.
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:returns: :class:`GenieGetMessageQueryResultResponse`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/query-result",
headers=headers,
)
return GenieGetMessageQueryResultResponse.from_dict(res)
def get_message_query_result_by_attachment(
self, space_id: str, conversation_id: str, message_id: str, attachment_id: str
) -> GenieGetMessageQueryResultResponse:
"""DEPRECATED: Use [Get Message Attachment Query Result](:method:genie/getmessageattachmentqueryresult)
instead.
:param space_id: str
Genie space ID
:param conversation_id: str
Conversation ID
:param message_id: str
Message ID
:param attachment_id: str
Attachment ID
:returns: :class:`GenieGetMessageQueryResultResponse`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/query-result/{attachment_id}",
headers=headers,
)
return GenieGetMessageQueryResultResponse.from_dict(res)
def get_space(self, space_id: str, *, include_serialized_space: Optional[bool] = None) -> GenieSpace:
"""Get details of a Genie Space.
:param space_id: str
The ID associated with the Genie space
:param include_serialized_space: bool (optional)
Whether to include the serialized space export in the response. Requires at least CAN EDIT
permission on the space.
:returns: :class:`GenieSpace`
"""
query = {}
if include_serialized_space is not None:
query["include_serialized_space"] = include_serialized_space
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("GET", f"/api/2.0/genie/spaces/{space_id}", query=query, headers=headers)
return GenieSpace.from_dict(res)
def list_conversation_messages(
self, space_id: str, conversation_id: str, *, page_size: Optional[int] = None, page_token: Optional[str] = None
) -> GenieListConversationMessagesResponse:
"""List messages in a conversation
:param space_id: str
The ID associated with the Genie space where the conversation is located
:param conversation_id: str
The ID of the conversation to list messages from
:param page_size: int (optional)
Maximum number of messages to return per page
:param page_token: str (optional)
Token to get the next page of results
:returns: :class:`GenieListConversationMessagesResponse`
"""
query = {}
if page_size is not None:
query["page_size"] = page_size
if page_token is not None:
query["page_token"] = page_token
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages",
query=query,
headers=headers,
)
return GenieListConversationMessagesResponse.from_dict(res)
def list_conversations(
self,
space_id: str,
*,
include_all: Optional[bool] = None,
page_size: Optional[int] = None,
page_token: Optional[str] = None,
) -> GenieListConversationsResponse:
"""Get a list of conversations in a Genie Space.
:param space_id: str
The ID of the Genie space to retrieve conversations from.
:param include_all: bool (optional)
Include all conversations in the space across all users. Requires at least CAN MANAGE permission on
the space.
:param page_size: int (optional)
Maximum number of conversations to return per page
:param page_token: str (optional)
Token to get the next page of results
:returns: :class:`GenieListConversationsResponse`
"""
query = {}
if include_all is not None:
query["include_all"] = include_all
if page_size is not None:
query["page_size"] = page_size
if page_token is not None:
query["page_token"] = page_token
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("GET", f"/api/2.0/genie/spaces/{space_id}/conversations", query=query, headers=headers)
return GenieListConversationsResponse.from_dict(res)
def list_spaces(
self, *, page_size: Optional[int] = None, page_token: Optional[str] = None
) -> GenieListSpacesResponse:
"""Get list of Genie Spaces.
:param page_size: int (optional)
Maximum number of spaces to return per page
:param page_token: str (optional)
Pagination token for getting the next page of results
:returns: :class:`GenieListSpacesResponse`
"""
query = {}
if page_size is not None:
query["page_size"] = page_size
if page_token is not None:
query["page_token"] = page_token
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("GET", "/api/2.0/genie/spaces", query=query, headers=headers)
return GenieListSpacesResponse.from_dict(res)
def send_message_feedback(self, space_id: str, conversation_id: str, message_id: str, rating: GenieFeedbackRating):
"""Send feedback for a message.
:param space_id: str
The ID associated with the Genie space where the message is located.
:param conversation_id: str
The ID associated with the conversation.
:param message_id: str
The ID associated with the message to provide feedback for.
:param rating: :class:`GenieFeedbackRating`
The rating (POSITIVE, NEGATIVE, or NONE).
"""
body = {}
if rating is not None:
body["rating"] = rating.value
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do(
"POST",
f"/api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/feedback",
body=body,
headers=headers,
)
def start_conversation(self, space_id: str, content: str) -> Wait[GenieMessage]:
"""Start a new conversation.
:param space_id: str
The ID associated with the Genie space where you want to start a conversation.
:param content: str
The text of the message that starts the conversation.
:returns:
Long-running operation waiter for :class:`GenieMessage`.
See :method:wait_get_message_genie_completed for more details.
"""
body = {}
if content is not None:
body["content"] = content
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
op_response = self._api.do(
"POST", f"/api/2.0/genie/spaces/{space_id}/start-conversation", body=body, headers=headers
)
return Wait(
self.wait_get_message_genie_completed,
response=GenieStartConversationResponse.from_dict(op_response),
conversation_id=op_response["conversation_id"],
message_id=op_response["message_id"],
space_id=space_id,
)
def start_conversation_and_wait(self, space_id: str, content: str, timeout=timedelta(minutes=20)) -> GenieMessage:
return self.start_conversation(content=content, space_id=space_id).result(timeout=timeout)
def trash_space(self, space_id: str):
"""Move a Genie Space to the trash.
:param space_id: str
The ID associated with the Genie space to be sent to the trash.
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do("DELETE", f"/api/2.0/genie/spaces/{space_id}", headers=headers)
def update_space(
self,
space_id: str,
*,
description: Optional[str] = None,
serialized_space: Optional[str] = None,
title: Optional[str] = None,
warehouse_id: Optional[str] = None,
) -> GenieSpace:
"""Updates a Genie space with a serialized payload.
:param space_id: str
Genie space ID
:param description: str (optional)
Optional description
:param serialized_space: str (optional)
The contents of the Genie Space in serialized string form (full replacement). Use the [Get Genie
Space](:method:genie/getspace) API to retrieve an example response, which includes the
`serialized_space` field. This field provides the structure of the JSON string that represents the
space's layout and components.
:param title: str (optional)
Optional title override
:param warehouse_id: str (optional)
Optional warehouse override
:returns: :class:`GenieSpace`
"""
body = {}
if description is not None:
body["description"] = description
if serialized_space is not None:
body["serialized_space"] = serialized_space
if title is not None:
body["title"] = title
if warehouse_id is not None:
body["warehouse_id"] = warehouse_id
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("PATCH", f"/api/2.0/genie/spaces/{space_id}", body=body, headers=headers)
return GenieSpace.from_dict(res)
class LakeviewAPI:
"""These APIs provide specific management operations for Lakeview dashboards. Generic resource management can
be done with Workspace API (import, export, get-status, list, delete)."""
def __init__(self, api_client):
self._api = api_client
def create(
self, dashboard: Dashboard, *, dataset_catalog: Optional[str] = None, dataset_schema: Optional[str] = None
) -> Dashboard:
"""Create a draft dashboard.
:param dashboard: :class:`Dashboard`
:param dataset_catalog: str (optional)
Sets the default catalog for all datasets in this dashboard. Does not impact table references that
use fully qualified catalog names (ex: samples.nyctaxi.trips). Leave blank to keep each datasets
existing configuration.
:param dataset_schema: str (optional)
Sets the default schema for all datasets in this dashboard. Does not impact table references that
use fully qualified schema names (ex: nyctaxi.trips). Leave blank to keep each datasets existing
configuration.
:returns: :class:`Dashboard`
"""
body = dashboard.as_dict()
query = {}
if dataset_catalog is not None:
query["dataset_catalog"] = dataset_catalog
if dataset_schema is not None:
query["dataset_schema"] = dataset_schema
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("POST", "/api/2.0/lakeview/dashboards", query=query, body=body, headers=headers)
return Dashboard.from_dict(res)
def create_schedule(self, dashboard_id: str, schedule: Schedule) -> Schedule:
"""Create dashboard schedule.
:param dashboard_id: str
UUID identifying the dashboard to which the schedule belongs.
:param schedule: :class:`Schedule`
The schedule to create. A dashboard is limited to 10 schedules.
:returns: :class:`Schedule`
"""
body = schedule.as_dict()
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("POST", f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules", body=body, headers=headers)
return Schedule.from_dict(res)
def create_subscription(self, dashboard_id: str, schedule_id: str, subscription: Subscription) -> Subscription:
"""Create schedule subscription.
:param dashboard_id: str
UUID identifying the dashboard to which the subscription belongs.
:param schedule_id: str
UUID identifying the schedule to which the subscription belongs.
:param subscription: :class:`Subscription`
The subscription to create. A schedule is limited to 100 subscriptions.
:returns: :class:`Subscription`
"""
body = subscription.as_dict()
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"POST",
f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}/subscriptions",
body=body,
headers=headers,
)
return Subscription.from_dict(res)
def delete_schedule(self, dashboard_id: str, schedule_id: str, *, etag: Optional[str] = None):
"""Delete dashboard schedule.
:param dashboard_id: str
UUID identifying the dashboard to which the schedule belongs.
:param schedule_id: str
UUID identifying the schedule.
:param etag: str (optional)
The etag for the schedule. Optionally, it can be provided to verify that the schedule has not been
modified from its last retrieval.
"""
query = {}
if etag is not None:
query["etag"] = etag
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do(
"DELETE",
f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}",
query=query,
headers=headers,
)
def delete_subscription(
self, dashboard_id: str, schedule_id: str, subscription_id: str, *, etag: Optional[str] = None
):
"""Delete schedule subscription.
:param dashboard_id: str
UUID identifying the dashboard which the subscription belongs.
:param schedule_id: str
UUID identifying the schedule which the subscription belongs.
:param subscription_id: str
UUID identifying the subscription.
:param etag: str (optional)
The etag for the subscription. Can be optionally provided to ensure that the subscription has not
been modified since the last read.
"""
query = {}
if etag is not None:
query["etag"] = etag
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do(
"DELETE",
f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}/subscriptions/{subscription_id}",
query=query,
headers=headers,
)
def get(self, dashboard_id: str) -> Dashboard:
"""Get a draft dashboard.
:param dashboard_id: str
UUID identifying the dashboard.
:returns: :class:`Dashboard`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("GET", f"/api/2.0/lakeview/dashboards/{dashboard_id}", headers=headers)
return Dashboard.from_dict(res)
def get_published(self, dashboard_id: str) -> PublishedDashboard:
"""Get the current published dashboard.
:param dashboard_id: str
UUID identifying the published dashboard.
:returns: :class:`PublishedDashboard`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("GET", f"/api/2.0/lakeview/dashboards/{dashboard_id}/published", headers=headers)
return PublishedDashboard.from_dict(res)
def get_schedule(self, dashboard_id: str, schedule_id: str) -> Schedule:
"""Get dashboard schedule.
:param dashboard_id: str
UUID identifying the dashboard to which the schedule belongs.
:param schedule_id: str
UUID identifying the schedule.
:returns: :class:`Schedule`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET", f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}", headers=headers
)
return Schedule.from_dict(res)
def get_subscription(self, dashboard_id: str, schedule_id: str, subscription_id: str) -> Subscription:
"""Get schedule subscription.
:param dashboard_id: str
UUID identifying the dashboard which the subscription belongs.
:param schedule_id: str
UUID identifying the schedule which the subscription belongs.
:param subscription_id: str
UUID identifying the subscription.
:returns: :class:`Subscription`
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET",
f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}/subscriptions/{subscription_id}",
headers=headers,
)
return Subscription.from_dict(res)
def list(
self,
*,
page_size: Optional[int] = None,
page_token: Optional[str] = None,
show_trashed: Optional[bool] = None,
view: Optional[DashboardView] = None,
) -> Iterator[Dashboard]:
"""List dashboards.
:param page_size: int (optional)
The number of dashboards to return per page.
:param page_token: str (optional)
A page token, received from a previous `ListDashboards` call. This token can be used to retrieve the
subsequent page.
:param show_trashed: bool (optional)
The flag to include dashboards located in the trash. If unspecified, only active dashboards will be
returned.
:param view: :class:`DashboardView` (optional)
`DASHBOARD_VIEW_BASIC`only includes summary metadata from the dashboard.
:returns: Iterator over :class:`Dashboard`
"""
query = {}
if page_size is not None:
query["page_size"] = page_size
if page_token is not None:
query["page_token"] = page_token
if show_trashed is not None:
query["show_trashed"] = show_trashed
if view is not None:
query["view"] = view.value
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
while True:
json = self._api.do("GET", "/api/2.0/lakeview/dashboards", query=query, headers=headers)
if "dashboards" in json:
for v in json["dashboards"]:
yield Dashboard.from_dict(v)
if "next_page_token" not in json or not json["next_page_token"]:
return
query["page_token"] = json["next_page_token"]
def list_schedules(
self, dashboard_id: str, *, page_size: Optional[int] = None, page_token: Optional[str] = None
) -> Iterator[Schedule]:
"""List dashboard schedules.
:param dashboard_id: str
UUID identifying the dashboard to which the schedules belongs.
:param page_size: int (optional)
The number of schedules to return per page.
:param page_token: str (optional)
A page token, received from a previous `ListSchedules` call. Use this to retrieve the subsequent
page.
:returns: Iterator over :class:`Schedule`
"""
query = {}
if page_size is not None:
query["page_size"] = page_size
if page_token is not None:
query["page_token"] = page_token
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
while True:
json = self._api.do(
"GET", f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules", query=query, headers=headers
)
if "schedules" in json:
for v in json["schedules"]:
yield Schedule.from_dict(v)
if "next_page_token" not in json or not json["next_page_token"]:
return
query["page_token"] = json["next_page_token"]
def list_subscriptions(
self, dashboard_id: str, schedule_id: str, *, page_size: Optional[int] = None, page_token: Optional[str] = None
) -> Iterator[Subscription]:
"""List schedule subscriptions.
:param dashboard_id: str
UUID identifying the dashboard which the subscriptions belongs.
:param schedule_id: str
UUID identifying the schedule which the subscriptions belongs.
:param page_size: int (optional)
The number of subscriptions to return per page.
:param page_token: str (optional)
A page token, received from a previous `ListSubscriptions` call. Use this to retrieve the subsequent
page.
:returns: Iterator over :class:`Subscription`
"""
query = {}
if page_size is not None:
query["page_size"] = page_size
if page_token is not None:
query["page_token"] = page_token
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
while True:
json = self._api.do(
"GET",
f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}/subscriptions",
query=query,
headers=headers,
)
if "subscriptions" in json:
for v in json["subscriptions"]:
yield Subscription.from_dict(v)
if "next_page_token" not in json or not json["next_page_token"]:
return
query["page_token"] = json["next_page_token"]
def migrate(
self,
source_dashboard_id: str,
*,
display_name: Optional[str] = None,
parent_path: Optional[str] = None,
update_parameter_syntax: Optional[bool] = None,
) -> Dashboard:
"""Migrates a classic SQL dashboard to Lakeview.
:param source_dashboard_id: str
UUID of the dashboard to be migrated.
:param display_name: str (optional)
Display name for the new Lakeview dashboard.
:param parent_path: str (optional)
The workspace path of the folder to contain the migrated Lakeview dashboard.
:param update_parameter_syntax: bool (optional)
Flag to indicate if mustache parameter syntax ({{ param }}) should be auto-updated to named syntax
(:param) when converting datasets in the dashboard.
:returns: :class:`Dashboard`
"""
body = {}
if display_name is not None:
body["display_name"] = display_name
if parent_path is not None:
body["parent_path"] = parent_path
if source_dashboard_id is not None:
body["source_dashboard_id"] = source_dashboard_id
if update_parameter_syntax is not None:
body["update_parameter_syntax"] = update_parameter_syntax
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("POST", "/api/2.0/lakeview/dashboards/migrate", body=body, headers=headers)
return Dashboard.from_dict(res)
def publish(
self, dashboard_id: str, *, embed_credentials: Optional[bool] = None, warehouse_id: Optional[str] = None
) -> PublishedDashboard:
"""Publish the current draft dashboard.
:param dashboard_id: str
UUID identifying the dashboard to be published.
:param embed_credentials: bool (optional)
Flag to indicate if the publisher's credentials should be embedded in the published dashboard. These
embedded credentials will be used to execute the published dashboard's queries.
:param warehouse_id: str (optional)
The ID of the warehouse that can be used to override the warehouse which was set in the draft.
:returns: :class:`PublishedDashboard`
"""
body = {}
if embed_credentials is not None:
body["embed_credentials"] = embed_credentials
if warehouse_id is not None:
body["warehouse_id"] = warehouse_id
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do("POST", f"/api/2.0/lakeview/dashboards/{dashboard_id}/published", body=body, headers=headers)
return PublishedDashboard.from_dict(res)
def trash(self, dashboard_id: str):
"""Trash a dashboard.
:param dashboard_id: str
UUID identifying the dashboard.
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do("DELETE", f"/api/2.0/lakeview/dashboards/{dashboard_id}", headers=headers)
def unpublish(self, dashboard_id: str):
"""Unpublish the dashboard.
:param dashboard_id: str
UUID identifying the published dashboard.
"""
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
self._api.do("DELETE", f"/api/2.0/lakeview/dashboards/{dashboard_id}/published", headers=headers)
def update(
self,
dashboard_id: str,
dashboard: Dashboard,
*,
dataset_catalog: Optional[str] = None,
dataset_schema: Optional[str] = None,
) -> Dashboard:
"""Update a draft dashboard.
:param dashboard_id: str
UUID identifying the dashboard.
:param dashboard: :class:`Dashboard`
:param dataset_catalog: str (optional)
Sets the default catalog for all datasets in this dashboard. Does not impact table references that
use fully qualified catalog names (ex: samples.nyctaxi.trips). Leave blank to keep each datasets
existing configuration.
:param dataset_schema: str (optional)
Sets the default schema for all datasets in this dashboard. Does not impact table references that
use fully qualified schema names (ex: nyctaxi.trips). Leave blank to keep each datasets existing
configuration.
:returns: :class:`Dashboard`
"""
body = dashboard.as_dict()
query = {}
if dataset_catalog is not None:
query["dataset_catalog"] = dataset_catalog
if dataset_schema is not None:
query["dataset_schema"] = dataset_schema
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"PATCH", f"/api/2.0/lakeview/dashboards/{dashboard_id}", query=query, body=body, headers=headers
)
return Dashboard.from_dict(res)
def update_schedule(self, dashboard_id: str, schedule_id: str, schedule: Schedule) -> Schedule:
"""Update dashboard schedule.
:param dashboard_id: str
UUID identifying the dashboard to which the schedule belongs.
:param schedule_id: str
UUID identifying the schedule.
:param schedule: :class:`Schedule`
The schedule to update.
:returns: :class:`Schedule`
"""
body = schedule.as_dict()
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"PUT", f"/api/2.0/lakeview/dashboards/{dashboard_id}/schedules/{schedule_id}", body=body, headers=headers
)
return Schedule.from_dict(res)
class LakeviewEmbeddedAPI:
"""Token-based Lakeview APIs for embedding dashboards in external applications."""
def __init__(self, api_client):
self._api = api_client
def get_published_dashboard_token_info(
self, dashboard_id: str, *, external_value: Optional[str] = None, external_viewer_id: Optional[str] = None
) -> GetPublishedDashboardTokenInfoResponse:
"""Get a required authorization details and scopes of a published dashboard to mint an OAuth token.
:param dashboard_id: str
UUID identifying the published dashboard.
:param external_value: str (optional)
Provided external value to be included in the custom claim.
:param external_viewer_id: str (optional)
Provided external viewer id to be included in the custom claim.
:returns: :class:`GetPublishedDashboardTokenInfoResponse`
"""
query = {}
if external_value is not None:
query["external_value"] = external_value
if external_viewer_id is not None:
query["external_viewer_id"] = external_viewer_id
headers = {
"Accept": "application/json",
}
cfg = self._api._cfg
if cfg.host_type == HostType.UNIFIED and cfg.workspace_id:
headers["X-Databricks-Org-Id"] = cfg.workspace_id
res = self._api.do(
"GET", f"/api/2.0/lakeview/dashboards/{dashboard_id}/published/tokeninfo", query=query, headers=headers
)
return GetPublishedDashboardTokenInfoResponse.from_dict(res)