From fb289f375f28080defafc6fcf48534d1c651fff7 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 6 Nov 2025 18:01:21 +0000 Subject: [PATCH] Update SDK to bce9714cf1393c458531de222ef43e1e3afb57b0 --- .codegen/_openapi_sha | 2 +- NEXT_CHANGELOG.md | 4 + databricks/sdk/service/catalog.py | 2 +- databricks/sdk/service/dashboards.py | 17 +- databricks/sdk/service/iam.py | 5 +- databricks/sdk/service/jobs.py | 17 +- databricks/sdk/service/ml.py | 58 ++++- databricks/sdk/service/pipelines.py | 10 + databricks/sdk/service/vectorsearch.py | 232 ++++++++++++++++++ docs/account/iam/groups_v2.rst | 5 +- docs/account/iam/workspace_assignment.rst | 4 +- docs/account/provisioning/credentials.rst | 6 +- docs/account/provisioning/storage.rst | 7 +- docs/dbdataclasses/catalog.rst | 2 +- docs/dbdataclasses/dashboards.rst | 7 + docs/dbdataclasses/ml.rst | 4 + docs/dbdataclasses/vectorsearch.rst | 20 ++ docs/workspace/catalog/catalogs.rst | 7 +- .../workspace/catalog/storage_credentials.rst | 4 +- docs/workspace/catalog/tables.rst | 2 +- docs/workspace/jobs/jobs.rst | 25 +- docs/workspace/ml/model_registry.rst | 11 +- .../vectorsearch/vector_search_endpoints.rst | 20 ++ docs/workspace/workspace/workspace.rst | 12 +- tests/databricks/sdk/service/lrotesting.py | 21 +- tests/generated/test_json_marshall.py | 3 +- 26 files changed, 434 insertions(+), 73 deletions(-) diff --git a/.codegen/_openapi_sha b/.codegen/_openapi_sha index ad1e20e88..e1fc30fcc 100644 --- a/.codegen/_openapi_sha +++ b/.codegen/_openapi_sha @@ -1 +1 @@ -27cebd58ae24e19c95c675db3a93b6046abaca2a \ No newline at end of file +bce9714cf1393c458531de222ef43e1e3afb57b0 \ No newline at end of file diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index da08fc0c6..b8be1b5e7 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -13,3 +13,7 @@ ### Internal Changes ### API Changes +* Add `retrieve_user_visible_metrics()` method for [w.vector_search_endpoints](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/vectorsearch/vector_search_endpoints.html) workspace-level service. +* Add `purpose` field for `databricks.sdk.service.dashboards.TextAttachment`. +* Add `ingest_from_uc_foreign_catalog` field for `databricks.sdk.service.pipelines.IngestionPipelineDefinition`. +* [Breaking] Change `online_store_config` field for `databricks.sdk.service.ml.MaterializedFeature` to type `databricks.sdk.service.ml.OnlineStoreConfig` dataclass. \ No newline at end of file diff --git a/databricks/sdk/service/catalog.py b/databricks/sdk/service/catalog.py index a99c5405a..cbde1b8ca 100755 --- a/databricks/sdk/service/catalog.py +++ b/databricks/sdk/service/catalog.py @@ -8745,7 +8745,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Securable: class SecurableKind(Enum): - """Latest kind: CONNECTION_AWS_SECRETS_MANAGER = 270; Next id:271""" + """Latest kind: CONNECTION_POSTGRESQL_AWS_SERVICE_CRED = 271; Next id:272""" TABLE_DB_STORAGE = "TABLE_DB_STORAGE" TABLE_DELTA = "TABLE_DELTA" diff --git a/databricks/sdk/service/dashboards.py b/databricks/sdk/service/dashboards.py index 5bf772f27..44e02e4f9 100755 --- a/databricks/sdk/service/dashboards.py +++ b/databricks/sdk/service/dashboards.py @@ -1639,6 +1639,9 @@ class TextAttachment: 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 = {} @@ -1646,6 +1649,8 @@ def as_dict(self) -> dict: 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: @@ -1655,12 +1660,22 @@ def as_shallow_dict(self) -> dict: 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)) + 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 diff --git a/databricks/sdk/service/iam.py b/databricks/sdk/service/iam.py index e84121f29..4c0d13ab6 100755 --- a/databricks/sdk/service/iam.py +++ b/databricks/sdk/service/iam.py @@ -2525,8 +2525,9 @@ def list( start_index: Optional[int] = None, ) -> Iterator[AccountGroup]: """Gets all details of the groups associated with the Databricks account. As of 08/22/2025, this endpoint - will not return members. Instead, members should be retrieved by iterating through `Get group - details`. + will no longer return members. Instead, members should be retrieved by iterating through `Get group + details`. Existing accounts that rely on this attribute will not be impacted and will continue + receiving member data as before. :param attributes: str (optional) Comma-separated list of attributes to return in response. diff --git a/databricks/sdk/service/jobs.py b/databricks/sdk/service/jobs.py index 1ca8e631c..83b35a218 100755 --- a/databricks/sdk/service/jobs.py +++ b/databricks/sdk/service/jobs.py @@ -2915,10 +2915,10 @@ class JobSettings: environments: Optional[List[JobEnvironment]] = None """A list of task execution environment specifications that can be referenced by serverless tasks - of this job. An environment is required to be present for serverless tasks. For serverless - notebook tasks, the environment is accessible in the notebook environment panel. For other - serverless tasks, the task environment is required to be specified using environment_key in the - task settings.""" + of this job. For serverless notebook tasks, if the environment_key is not specified, the + notebook environment will be used if present. If a jobs environment is specified, it will + override the notebook environment. For other serverless tasks, the task environment is required + to be specified using environment_key in the task settings.""" format: Optional[Format] = None """Used to tell what is the format of the job. This field is ignored in Create/Update/Reset calls. @@ -8246,7 +8246,7 @@ class JobsAPI: scalable resources. Your job can consist of a single task or can be a large, multi-task workflow with complex dependencies. Databricks manages the task orchestration, cluster management, monitoring, and error reporting for all of your jobs. You can run your jobs immediately or periodically through an easy-to-use - scheduling system. You can implement job tasks using notebooks, JARS, Delta Live Tables pipelines, or + scheduling system. You can implement job tasks using notebooks, JARS, Spark Declarative Pipelines, or Python, Scala, Spark submit, and Java applications. You should never hard code secrets or store them in plain text. Use the [Secrets CLI] to manage secrets in @@ -8397,9 +8397,10 @@ def create( as when this job is deleted. :param environments: List[:class:`JobEnvironment`] (optional) A list of task execution environment specifications that can be referenced by serverless tasks of - this job. An environment is required to be present for serverless tasks. For serverless notebook - tasks, the environment is accessible in the notebook environment panel. For other serverless tasks, - the task environment is required to be specified using environment_key in the task settings. + this job. For serverless notebook tasks, if the environment_key is not specified, the notebook + environment will be used if present. If a jobs environment is specified, it will override the + notebook environment. For other serverless tasks, the task environment is required to be specified + using environment_key in the task settings. :param format: :class:`Format` (optional) Used to tell what is the format of the job. This field is ignored in Create/Update/Reset calls. When using the Jobs API 2.1 this value is always set to `"MULTI_TASK"`. diff --git a/databricks/sdk/service/ml.py b/databricks/sdk/service/ml.py index 94fd823ca..f6e84e53c 100755 --- a/databricks/sdk/service/ml.py +++ b/databricks/sdk/service/ml.py @@ -3154,7 +3154,7 @@ class MaterializedFeature: offline_store_config: Optional[OfflineStoreConfig] = None - online_store_config: Optional[OnlineStore] = None + online_store_config: Optional[OnlineStoreConfig] = None pipeline_schedule_state: Optional[MaterializedFeaturePipelineScheduleState] = None """The schedule state of the materialization pipeline.""" @@ -3209,7 +3209,7 @@ def from_dict(cls, d: Dict[str, Any]) -> MaterializedFeature: last_materialization_time=d.get("last_materialization_time", None), materialized_feature_id=d.get("materialized_feature_id", None), offline_store_config=_from_dict(d, "offline_store_config", OfflineStoreConfig), - online_store_config=_from_dict(d, "online_store_config", OnlineStore), + online_store_config=_from_dict(d, "online_store_config", OnlineStoreConfig), pipeline_schedule_state=_enum(d, "pipeline_schedule_state", MaterializedFeaturePipelineScheduleState), table_name=d.get("table_name", None), ) @@ -4013,6 +4013,60 @@ def from_dict(cls, d: Dict[str, Any]) -> OnlineStore: ) +@dataclass +class OnlineStoreConfig: + """Configuration for online store destination.""" + + catalog_name: str + """The Unity Catalog catalog name. This name is also used as the Lakebase logical database name.""" + + schema_name: str + """The Unity Catalog schema name.""" + + table_name_prefix: str + """Prefix for Unity Catalog table name. The materialized feature will be stored in a Lakebase table + with this prefix and a generated postfix.""" + + online_store_name: str + """The name of the target online store.""" + + def as_dict(self) -> dict: + """Serializes the OnlineStoreConfig into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.catalog_name is not None: + body["catalog_name"] = self.catalog_name + if self.online_store_name is not None: + body["online_store_name"] = self.online_store_name + if self.schema_name is not None: + body["schema_name"] = self.schema_name + if self.table_name_prefix is not None: + body["table_name_prefix"] = self.table_name_prefix + return body + + def as_shallow_dict(self) -> dict: + """Serializes the OnlineStoreConfig into a shallow dictionary of its immediate attributes.""" + body = {} + if self.catalog_name is not None: + body["catalog_name"] = self.catalog_name + if self.online_store_name is not None: + body["online_store_name"] = self.online_store_name + if self.schema_name is not None: + body["schema_name"] = self.schema_name + if self.table_name_prefix is not None: + body["table_name_prefix"] = self.table_name_prefix + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> OnlineStoreConfig: + """Deserializes the OnlineStoreConfig from a dictionary.""" + return cls( + catalog_name=d.get("catalog_name", None), + online_store_name=d.get("online_store_name", None), + schema_name=d.get("schema_name", None), + table_name_prefix=d.get("table_name_prefix", None), + ) + + class OnlineStoreState(Enum): AVAILABLE = "AVAILABLE" diff --git a/databricks/sdk/service/pipelines.py b/databricks/sdk/service/pipelines.py index 9ab410419..e038d65bc 100755 --- a/databricks/sdk/service/pipelines.py +++ b/databricks/sdk/service/pipelines.py @@ -607,6 +607,11 @@ class IngestionPipelineDefinition: """Immutable. The Unity Catalog connection that this ingestion pipeline uses to communicate with the source. This is used with connectors for applications like Salesforce, Workday, and so on.""" + ingest_from_uc_foreign_catalog: Optional[bool] = None + """Immutable. If set to true, the pipeline will ingest tables from the UC foreign catalogs directly + without the need to specify a UC connection or ingestion gateway. The `source_catalog` fields in + objects of IngestionConfig are interpreted as the UC foreign catalogs to ingest from.""" + ingestion_gateway_id: Optional[str] = None """Immutable. Identifier for the gateway that is used by this ingestion pipeline to communicate with the source database. This is used with connectors to databases like SQL Server.""" @@ -634,6 +639,8 @@ def as_dict(self) -> dict: body = {} if self.connection_name is not None: body["connection_name"] = self.connection_name + if self.ingest_from_uc_foreign_catalog is not None: + body["ingest_from_uc_foreign_catalog"] = self.ingest_from_uc_foreign_catalog if self.ingestion_gateway_id is not None: body["ingestion_gateway_id"] = self.ingestion_gateway_id if self.netsuite_jar_path is not None: @@ -653,6 +660,8 @@ def as_shallow_dict(self) -> dict: body = {} if self.connection_name is not None: body["connection_name"] = self.connection_name + if self.ingest_from_uc_foreign_catalog is not None: + body["ingest_from_uc_foreign_catalog"] = self.ingest_from_uc_foreign_catalog if self.ingestion_gateway_id is not None: body["ingestion_gateway_id"] = self.ingestion_gateway_id if self.netsuite_jar_path is not None: @@ -672,6 +681,7 @@ def from_dict(cls, d: Dict[str, Any]) -> IngestionPipelineDefinition: """Deserializes the IngestionPipelineDefinition from a dictionary.""" return cls( connection_name=d.get("connection_name", None), + ingest_from_uc_foreign_catalog=d.get("ingest_from_uc_foreign_catalog", None), ingestion_gateway_id=d.get("ingestion_gateway_id", None), netsuite_jar_path=d.get("netsuite_jar_path", None), objects=_repeated_dict(d, "objects", IngestionConfig), diff --git a/databricks/sdk/service/vectorsearch.py b/databricks/sdk/service/vectorsearch.py index a0b731ffa..42a4fee7e 100755 --- a/databricks/sdk/service/vectorsearch.py +++ b/databricks/sdk/service/vectorsearch.py @@ -737,6 +737,153 @@ def from_dict(cls, d: Dict[str, Any]) -> MapStringValueEntry: return cls(key=d.get("key", None), value=_from_dict(d, "value", Value)) +@dataclass +class Metric: + """Metric specification""" + + labels: Optional[List[MetricLabel]] = None + """Metric labels""" + + name: Optional[str] = None + """Metric name""" + + percentile: Optional[float] = None + """Percentile for the metric""" + + def as_dict(self) -> dict: + """Serializes the Metric into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.labels: + body["labels"] = [v.as_dict() for v in self.labels] + if self.name is not None: + body["name"] = self.name + if self.percentile is not None: + body["percentile"] = self.percentile + return body + + def as_shallow_dict(self) -> dict: + """Serializes the Metric into a shallow dictionary of its immediate attributes.""" + body = {} + if self.labels: + body["labels"] = self.labels + if self.name is not None: + body["name"] = self.name + if self.percentile is not None: + body["percentile"] = self.percentile + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> Metric: + """Deserializes the Metric from a dictionary.""" + return cls( + labels=_repeated_dict(d, "labels", MetricLabel), + name=d.get("name", None), + percentile=d.get("percentile", None), + ) + + +@dataclass +class MetricLabel: + """Label for a metric""" + + name: Optional[str] = None + """Label name""" + + value: Optional[str] = None + """Label value""" + + def as_dict(self) -> dict: + """Serializes the MetricLabel into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.name is not None: + body["name"] = self.name + if self.value is not None: + body["value"] = self.value + return body + + def as_shallow_dict(self) -> dict: + """Serializes the MetricLabel into a shallow dictionary of its immediate attributes.""" + body = {} + if self.name is not None: + body["name"] = self.name + if self.value is not None: + body["value"] = self.value + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> MetricLabel: + """Deserializes the MetricLabel from a dictionary.""" + return cls(name=d.get("name", None), value=d.get("value", None)) + + +@dataclass +class MetricValue: + """Single metric value at a specific timestamp""" + + timestamp: Optional[int] = None + """Timestamp of the metric value (milliseconds since epoch)""" + + value: Optional[float] = None + """Metric value""" + + def as_dict(self) -> dict: + """Serializes the MetricValue into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.timestamp is not None: + body["timestamp"] = self.timestamp + if self.value is not None: + body["value"] = self.value + return body + + def as_shallow_dict(self) -> dict: + """Serializes the MetricValue into a shallow dictionary of its immediate attributes.""" + body = {} + if self.timestamp is not None: + body["timestamp"] = self.timestamp + if self.value is not None: + body["value"] = self.value + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> MetricValue: + """Deserializes the MetricValue from a dictionary.""" + return cls(timestamp=d.get("timestamp", None), value=d.get("value", None)) + + +@dataclass +class MetricValues: + """Collection of metric values for a specific metric""" + + metric: Optional[Metric] = None + """Metric specification""" + + values: Optional[List[MetricValue]] = None + """Time series of metric values""" + + def as_dict(self) -> dict: + """Serializes the MetricValues into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.metric: + body["metric"] = self.metric.as_dict() + if self.values: + body["values"] = [v.as_dict() for v in self.values] + return body + + def as_shallow_dict(self) -> dict: + """Serializes the MetricValues into a shallow dictionary of its immediate attributes.""" + body = {} + if self.metric: + body["metric"] = self.metric + if self.values: + body["values"] = self.values + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> MetricValues: + """Deserializes the MetricValues from a dictionary.""" + return cls(metric=_from_dict(d, "metric", Metric), values=_repeated_dict(d, "values", MetricValue)) + + @dataclass class MiniVectorIndex: creator: Optional[str] = None @@ -998,6 +1145,44 @@ def from_dict(cls, d: Dict[str, Any]) -> ResultManifest: return cls(column_count=d.get("column_count", None), columns=_repeated_dict(d, "columns", ColumnInfo)) +@dataclass +class RetrieveUserVisibleMetricsResponse: + """Response containing user-visible metrics""" + + metric_values: Optional[List[MetricValues]] = None + """Collection of metric values""" + + next_page_token: Optional[str] = None + """A token that can be used to get the next page of results. If not present, there are no more + results to show.""" + + def as_dict(self) -> dict: + """Serializes the RetrieveUserVisibleMetricsResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.metric_values: + body["metric_values"] = [v.as_dict() for v in self.metric_values] + 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 RetrieveUserVisibleMetricsResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.metric_values: + body["metric_values"] = self.metric_values + 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]) -> RetrieveUserVisibleMetricsResponse: + """Deserializes the RetrieveUserVisibleMetricsResponse from a dictionary.""" + return cls( + metric_values=_repeated_dict(d, "metric_values", MetricValues), + next_page_token=d.get("next_page_token", None), + ) + + @dataclass class ScanVectorIndexResponse: """Response to a scan vector index request.""" @@ -1519,6 +1704,53 @@ def list_endpoints(self, *, page_token: Optional[str] = None) -> Iterator[Endpoi return query["page_token"] = json["next_page_token"] + def retrieve_user_visible_metrics( + self, + name: str, + *, + end_time: Optional[str] = None, + granularity_in_seconds: Optional[int] = None, + metrics: Optional[List[Metric]] = None, + page_token: Optional[str] = None, + start_time: Optional[str] = None, + ) -> RetrieveUserVisibleMetricsResponse: + """Retrieve user-visible metrics for an endpoint + + :param name: str + Vector search endpoint name + :param end_time: str (optional) + End time for metrics query + :param granularity_in_seconds: int (optional) + Granularity in seconds + :param metrics: List[:class:`Metric`] (optional) + List of metrics to retrieve + :param page_token: str (optional) + Token for pagination + :param start_time: str (optional) + Start time for metrics query + + :returns: :class:`RetrieveUserVisibleMetricsResponse` + """ + + body = {} + if end_time is not None: + body["end_time"] = end_time + if granularity_in_seconds is not None: + body["granularity_in_seconds"] = granularity_in_seconds + if metrics is not None: + body["metrics"] = [v.as_dict() for v in metrics] + if page_token is not None: + body["page_token"] = page_token + if start_time is not None: + body["start_time"] = start_time + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", f"/api/2.0/vector-search/endpoints/{name}/metrics", body=body, headers=headers) + return RetrieveUserVisibleMetricsResponse.from_dict(res) + def update_endpoint_budget_policy( self, endpoint_name: str, budget_policy_id: str ) -> PatchEndpointBudgetPolicyResponse: diff --git a/docs/account/iam/groups_v2.rst b/docs/account/iam/groups_v2.rst index 9a38fb63d..622277161 100644 --- a/docs/account/iam/groups_v2.rst +++ b/docs/account/iam/groups_v2.rst @@ -52,8 +52,9 @@ .. py:method:: list( [, attributes: Optional[str], count: Optional[int], excluded_attributes: Optional[str], filter: Optional[str], sort_by: Optional[str], sort_order: Optional[ListSortOrder], start_index: Optional[int]]) -> Iterator[AccountGroup] Gets all details of the groups associated with the Databricks account. As of 08/22/2025, this endpoint - will not return members. Instead, members should be retrieved by iterating through `Get group - details`. + will no longer return members. Instead, members should be retrieved by iterating through `Get group + details`. Existing accounts that rely on this attribute will not be impacted and will continue + receiving member data as before. :param attributes: str (optional) Comma-separated list of attributes to return in response. diff --git a/docs/account/iam/workspace_assignment.rst b/docs/account/iam/workspace_assignment.rst index 2a8043172..fa9c2ee3e 100644 --- a/docs/account/iam/workspace_assignment.rst +++ b/docs/account/iam/workspace_assignment.rst @@ -74,9 +74,9 @@ spn_id = spn.id - workspace_id = os.environ["TEST_WORKSPACE_ID"] + workspace_id = os.environ["DUMMY_WORKSPACE_ID"] - a.workspace_assignment.update( + _ = a.workspace_assignment.update( workspace_id=workspace_id, principal_id=spn_id, permissions=[iam.WorkspacePermission.USER], diff --git a/docs/account/provisioning/credentials.rst b/docs/account/provisioning/credentials.rst index b71c1707e..d63648d58 100644 --- a/docs/account/provisioning/credentials.rst +++ b/docs/account/provisioning/credentials.rst @@ -24,15 +24,15 @@ a = AccountClient() - creds = a.credentials.create( + role = a.credentials.create( credentials_name=f"sdk-{time.time_ns()}", aws_credentials=provisioning.CreateCredentialAwsCredentials( - sts_role=provisioning.CreateCredentialStsRole(role_arn=os.environ["TEST_LOGDELIVERY_ARN"]) + sts_role=provisioning.CreateCredentialStsRole(role_arn=os.environ["TEST_CROSSACCOUNT_ARN"]) ), ) # cleanup - a.credentials.delete(credentials_id=creds.credentials_id) + a.credentials.delete(credentials_id=role.credentials_id) Creates a Databricks credential configuration that represents cloud cross-account credentials for a specified account. Databricks uses this to set up network infrastructure properly to host Databricks diff --git a/docs/account/provisioning/storage.rst b/docs/account/provisioning/storage.rst index 41a04deb3..b9f080e36 100644 --- a/docs/account/provisioning/storage.rst +++ b/docs/account/provisioning/storage.rst @@ -16,6 +16,7 @@ .. code-block:: + import os import time from databricks.sdk import AccountClient @@ -23,13 +24,13 @@ a = AccountClient() - bucket = a.storage.create( + storage = a.storage.create( storage_configuration_name=f"sdk-{time.time_ns()}", - root_bucket_info=provisioning.RootBucketInfo(bucket_name=f"sdk-{time.time_ns()}"), + root_bucket_info=provisioning.RootBucketInfo(bucket_name=os.environ["TEST_ROOT_BUCKET"]), ) # cleanup - a.storage.delete(storage_configuration_id=bucket.storage_configuration_id) + a.storage.delete(storage_configuration_id=storage.storage_configuration_id) Creates a Databricks storage configuration for an account. diff --git a/docs/dbdataclasses/catalog.rst b/docs/dbdataclasses/catalog.rst index 44209d4b9..9ff55ebcb 100644 --- a/docs/dbdataclasses/catalog.rst +++ b/docs/dbdataclasses/catalog.rst @@ -1500,7 +1500,7 @@ These dataclasses are used in the SDK to represent API requests and responses fo .. py:class:: SecurableKind - Latest kind: CONNECTION_AWS_SECRETS_MANAGER = 270; Next id:271 + Latest kind: CONNECTION_POSTGRESQL_AWS_SERVICE_CRED = 271; Next id:272 .. py:attribute:: TABLE_DB_STORAGE :value: "TABLE_DB_STORAGE" diff --git a/docs/dbdataclasses/dashboards.rst b/docs/dbdataclasses/dashboards.rst index df004c847..a1211ed11 100644 --- a/docs/dbdataclasses/dashboards.rst +++ b/docs/dbdataclasses/dashboards.rst @@ -385,6 +385,13 @@ These dataclasses are used in the SDK to represent API requests and responses fo :members: :undoc-members: +.. py:class:: TextAttachmentPurpose + + Purpose/intent of a text attachment + + .. py:attribute:: FOLLOW_UP_QUESTION + :value: "FOLLOW_UP_QUESTION" + .. autoclass:: TrashDashboardResponse :members: :undoc-members: diff --git a/docs/dbdataclasses/ml.rst b/docs/dbdataclasses/ml.rst index 844e66245..3b514c298 100644 --- a/docs/dbdataclasses/ml.rst +++ b/docs/dbdataclasses/ml.rst @@ -604,6 +604,10 @@ These dataclasses are used in the SDK to represent API requests and responses fo :members: :undoc-members: +.. autoclass:: OnlineStoreConfig + :members: + :undoc-members: + .. py:class:: OnlineStoreState .. py:attribute:: AVAILABLE diff --git a/docs/dbdataclasses/vectorsearch.rst b/docs/dbdataclasses/vectorsearch.rst index b8bd46536..33e37bdd8 100644 --- a/docs/dbdataclasses/vectorsearch.rst +++ b/docs/dbdataclasses/vectorsearch.rst @@ -109,6 +109,22 @@ These dataclasses are used in the SDK to represent API requests and responses fo :members: :undoc-members: +.. autoclass:: Metric + :members: + :undoc-members: + +.. autoclass:: MetricLabel + :members: + :undoc-members: + +.. autoclass:: MetricValue + :members: + :undoc-members: + +.. autoclass:: MetricValues + :members: + :undoc-members: + .. autoclass:: MiniVectorIndex :members: :undoc-members: @@ -147,6 +163,10 @@ These dataclasses are used in the SDK to represent API requests and responses fo :members: :undoc-members: +.. autoclass:: RetrieveUserVisibleMetricsResponse + :members: + :undoc-members: + .. autoclass:: ScanVectorIndexResponse :members: :undoc-members: diff --git a/docs/workspace/catalog/catalogs.rst b/docs/workspace/catalog/catalogs.rst index 17297d8dd..62dfa5e3c 100644 --- a/docs/workspace/catalog/catalogs.rst +++ b/docs/workspace/catalog/catalogs.rst @@ -24,10 +24,10 @@ w = WorkspaceClient() - created_catalog = w.catalogs.create(name=f"sdk-{time.time_ns()}") + created = w.catalogs.create(name=f"sdk-{time.time_ns()}") # cleanup - w.catalogs.delete(name=created_catalog.name, force=True) + w.catalogs.delete(name=created.name, force=True) Creates a new catalog instance in the parent metastore if the caller is a metastore admin or has the **CREATE_CATALOG** privilege. @@ -155,12 +155,13 @@ import time from databricks.sdk import WorkspaceClient + from databricks.sdk.service import catalog w = WorkspaceClient() created = w.catalogs.create(name=f"sdk-{time.time_ns()}") - _ = w.catalogs.update(name=created.name, comment="updated") + _ = w.catalogs.update(name=created.name, isolation_mode=catalog.CatalogIsolationMode.ISOLATED) # cleanup w.catalogs.delete(name=created.name, force=True) diff --git a/docs/workspace/catalog/storage_credentials.rst b/docs/workspace/catalog/storage_credentials.rst index d8111141e..d43446e66 100644 --- a/docs/workspace/catalog/storage_credentials.rst +++ b/docs/workspace/catalog/storage_credentials.rst @@ -30,13 +30,13 @@ w = WorkspaceClient() - credential = w.storage_credentials.create( + created = w.storage_credentials.create( name=f"sdk-{time.time_ns()}", aws_iam_role=catalog.AwsIamRoleRequest(role_arn=os.environ["TEST_METASTORE_DATA_ACCESS_ARN"]), ) # cleanup - w.storage_credentials.delete(name=credential.name) + w.storage_credentials.delete(name=created.name) Creates a new storage credential. diff --git a/docs/workspace/catalog/tables.rst b/docs/workspace/catalog/tables.rst index b33bef940..8de553fc2 100644 --- a/docs/workspace/catalog/tables.rst +++ b/docs/workspace/catalog/tables.rst @@ -156,7 +156,7 @@ created_schema = w.schemas.create(name=f"sdk-{time.time_ns()}", catalog_name=created_catalog.name) - all_tables = w.tables.list(catalog_name=created_catalog.name, schema_name=created_schema.name) + summaries = w.tables.list_summaries(catalog_name=created_catalog.name, schema_name_pattern=created_schema.name) # cleanup w.schemas.delete(full_name=created_schema.full_name) diff --git a/docs/workspace/jobs/jobs.rst b/docs/workspace/jobs/jobs.rst index 0b82986de..c3ff96a4e 100644 --- a/docs/workspace/jobs/jobs.rst +++ b/docs/workspace/jobs/jobs.rst @@ -10,7 +10,7 @@ scalable resources. Your job can consist of a single task or can be a large, multi-task workflow with complex dependencies. Databricks manages the task orchestration, cluster management, monitoring, and error reporting for all of your jobs. You can run your jobs immediately or periodically through an easy-to-use - scheduling system. You can implement job tasks using notebooks, JARS, Delta Live Tables pipelines, or + scheduling system. You can implement job tasks using notebooks, JARS, Spark Declarative Pipelines, or Python, Scala, Spark submit, and Java applications. You should never hard code secrets or store them in plain text. Use the [Secrets CLI] to manage secrets in @@ -188,9 +188,10 @@ as when this job is deleted. :param environments: List[:class:`JobEnvironment`] (optional) A list of task execution environment specifications that can be referenced by serverless tasks of - this job. An environment is required to be present for serverless tasks. For serverless notebook - tasks, the environment is accessible in the notebook environment panel. For other serverless tasks, - the task environment is required to be specified using environment_key in the task settings. + this job. For serverless notebook tasks, if the environment_key is not specified, the notebook + environment will be used if present. If a jobs environment is specified, it will override the + notebook environment. For other serverless tasks, the task environment is required to be specified + using environment_key in the task settings. :param format: :class:`Format` (optional) Used to tell what is the format of the job. This field is ignored in Create/Update/Reset calls. When using the Jobs API 2.1 this value is always set to `"MULTI_TASK"`. @@ -357,23 +358,21 @@ w.clusters.ensure_cluster_is_running(os.environ["DATABRICKS_CLUSTER_ID"]) and os.environ["DATABRICKS_CLUSTER_ID"] ) - created_job = w.jobs.create( - name=f"sdk-{time.time_ns()}", + run = w.jobs.submit( + run_name=f"sdk-{time.time_ns()}", tasks=[ - jobs.Task( - description="test", + jobs.SubmitTask( existing_cluster_id=cluster_id, notebook_task=jobs.NotebookTask(notebook_path=notebook_path), - task_key="test", - timeout_seconds=0, + task_key=f"sdk-{time.time_ns()}", ) ], - ) + ).result() - by_id = w.jobs.get(job_id=created_job.job_id) + output = w.jobs.get_run_output(run_id=run.tasks[0].run_id) # cleanup - w.jobs.delete(job_id=created_job.job_id) + w.jobs.delete_run(run_id=run.run_id) Get a single job. diff --git a/docs/workspace/ml/model_registry.rst b/docs/workspace/ml/model_registry.rst index 98d803a63..c528f4329 100644 --- a/docs/workspace/ml/model_registry.rst +++ b/docs/workspace/ml/model_registry.rst @@ -120,7 +120,7 @@ model = w.model_registry.create_model(name=f"sdk-{time.time_ns()}") - created = w.model_registry.create_model_version(name=model.registered_model.name, source="dbfs:/tmp") + mv = w.model_registry.create_model_version(name=model.registered_model.name, source="dbfs:/tmp") Creates a model version. @@ -734,13 +734,14 @@ w = WorkspaceClient() - created = w.model_registry.create_model(name=f"sdk-{time.time_ns()}") + model = w.model_registry.create_model(name=f"sdk-{time.time_ns()}") - model = w.model_registry.get_model(name=created.registered_model.name) + created = w.model_registry.create_model_version(name=model.registered_model.name, source="dbfs:/tmp") - w.model_registry.update_model( - name=model.registered_model_databricks.name, + w.model_registry.update_model_version( description=f"sdk-{time.time_ns()}", + name=created.model_version.name, + version=created.model_version.version, ) Updates a registered model. diff --git a/docs/workspace/vectorsearch/vector_search_endpoints.rst b/docs/workspace/vectorsearch/vector_search_endpoints.rst index 47a8fa59a..53c0bdd7a 100644 --- a/docs/workspace/vectorsearch/vector_search_endpoints.rst +++ b/docs/workspace/vectorsearch/vector_search_endpoints.rst @@ -55,6 +55,26 @@ :returns: Iterator over :class:`EndpointInfo` + .. py:method:: retrieve_user_visible_metrics(name: str [, end_time: Optional[str], granularity_in_seconds: Optional[int], metrics: Optional[List[Metric]], page_token: Optional[str], start_time: Optional[str]]) -> RetrieveUserVisibleMetricsResponse + + Retrieve user-visible metrics for an endpoint + + :param name: str + Vector search endpoint name + :param end_time: str (optional) + End time for metrics query + :param granularity_in_seconds: int (optional) + Granularity in seconds + :param metrics: List[:class:`Metric`] (optional) + List of metrics to retrieve + :param page_token: str (optional) + Token for pagination + :param start_time: str (optional) + Start time for metrics query + + :returns: :class:`RetrieveUserVisibleMetricsResponse` + + .. py:method:: update_endpoint_budget_policy(endpoint_name: str, budget_policy_id: str) -> PatchEndpointBudgetPolicyResponse Update the budget policy of an endpoint diff --git a/docs/workspace/workspace/workspace.rst b/docs/workspace/workspace/workspace.rst index e1b7d12b9..67867bc6c 100644 --- a/docs/workspace/workspace/workspace.rst +++ b/docs/workspace/workspace/workspace.rst @@ -79,7 +79,7 @@ notebook = f"/Users/{w.current_user.me().user_name}/sdk-{time.time_ns()}" - export_response = w.workspace.export(format=workspace.ExportFormat.SOURCE, path=notebook) + export_response = w.workspace.export_(format=workspace.ExportFormat.SOURCE, path=notebook) Exports an object or the contents of an entire directory. @@ -223,14 +223,16 @@ .. code-block:: + import os + import time + from databricks.sdk import WorkspaceClient w = WorkspaceClient() - names = [] - for i in w.workspace.list(f"/Users/{w.current_user.me().user_name}", recursive=True): - names.append(i.path) - assert len(names) > 0 + notebook = f"/Users/{w.current_user.me().user_name}/sdk-{time.time_ns()}" + + objects = w.workspace.list(path=os.path.dirname(notebook)) List workspace objects diff --git a/tests/databricks/sdk/service/lrotesting.py b/tests/databricks/sdk/service/lrotesting.py index 679118220..bc0374ddc 100755 --- a/tests/databricks/sdk/service/lrotesting.py +++ b/tests/databricks/sdk/service/lrotesting.py @@ -20,11 +20,7 @@ @dataclass class DatabricksServiceExceptionWithDetailsProto: - """Serialization format for DatabricksServiceException with error details. This message doesn't - work for ScalaPB-04 as google.protobuf.Any is only available to ScalaPB-09. Note the definition - of this message should be in sync with DatabricksServiceExceptionProto defined in - /api-base/proto/legacy/databricks.proto except the later one doesn't have the error details - field defined.""" + """Databricks Error that is returned by all Databricks APIs.""" details: Optional[List[dict]] = None """@pbjson-skip""" @@ -174,24 +170,15 @@ class Operation: metadata: Optional[dict] = None """Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such - metadata. Any method that returns a long-running operation should document the metadata type, if - any.""" + metadata.""" name: Optional[str] = None """The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with - `operations/{unique_id}`. - - Note: multi-segment resource names are not yet supported in the RPC framework and SDK/TF. Until - that support is added, `name` must be string without internal `/` separators.""" + `operations/{unique_id}`.""" response: Optional[dict] = None - """The normal, successful response of the operation. If the original method returns no data on - success, such as `Delete`, the response is `google.protobuf.Empty`. If the original method is - standard `Get`/`Create`/`Update`, the response should be the resource. For other methods, the - response should have the type `XxxResponse`, where `Xxx` is the original method name. For - example, if the original method name is `TakeSnapshot()`, the inferred response type is - `TakeSnapshotResponse`.""" + """The normal, successful response of the operation.""" def as_dict(self) -> dict: """Serializes the Operation into a dictionary suitable for use as a JSON request body.""" diff --git a/tests/generated/test_json_marshall.py b/tests/generated/test_json_marshall.py index 16fc6fb26..bf5460f2e 100755 --- a/tests/generated/test_json_marshall.py +++ b/tests/generated/test_json_marshall.py @@ -190,7 +190,7 @@ def _fieldmask(d: str) -> FieldMask: required_string="non_default_string", required_struct={}, required_timestamp=_timestamp("2023-12-31T23:59:59Z"), - required_value=json.loads("{}"), + required_value=json.loads('{"key": "value"}'), test_required_enum=TestEnum.TEST_ENUM_TWO, ), """{ @@ -198,6 +198,7 @@ def _fieldmask(d: str) -> FieldMask: "required_int32": 42, "required_int64": 1234567890123456789, "required_bool": true, + "required_value": {"key": "value"}, "required_message": {}, "test_required_enum": "TEST_ENUM_TWO", "required_duration": "7200s",