From cc83537127e18b3c04ae91758c4d9fd8caf15e26 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Tue, 16 Sep 2025 20:56:38 +0000 Subject: [PATCH 1/3] Update SDK to latest API definition --- .codegen/_openapi_sha | 2 +- .gitattributes | 1 + NEXT_CHANGELOG.md | 101 + databricks/sdk/__init__.py | 112 +- databricks/sdk/service/catalog.py | 10 +- databricks/sdk/service/compute.py | 10 + databricks/sdk/service/dashboards.py | 83 +- databricks/sdk/service/database.py | 62 +- databricks/sdk/service/iam.py | 2982 +++++++++++++++++++++----- databricks/sdk/service/iamv2.py | 643 ++++++ databricks/sdk/service/jobs.py | 17 +- databricks/sdk/service/ml.py | 392 ++++ databricks/sdk/service/oauth2.py | 6 +- databricks/sdk/service/pipelines.py | 105 + databricks/sdk/service/settingsv2.py | 78 +- databricks/sdk/service/sharing.py | 9 + databricks/sdk/service/sql.py | 18 +- databricks/sdk/service/tags.py | 31 +- docs/gen-client-docs.py | 5 + 19 files changed, 4028 insertions(+), 639 deletions(-) create mode 100755 databricks/sdk/service/iamv2.py diff --git a/.codegen/_openapi_sha b/.codegen/_openapi_sha index 8af35ea49..05ebbd8c0 100644 --- a/.codegen/_openapi_sha +++ b/.codegen/_openapi_sha @@ -1 +1 @@ -b95c2c6e21bec9551ec7d7d51ddf2dfe390b4522 \ No newline at end of file +3da28310c39d8ab0067e1c5fecd0707add475a86 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index e26b931e3..e68ce1aca 100755 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,7 @@ databricks/sdk/service/dashboards.py linguist-generated=true databricks/sdk/service/database.py linguist-generated=true databricks/sdk/service/files.py linguist-generated=true databricks/sdk/service/iam.py linguist-generated=true +databricks/sdk/service/iamv2.py linguist-generated=true databricks/sdk/service/jobs.py linguist-generated=true databricks/sdk/service/marketplace.py linguist-generated=true databricks/sdk/service/ml.py linguist-generated=true diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index b9a5380af..802055bbe 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -13,3 +13,104 @@ ### Internal Changes ### API Changes +* Added `databricks.sdk.service.iamv2` package. +* Added [a.account_groups_v2](https://databricks-sdk-py.readthedocs.io/en/latest/account/iam/account_groups_v2.html) account-level service, [a.account_service_principals_v2](https://databricks-sdk-py.readthedocs.io/en/latest/account/iam/account_service_principals_v2.html) account-level service, [a.account_users_v2](https://databricks-sdk-py.readthedocs.io/en/latest/account/iam/account_users_v2.html) account-level service, [w.groups_v2](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/iam/groups_v2.html) workspace-level service, [w.service_principals_v2](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/iam/service_principals_v2.html) workspace-level service and [w.users_v2](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/iam/users_v2.html) workspace-level service. +* Added [a.account_iam_v2](https://databricks-sdk-py.readthedocs.io/en/latest/account/iamv2/account_iam_v2.html) account-level service and [w.workspace_iam_v2](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/iamv2/workspace_iam_v2.html) workspace-level service. +* Added [w.feature_engineering](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/ml/feature_engineering.html) workspace-level service. +* Added `java_dependencies` field for `databricks.sdk.service.compute.Environment`. +* Added `followup_questions` field for `databricks.sdk.service.dashboards.GenieAttachment`. +* Added `feedback` field for `databricks.sdk.service.dashboards.GenieMessage`. +* Added `effective_capacity` field for `databricks.sdk.service.database.DatabaseInstance`. +* Added `disabled` field for `databricks.sdk.service.jobs.Task`. +* Added `netsuite_jar_path` field for `databricks.sdk.service.pipelines.IngestionPipelineDefinition`. +* Added `workday_report_parameters` field for `databricks.sdk.service.pipelines.TableSpecificConfig`. +* Added `auxiliary_managed_location` field for `databricks.sdk.service.sharing.TableInternalAttributes`. +* Added `alerts` field for `databricks.sdk.service.sql.ListAlertsV2Response`. +* Added `create_time` and `update_time` fields for `databricks.sdk.service.tags.TagPolicy`. +* Added `table_delta_uniform_iceberg_foreign_deltasharing` enum value for `databricks.sdk.service.catalog.SecurableKind`. +* Added `no_activated_k8s` and `usage_policy_entitlement_denied` enum values for `databricks.sdk.service.compute.TerminationReasonCode`. +* Added `internal_catalog_path_overlap_exception` and `internal_catalog_missing_uc_path_exception` enum values for `databricks.sdk.service.dashboards.MessageErrorType`. +* Added `foreign_catalog` enum value for `databricks.sdk.service.pipelines.IngestionSourceType`. +* Added `foreign_iceberg_table` enum value for `databricks.sdk.service.sharing.TableInternalAttributesSharedTableType`. +* [Breaking] Changed `creation_time` field for `databricks.sdk.service.agentbricks.CustomLlm` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.agentbricks.UpdateCustomLlmRequest` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.apps.App` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.apps.AppDeployment` to type `str` dataclass. +* [Breaking] Changed `timestamp` field for `databricks.sdk.service.catalog.ContinuousUpdateStatus` to type `str` dataclass. +* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageExternalMetadataInfo` to type `str` dataclass. +* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageFileInfo` to type `str` dataclass. +* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageModelVersionInfo` to type `str` dataclass. +* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageTableInfo` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.catalog.ExternalMetadata` to type `str` dataclass. +* [Breaking] Changed `timestamp` field for `databricks.sdk.service.catalog.FailedStatus` to type `str` dataclass. +* [Breaking] Changed `timestamp` field for `databricks.sdk.service.catalog.TriggeredUpdateStatus` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateAccessRequestDestinationsRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateEntityTagAssignmentRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateExternalLineageRelationshipRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateExternalMetadataRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdatePolicyRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.compute.UpdateCluster` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.dashboards.Dashboard` to type `str` dataclass. +* [Breaking] Changed `revision_create_time` field for `databricks.sdk.service.dashboards.PublishedDashboard` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.dashboards.Schedule` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.dashboards.Subscription` to type `str` dataclass. +* [Breaking] Changed `expiration_time` field for `databricks.sdk.service.database.DatabaseCredential` to type `str` dataclass. +* [Breaking] Changed `creation_time` field for `databricks.sdk.service.database.DatabaseInstance` to type `str` dataclass. +* [Breaking] Changed `branch_time` field for `databricks.sdk.service.database.DatabaseInstanceRef` to type `str` dataclass. +* [Breaking] Changed `delta_commit_timestamp` field for `databricks.sdk.service.database.DeltaTableSyncInfo` to type `str` dataclass. +* [Breaking] Changed `timestamp` field for `databricks.sdk.service.database.SyncedTableContinuousUpdateStatus` to type `str` dataclass. +* [Breaking] Changed `timestamp` field for `databricks.sdk.service.database.SyncedTableFailedStatus` to type `str` dataclass. +* [Breaking] Changed `sync_end_timestamp` and `sync_start_timestamp` fields for `databricks.sdk.service.database.SyncedTablePosition` to type `str` dataclass. +* [Breaking] Changed `timestamp` field for `databricks.sdk.service.database.SyncedTableTriggeredUpdateStatus` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.database.UpdateDatabaseCatalogRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.database.UpdateDatabaseInstanceRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.database.UpdateSyncedDatabaseTableRequest` to type `str` dataclass. +* [Breaking] Changed `creation_time` field for `databricks.sdk.service.ml.OnlineStore` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.ml.UpdateFeatureTagRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.ml.UpdateOnlineStoreRequest` to type `str` dataclass. +* [Breaking] Changed `lifetime` field for `databricks.sdk.service.oauth2.CreateServicePrincipalSecretRequest` to type `str` dataclass. +* [Breaking] Changed `expire_time` field for `databricks.sdk.service.oauth2.CreateServicePrincipalSecretResponse` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.oauth2.FederationPolicy` to type `str` dataclass. +* [Breaking] Changed `expire_time` field for `databricks.sdk.service.oauth2.SecretInfo` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.oauth2.UpdateAccountFederationPolicyRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.oauth2.UpdateServicePrincipalFederationPolicyRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAccountIpAccessEnableRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAibiDashboardEmbeddingAccessPolicySettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAibiDashboardEmbeddingApprovedDomainsSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAutomaticClusterUpdateSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateComplianceSecurityProfileSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateCspEnablementAccountSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDashboardEmailSubscriptionsRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDefaultNamespaceSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDefaultWarehouseIdRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDisableLegacyAccessRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDisableLegacyDbfsRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDisableLegacyFeaturesRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnableExportNotebookRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnableNotebookTableClipboardRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnableResultsDownloadingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnhancedSecurityMonitoringSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEsmEnablementAccountSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateLlmProxyPartnerPoweredAccountRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateLlmProxyPartnerPoweredEnforceRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateLlmProxyPartnerPoweredWorkspaceRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.settings.UpdateNccPrivateEndpointRuleRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdatePersonalComputeSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateRestrictWorkspaceAdminsSettingRequest` to type `str` dataclass. +* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateSqlResultsDownloadRequest` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sharing.FederationPolicy` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sharing.UpdateFederationPolicyRequest` to type `str` dataclass. +* [Breaking] Changed `create_time`, `trigger_time` and `update_time` fields for `databricks.sdk.service.sql.Alert` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.AlertV2` to type `str` dataclass. +* [Breaking] Changed `last_evaluated_at` field for `databricks.sdk.service.sql.AlertV2Evaluation` to type `str` dataclass. +* [Breaking] Changed `create_time`, `trigger_time` and `update_time` fields for `databricks.sdk.service.sql.ListAlertsResponseAlert` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.ListQueryObjectsResponseQuery` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.Query` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateAlertRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateAlertV2Request` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateQueryRequest` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateVisualizationRequest` to type `str` dataclass. +* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.Visualization` to type `str` dataclass. +* [Breaking] Changed `update_mask` field for `databricks.sdk.service.tags.UpdateTagPolicyRequest` to type `str` dataclass. +* [Breaking] Removed `disabled` field for `databricks.sdk.service.jobs.RunTask`. +* [Breaking] Removed `default_data_security_mode` and `effective_default_data_security_mode` fields for `databricks.sdk.service.settingsv2.Setting`. diff --git a/databricks/sdk/__init__.py b/databricks/sdk/__init__.py index a426eebfb..ef42d1c34 100755 --- a/databricks/sdk/__init__.py +++ b/databricks/sdk/__init__.py @@ -23,6 +23,7 @@ from databricks.sdk.service import database as pkg_database from databricks.sdk.service import files as pkg_files from databricks.sdk.service import iam as pkg_iam +from databricks.sdk.service import iamv2 as pkg_iamv2 from databricks.sdk.service import jobs as pkg_jobs from databricks.sdk.service import marketplace as pkg_marketplace from databricks.sdk.service import ml as pkg_ml @@ -82,12 +83,16 @@ from databricks.sdk.service.iam import (AccessControlAPI, AccountAccessControlAPI, AccountAccessControlProxyAPI, - AccountGroupsAPI, + AccountGroupsAPI, AccountGroupsV2API, AccountServicePrincipalsAPI, - AccountUsersAPI, CurrentUserAPI, - GroupsAPI, PermissionMigrationAPI, - PermissionsAPI, ServicePrincipalsAPI, - UsersAPI, WorkspaceAssignmentAPI) + AccountServicePrincipalsV2API, + AccountUsersAPI, AccountUsersV2API, + CurrentUserAPI, GroupsAPI, GroupsV2API, + PermissionMigrationAPI, PermissionsAPI, + ServicePrincipalsAPI, + ServicePrincipalsV2API, UsersAPI, + UsersV2API, WorkspaceAssignmentAPI) +from databricks.sdk.service.iamv2 import AccountIamV2API, WorkspaceIamV2API from databricks.sdk.service.jobs import JobsAPI, PolicyComplianceForJobsAPI from databricks.sdk.service.marketplace import ( ConsumerFulfillmentsAPI, ConsumerInstallationsAPI, ConsumerListingsAPI, @@ -95,8 +100,9 @@ ProviderExchangeFiltersAPI, ProviderExchangesAPI, ProviderFilesAPI, ProviderListingsAPI, ProviderPersonalizationRequestsAPI, ProviderProviderAnalyticsDashboardsAPI, ProviderProvidersAPI) -from databricks.sdk.service.ml import (ExperimentsAPI, FeatureStoreAPI, - ForecastingAPI, MaterializedFeaturesAPI, +from databricks.sdk.service.ml import (ExperimentsAPI, FeatureEngineeringAPI, + FeatureStoreAPI, ForecastingAPI, + MaterializedFeaturesAPI, ModelRegistryAPI) from databricks.sdk.service.oauth2 import (AccountFederationPolicyAPI, CustomAppIntegrationAPI, @@ -285,6 +291,7 @@ def __init__( self._external_lineage = pkg_catalog.ExternalLineageAPI(self._api_client) self._external_locations = pkg_catalog.ExternalLocationsAPI(self._api_client) self._external_metadata = pkg_catalog.ExternalMetadataAPI(self._api_client) + self._feature_engineering = pkg_ml.FeatureEngineeringAPI(self._api_client) self._feature_store = pkg_ml.FeatureStoreAPI(self._api_client) self._files = _make_files_client(self._api_client, self._config) self._functions = pkg_catalog.FunctionsAPI(self._api_client) @@ -292,7 +299,7 @@ def __init__( self._git_credentials = pkg_workspace.GitCredentialsAPI(self._api_client) self._global_init_scripts = pkg_compute.GlobalInitScriptsAPI(self._api_client) self._grants = pkg_catalog.GrantsAPI(self._api_client) - self._groups = pkg_iam.GroupsAPI(self._api_client) + self._groups_v2 = pkg_iam.GroupsV2API(self._api_client) self._instance_pools = pkg_compute.InstancePoolsAPI(self._api_client) self._instance_profiles = pkg_compute.InstanceProfilesAPI(self._api_client) self._ip_access_lists = pkg_settings.IpAccessListsAPI(self._api_client) @@ -341,7 +348,7 @@ def __init__( self._schemas = pkg_catalog.SchemasAPI(self._api_client) self._secrets = pkg_workspace.SecretsAPI(self._api_client) self._service_principal_secrets_proxy = pkg_oauth2.ServicePrincipalSecretsProxyAPI(self._api_client) - self._service_principals = pkg_iam.ServicePrincipalsAPI(self._api_client) + self._service_principals_v2 = pkg_iam.ServicePrincipalsV2API(self._api_client) self._serving_endpoints = serving_endpoints serving_endpoints_data_plane_token_source = DataPlaneTokenSource( self._config.host, self._config.oauth_token, self._config.disable_async_token_refresh @@ -361,7 +368,7 @@ def __init__( self._temporary_table_credentials = pkg_catalog.TemporaryTableCredentialsAPI(self._api_client) self._token_management = pkg_settings.TokenManagementAPI(self._api_client) self._tokens = pkg_settings.TokensAPI(self._api_client) - self._users = pkg_iam.UsersAPI(self._api_client) + self._users_v2 = pkg_iam.UsersV2API(self._api_client) self._vector_search_endpoints = pkg_vectorsearch.VectorSearchEndpointsAPI(self._api_client) self._vector_search_indexes = pkg_vectorsearch.VectorSearchIndexesAPI(self._api_client) self._volumes = pkg_catalog.VolumesAPI(self._api_client) @@ -371,6 +378,10 @@ def __init__( self._workspace_conf = pkg_settings.WorkspaceConfAPI(self._api_client) self._workspace_settings_v2 = pkg_settingsv2.WorkspaceSettingsV2API(self._api_client) self._forecasting = pkg_ml.ForecastingAPI(self._api_client) + self._workspace_iam_v2 = pkg_iamv2.WorkspaceIamV2API(self._api_client) + self._groups = pkg_iam.GroupsAPI(self._api_client) + self._service_principals = pkg_iam.ServicePrincipalsAPI(self._api_client) + self._users = pkg_iam.UsersAPI(self._api_client) @property def config(self) -> client.Config: @@ -574,6 +585,11 @@ def external_metadata(self) -> pkg_catalog.ExternalMetadataAPI: """External Metadata objects enable customers to register and manage metadata about external systems within Unity Catalog.""" return self._external_metadata + @property + def feature_engineering(self) -> pkg_ml.FeatureEngineeringAPI: + """[description].""" + return self._feature_engineering + @property def feature_store(self) -> pkg_ml.FeatureStoreAPI: """A feature store is a centralized repository that enables data scientists to find and share features.""" @@ -610,9 +626,9 @@ def grants(self) -> pkg_catalog.GrantsAPI: return self._grants @property - def groups(self) -> pkg_iam.GroupsAPI: + def groups_v2(self) -> pkg_iam.GroupsV2API: """Groups simplify identity management, making it easier to assign access to Databricks workspace, data, and other securable objects.""" - return self._groups + return self._groups_v2 @property def instance_pools(self) -> pkg_compute.InstancePoolsAPI: @@ -845,9 +861,9 @@ def service_principal_secrets_proxy(self) -> pkg_oauth2.ServicePrincipalSecretsP return self._service_principal_secrets_proxy @property - def service_principals(self) -> pkg_iam.ServicePrincipalsAPI: + def service_principals_v2(self) -> pkg_iam.ServicePrincipalsV2API: """Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms.""" - return self._service_principals + return self._service_principals_v2 @property def serving_endpoints(self) -> ServingEndpointsExt: @@ -896,7 +912,7 @@ def tables(self) -> pkg_catalog.TablesAPI: @property def tag_policies(self) -> pkg_tags.TagPoliciesAPI: - """The Tag Policy API allows you to manage tag policies in Databricks.""" + """The Tag Policy API allows you to manage policies for governed tags in Databricks.""" return self._tag_policies @property @@ -920,9 +936,9 @@ def tokens(self) -> pkg_settings.TokensAPI: return self._tokens @property - def users(self) -> pkg_iam.UsersAPI: + def users_v2(self) -> pkg_iam.UsersV2API: """User identities recognized by Databricks and represented by email addresses.""" - return self._users + return self._users_v2 @property def vector_search_endpoints(self) -> pkg_vectorsearch.VectorSearchEndpointsAPI: @@ -969,6 +985,26 @@ def forecasting(self) -> pkg_ml.ForecastingAPI: """The Forecasting API allows you to create and get serverless forecasting experiments.""" return self._forecasting + @property + def workspace_iam_v2(self) -> pkg_iamv2.WorkspaceIamV2API: + """These APIs are used to manage identities and the workspace access of these identities in .""" + return self._workspace_iam_v2 + + @property + def groups(self) -> pkg_iam.GroupsAPI: + """Groups simplify identity management, making it easier to assign access to Databricks workspace, data, and other securable objects.""" + return self._groups + + @property + def service_principals(self) -> pkg_iam.ServicePrincipalsAPI: + """Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms.""" + return self._service_principals + + @property + def users(self) -> pkg_iam.UsersAPI: + """User identities recognized by Databricks and represented by email addresses.""" + return self._users + def get_workspace_id(self) -> int: """Get the workspace ID of the workspace that this client is connected to.""" response = self._api_client.do("GET", "/api/2.0/preview/scim/v2/Me", response_headers=["X-Databricks-Org-Id"]) @@ -1050,7 +1086,7 @@ def __init__( self._custom_app_integration = pkg_oauth2.CustomAppIntegrationAPI(self._api_client) self._encryption_keys = pkg_provisioning.EncryptionKeysAPI(self._api_client) self._federation_policy = pkg_oauth2.AccountFederationPolicyAPI(self._api_client) - self._groups = pkg_iam.AccountGroupsAPI(self._api_client) + self._groups_v2 = pkg_iam.AccountGroupsV2API(self._api_client) self._ip_access_lists = pkg_settings.AccountIpAccessListsAPI(self._api_client) self._log_delivery = pkg_billing.LogDeliveryAPI(self._api_client) self._metastore_assignments = pkg_catalog.AccountMetastoreAssignmentsAPI(self._api_client) @@ -1063,18 +1099,22 @@ def __init__( self._published_app_integration = pkg_oauth2.PublishedAppIntegrationAPI(self._api_client) self._service_principal_federation_policy = pkg_oauth2.ServicePrincipalFederationPolicyAPI(self._api_client) self._service_principal_secrets = pkg_oauth2.ServicePrincipalSecretsAPI(self._api_client) - self._service_principals = pkg_iam.AccountServicePrincipalsAPI(self._api_client) + self._service_principals_v2 = pkg_iam.AccountServicePrincipalsV2API(self._api_client) self._settings = pkg_settings.AccountSettingsAPI(self._api_client) self._settings_v2 = pkg_settingsv2.AccountSettingsV2API(self._api_client) self._storage = pkg_provisioning.StorageAPI(self._api_client) self._storage_credentials = pkg_catalog.AccountStorageCredentialsAPI(self._api_client) self._usage_dashboards = pkg_billing.UsageDashboardsAPI(self._api_client) - self._users = pkg_iam.AccountUsersAPI(self._api_client) + self._users_v2 = pkg_iam.AccountUsersV2API(self._api_client) self._vpc_endpoints = pkg_provisioning.VpcEndpointsAPI(self._api_client) self._workspace_assignment = pkg_iam.WorkspaceAssignmentAPI(self._api_client) self._workspace_network_configuration = pkg_settings.WorkspaceNetworkConfigurationAPI(self._api_client) self._workspaces = pkg_provisioning.WorkspacesAPI(self._api_client) + self._iam_v2 = pkg_iamv2.AccountIamV2API(self._api_client) self._budgets = pkg_billing.BudgetsAPI(self._api_client) + self._groups = pkg_iam.AccountGroupsAPI(self._api_client) + self._service_principals = pkg_iam.AccountServicePrincipalsAPI(self._api_client) + self._users = pkg_iam.AccountUsersAPI(self._api_client) @property def config(self) -> client.Config: @@ -1120,9 +1160,9 @@ def federation_policy(self) -> pkg_oauth2.AccountFederationPolicyAPI: return self._federation_policy @property - def groups(self) -> pkg_iam.AccountGroupsAPI: + def groups_v2(self) -> pkg_iam.AccountGroupsV2API: """Groups simplify identity management, making it easier to assign access to Databricks account, data, and other securable objects.""" - return self._groups + return self._groups_v2 @property def ip_access_lists(self) -> pkg_settings.AccountIpAccessListsAPI: @@ -1185,9 +1225,9 @@ def service_principal_secrets(self) -> pkg_oauth2.ServicePrincipalSecretsAPI: return self._service_principal_secrets @property - def service_principals(self) -> pkg_iam.AccountServicePrincipalsAPI: + def service_principals_v2(self) -> pkg_iam.AccountServicePrincipalsV2API: """Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms.""" - return self._service_principals + return self._service_principals_v2 @property def settings(self) -> pkg_settings.AccountSettingsAPI: @@ -1215,9 +1255,9 @@ def usage_dashboards(self) -> pkg_billing.UsageDashboardsAPI: return self._usage_dashboards @property - def users(self) -> pkg_iam.AccountUsersAPI: + def users_v2(self) -> pkg_iam.AccountUsersV2API: """User identities recognized by Databricks and represented by email addresses.""" - return self._users + return self._users_v2 @property def vpc_endpoints(self) -> pkg_provisioning.VpcEndpointsAPI: @@ -1239,11 +1279,31 @@ def workspaces(self) -> pkg_provisioning.WorkspacesAPI: """These APIs manage workspaces for this account.""" return self._workspaces + @property + def iam_v2(self) -> pkg_iamv2.AccountIamV2API: + """These APIs are used to manage identities and the workspace access of these identities in .""" + return self._iam_v2 + @property def budgets(self) -> pkg_billing.BudgetsAPI: """These APIs manage budget configurations for this account.""" return self._budgets + @property + def groups(self) -> pkg_iam.AccountGroupsAPI: + """Groups simplify identity management, making it easier to assign access to Databricks account, data, and other securable objects.""" + return self._groups + + @property + def service_principals(self) -> pkg_iam.AccountServicePrincipalsAPI: + """Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms.""" + return self._service_principals + + @property + def users(self) -> pkg_iam.AccountUsersAPI: + """User identities recognized by Databricks and represented by email addresses.""" + return self._users + def get_workspace_client(self, workspace: Workspace) -> WorkspaceClient: """Constructs a ``WorkspaceClient`` for the given workspace. diff --git a/databricks/sdk/service/catalog.py b/databricks/sdk/service/catalog.py index 3db28a23e..c05285d67 100755 --- a/databricks/sdk/service/catalog.py +++ b/databricks/sdk/service/catalog.py @@ -3652,7 +3652,8 @@ class ExternalLocationInfo: sufficient.""" file_event_queue: Optional[FileEventQueue] = None - """File event queue settings.""" + """File event queue settings. If `enable_file_events` is `true`, must be defined and have exactly + one of the documented properties.""" isolation_mode: Optional[IsolationMode] = None @@ -8549,6 +8550,7 @@ class SecurableKind(Enum): TABLE_DELTA_ICEBERG_MANAGED = "TABLE_DELTA_ICEBERG_MANAGED" TABLE_DELTA_UNIFORM_HUDI_EXTERNAL = "TABLE_DELTA_UNIFORM_HUDI_EXTERNAL" TABLE_DELTA_UNIFORM_ICEBERG_EXTERNAL = "TABLE_DELTA_UNIFORM_ICEBERG_EXTERNAL" + TABLE_DELTA_UNIFORM_ICEBERG_FOREIGN_DELTASHARING = "TABLE_DELTA_UNIFORM_ICEBERG_FOREIGN_DELTASHARING" TABLE_DELTA_UNIFORM_ICEBERG_FOREIGN_HIVE_METASTORE_EXTERNAL = ( "TABLE_DELTA_UNIFORM_ICEBERG_FOREIGN_HIVE_METASTORE_EXTERNAL" ) @@ -11945,7 +11947,8 @@ def create( enabled, the access to the location falls back to cluster credentials if UC credentials are not sufficient. :param file_event_queue: :class:`FileEventQueue` (optional) - File event queue settings. + File event queue settings. If `enable_file_events` is `true`, must be defined and have exactly one + of the documented properties. :param read_only: bool (optional) Indicates whether the external location is read-only. :param skip_validation: bool (optional) @@ -12107,7 +12110,8 @@ def update( enabled, the access to the location falls back to cluster credentials if UC credentials are not sufficient. :param file_event_queue: :class:`FileEventQueue` (optional) - File event queue settings. + File event queue settings. If `enable_file_events` is `true`, must be defined and have exactly one + of the documented properties. :param force: bool (optional) Force update even if changing url invalidates dependent external tables or mounts. :param isolation_mode: :class:`IsolationMode` (optional) diff --git a/databricks/sdk/service/compute.py b/databricks/sdk/service/compute.py index c7ca04416..8dcf75ee8 100755 --- a/databricks/sdk/service/compute.py +++ b/databricks/sdk/service/compute.py @@ -3136,6 +3136,9 @@ class Environment: version and a set of Python packages. The version is a string, consisting of an integer.""" jar_dependencies: Optional[List[str]] = None + """Use `java_dependencies` instead.""" + + java_dependencies: Optional[List[str]] = None """List of jar dependencies, should be string representing volume paths. For example: `/Volumes/path/to/test.jar`.""" @@ -3150,6 +3153,8 @@ def as_dict(self) -> dict: body["environment_version"] = self.environment_version if self.jar_dependencies: body["jar_dependencies"] = [v for v in self.jar_dependencies] + if self.java_dependencies: + body["java_dependencies"] = [v for v in self.java_dependencies] return body def as_shallow_dict(self) -> dict: @@ -3163,6 +3168,8 @@ def as_shallow_dict(self) -> dict: body["environment_version"] = self.environment_version if self.jar_dependencies: body["jar_dependencies"] = self.jar_dependencies + if self.java_dependencies: + body["java_dependencies"] = self.java_dependencies return body @classmethod @@ -3173,6 +3180,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Environment: dependencies=d.get("dependencies", None), environment_version=d.get("environment_version", None), jar_dependencies=d.get("jar_dependencies", None), + java_dependencies=d.get("java_dependencies", None), ) @@ -7151,6 +7159,7 @@ class TerminationReasonCode(Enum): NETWORK_CHECK_STORAGE_FAILURE = "NETWORK_CHECK_STORAGE_FAILURE" NETWORK_CONFIGURATION_FAILURE = "NETWORK_CONFIGURATION_FAILURE" NFS_MOUNT_FAILURE = "NFS_MOUNT_FAILURE" + NO_ACTIVATED_K8S = "NO_ACTIVATED_K8S" NO_MATCHED_K8S = "NO_MATCHED_K8S" NO_MATCHED_K8S_TESTING_TAG = "NO_MATCHED_K8S_TESTING_TAG" NPIP_TUNNEL_SETUP_FAILURE = "NPIP_TUNNEL_SETUP_FAILURE" @@ -7189,6 +7198,7 @@ class TerminationReasonCode(Enum): UNKNOWN = "UNKNOWN" UNSUPPORTED_INSTANCE_TYPE = "UNSUPPORTED_INSTANCE_TYPE" UPDATE_INSTANCE_PROFILE_FAILURE = "UPDATE_INSTANCE_PROFILE_FAILURE" + USAGE_POLICY_ENTITLEMENT_DENIED = "USAGE_POLICY_ENTITLEMENT_DENIED" USER_INITIATED_VM_TERMINATION = "USER_INITIATED_VM_TERMINATION" USER_REQUEST = "USER_REQUEST" WORKER_SETUP_FAILURE = "WORKER_SETUP_FAILURE" diff --git a/databricks/sdk/service/dashboards.py b/databricks/sdk/service/dashboards.py index b71f2c866..7bd8caf6b 100755 --- a/databricks/sdk/service/dashboards.py +++ b/databricks/sdk/service/dashboards.py @@ -260,6 +260,9 @@ class GenieAttachment: attachment_id: Optional[str] = None """Attachment ID""" + followup_questions: Optional[GenieFollowupQuestionsAttachment] = None + """Follow-up questions suggested by Genie""" + query: Optional[GenieQueryAttachment] = None """Query Attachment if Genie responds with a SQL query""" @@ -271,6 +274,8 @@ def as_dict(self) -> dict: body = {} if self.attachment_id is not None: body["attachment_id"] = self.attachment_id + if self.followup_questions: + body["followup_questions"] = self.followup_questions.as_dict() if self.query: body["query"] = self.query.as_dict() if self.text: @@ -282,6 +287,8 @@ def as_shallow_dict(self) -> dict: body = {} if self.attachment_id is not None: body["attachment_id"] = self.attachment_id + if self.followup_questions: + body["followup_questions"] = self.followup_questions if self.query: body["query"] = self.query if self.text: @@ -293,6 +300,7 @@ def from_dict(cls, d: Dict[str, Any]) -> GenieAttachment: """Deserializes the GenieAttachment from a dictionary.""" return cls( attachment_id=d.get("attachment_id", None), + followup_questions=_from_dict(d, "followup_questions", GenieFollowupQuestionsAttachment), query=_from_dict(d, "query", GenieQueryAttachment), text=_from_dict(d, "text", TextAttachment), ) @@ -413,6 +421,40 @@ def from_dict(cls, d: Dict[str, Any]) -> GenieConversationSummary: ) +@dataclass +class GenieFeedback: + """Feedback containing rating and optional comment""" + + comment: Optional[str] = None + """Optional feedback comment text""" + + 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.comment is not None: + body["comment"] = self.comment + 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.comment is not None: + body["comment"] = self.comment + 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(comment=d.get("comment", None), rating=_enum(d, "rating", GenieFeedbackRating)) + + class GenieFeedbackRating(Enum): """Feedback rating for Genie messages""" @@ -421,6 +463,33 @@ class GenieFeedbackRating(Enum): POSITIVE = "POSITIVE" +@dataclass +class GenieFollowupQuestionsAttachment: + """Follow-up questions suggested by Genie""" + + questions: Optional[List[str]] = None + """The suggested follow-up questions""" + + def as_dict(self) -> dict: + """Serializes the GenieFollowupQuestionsAttachment 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 GenieFollowupQuestionsAttachment 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]) -> GenieFollowupQuestionsAttachment: + """Deserializes the GenieFollowupQuestionsAttachment from a dictionary.""" + return cls(questions=d.get("questions", None)) + + @dataclass class GenieGetMessageQueryResultResponse: statement_response: Optional[sql.StatementResponse] = None @@ -572,6 +641,9 @@ class GenieMessage: 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""" + last_updated_timestamp: Optional[int] = None """Timestamp when the message was last updated""" @@ -597,6 +669,8 @@ def as_dict(self) -> dict: 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: @@ -626,6 +700,8 @@ def as_shallow_dict(self) -> dict: 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: @@ -651,6 +727,7 @@ def from_dict(cls, d: Dict[str, Any]) -> GenieMessage: 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), @@ -1063,6 +1140,8 @@ class MessageErrorType(Enum): 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_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_ARGUMENTS_JSON_EXCEPTION = "INVALID_CHAT_COMPLETION_ARGUMENTS_JSON_EXCEPTION" @@ -1921,8 +2000,8 @@ def list_conversations( :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 "Can Manage" permission on the - space. + 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) diff --git a/databricks/sdk/service/database.py b/databricks/sdk/service/database.py index 01c65349f..aac36ec0e 100755 --- a/databricks/sdk/service/database.py +++ b/databricks/sdk/service/database.py @@ -125,48 +125,36 @@ class DatabaseInstance: creator: Optional[str] = None """The email of the creator of the instance.""" + effective_capacity: Optional[str] = None + """Deprecated. The sku of the instance; this field will always match the value of capacity.""" + effective_enable_pg_native_login: Optional[bool] = None - """xref AIP-129. `enable_pg_native_login` is owned by the client, while - `effective_enable_pg_native_login` is owned by the server. `enable_pg_native_login` will only be - set in Create/Update response messages if and only if the user provides the field via the - request. `effective_enable_pg_native_login` on the other hand will always bet set in all - response messages (Create/Update/Get/List).""" + """Whether the instance has PG native password login enabled.""" effective_enable_readable_secondaries: Optional[bool] = None - """xref AIP-129. `enable_readable_secondaries` is owned by the client, while - `effective_enable_readable_secondaries` is owned by the server. `enable_readable_secondaries` - will only be set in Create/Update response messages if and only if the user provides the field - via the request. `effective_enable_readable_secondaries` on the other hand will always bet set - in all response messages (Create/Update/Get/List).""" + """Whether secondaries serving read-only traffic are enabled. Defaults to false.""" effective_node_count: Optional[int] = None - """xref AIP-129. `node_count` is owned by the client, while `effective_node_count` is owned by the - server. `node_count` will only be set in Create/Update response messages if and only if the user - provides the field via the request. `effective_node_count` on the other hand will always bet set - in all response messages (Create/Update/Get/List).""" + """The number of nodes in the instance, composed of 1 primary and 0 or more secondaries. Defaults + to 1 primary and 0 secondaries.""" effective_retention_window_in_days: Optional[int] = None - """xref AIP-129. `retention_window_in_days` is owned by the client, while - `effective_retention_window_in_days` is owned by the server. `retention_window_in_days` will - only be set in Create/Update response messages if and only if the user provides the field via - the request. `effective_retention_window_in_days` on the other hand will always bet set in all - response messages (Create/Update/Get/List).""" + """The retention window for the instance. This is the time window in days for which the historical + data is retained.""" effective_stopped: Optional[bool] = None - """xref AIP-129. `stopped` is owned by the client, while `effective_stopped` is owned by the - server. `stopped` will only be set in Create/Update response messages if and only if the user - provides the field via the request. `effective_stopped` on the other hand will always bet set in - all response messages (Create/Update/Get/List).""" + """Whether the instance is stopped.""" enable_pg_native_login: Optional[bool] = None - """Whether the instance has PG native password login enabled. Defaults to true.""" + """Whether to enable PG native password login on the instance. Defaults to false.""" enable_readable_secondaries: Optional[bool] = None """Whether to enable secondaries to serve read-only traffic. Defaults to false.""" node_count: Optional[int] = None """The number of nodes in the instance, composed of 1 primary and 0 or more secondaries. Defaults - to 1 primary and 0 secondaries.""" + to 1 primary and 0 secondaries. This field is input only, see effective_node_count for the + output.""" parent_instance_ref: Optional[DatabaseInstanceRef] = None """The ref of the parent instance. This is only available if the instance is child instance. Input: @@ -191,7 +179,7 @@ class DatabaseInstance: """The current state of the instance.""" stopped: Optional[bool] = None - """Whether the instance is stopped.""" + """Whether to stop the instance. An input only param, see effective_stopped for the output.""" uid: Optional[str] = None """An immutable UUID identifier for the instance.""" @@ -207,6 +195,8 @@ def as_dict(self) -> dict: body["creation_time"] = self.creation_time if self.creator is not None: body["creator"] = self.creator + if self.effective_capacity is not None: + body["effective_capacity"] = self.effective_capacity if self.effective_enable_pg_native_login is not None: body["effective_enable_pg_native_login"] = self.effective_enable_pg_native_login if self.effective_enable_readable_secondaries is not None: @@ -254,6 +244,8 @@ def as_shallow_dict(self) -> dict: body["creation_time"] = self.creation_time if self.creator is not None: body["creator"] = self.creator + if self.effective_capacity is not None: + body["effective_capacity"] = self.effective_capacity if self.effective_enable_pg_native_login is not None: body["effective_enable_pg_native_login"] = self.effective_enable_pg_native_login if self.effective_enable_readable_secondaries is not None: @@ -298,6 +290,7 @@ def from_dict(cls, d: Dict[str, Any]) -> DatabaseInstance: child_instance_refs=_repeated_dict(d, "child_instance_refs", DatabaseInstanceRef), creation_time=d.get("creation_time", None), creator=d.get("creator", None), + effective_capacity=d.get("effective_capacity", None), effective_enable_pg_native_login=d.get("effective_enable_pg_native_login", None), effective_enable_readable_secondaries=d.get("effective_enable_readable_secondaries", None), effective_node_count=d.get("effective_node_count", None), @@ -335,12 +328,9 @@ class DatabaseInstanceRef: provided as input to create a child instance.""" effective_lsn: Optional[str] = None - """xref AIP-129. `lsn` is owned by the client, while `effective_lsn` is owned by the server. `lsn` - will only be set in Create/Update response messages if and only if the user provides the field - via the request. `effective_lsn` on the other hand will always bet set in all response messages - (Create/Update/Get/List). For a parent ref instance, this is the LSN on the parent instance from - which the instance was created. For a child ref instance, this is the LSN on the instance from - which the child instance was created.""" + """For a parent ref instance, this is the LSN on the parent instance from which the instance was + created. For a child ref instance, this is the LSN on the instance from which the child instance + was created.""" lsn: Optional[str] = None """User-specified WAL LSN of the ref database instance. @@ -1611,12 +1601,8 @@ def delete_database_instance(self, name: str, *, force: Optional[bool] = None, p By default, a instance cannot be deleted if it has descendant instances created via PITR. If this flag is specified as true, all descendent instances will be deleted as well. :param purge: bool (optional) - Note purge=false is in development. If false, the database instance is soft deleted (implementation - pending). Soft deleted instances behave as if they are deleted, and cannot be used for CRUD - operations nor connected to. However they can be undeleted by calling the undelete API for a limited - time (implementation pending). If true, the database instance is hard deleted and cannot be - undeleted. For the time being, setting this value to true is required to delete an instance (soft - delete is not yet supported). + Deprecated. Omitting the field or setting it to true will result in the field being hard deleted. + Setting a value of false will throw a bad request. """ diff --git a/databricks/sdk/service/iam.py b/databricks/sdk/service/iam.py index 2991a890f..e38498296 100755 --- a/databricks/sdk/service/iam.py +++ b/databricks/sdk/service/iam.py @@ -124,6 +124,244 @@ def from_dict(cls, d: Dict[str, Any]) -> AccessControlResponse: ) +@dataclass +class AccountGroup: + account_id: Optional[str] = None + """Databricks account ID""" + + display_name: Optional[str] = None + """String that represents a human-readable group name""" + + external_id: Optional[str] = None + """external_id should be unique for identifying groups""" + + id: Optional[str] = None + """Databricks group ID""" + + members: Optional[List[ComplexValue]] = None + + meta: Optional[ResourceMeta] = None + """Container for the group identifier. Workspace local versus account.""" + + roles: Optional[List[ComplexValue]] = None + """Indicates if the group has the admin role.""" + + def as_dict(self) -> dict: + """Serializes the AccountGroup into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.display_name is not None: + body["displayName"] = self.display_name + if self.external_id is not None: + body["externalId"] = self.external_id + if self.id is not None: + body["id"] = self.id + if self.members: + body["members"] = [v.as_dict() for v in self.members] + if self.meta: + body["meta"] = self.meta.as_dict() + if self.roles: + body["roles"] = [v.as_dict() for v in self.roles] + return body + + def as_shallow_dict(self) -> dict: + """Serializes the AccountGroup into a shallow dictionary of its immediate attributes.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.display_name is not None: + body["displayName"] = self.display_name + if self.external_id is not None: + body["externalId"] = self.external_id + if self.id is not None: + body["id"] = self.id + if self.members: + body["members"] = self.members + if self.meta: + body["meta"] = self.meta + if self.roles: + body["roles"] = self.roles + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> AccountGroup: + """Deserializes the AccountGroup from a dictionary.""" + return cls( + account_id=d.get("account_id", None), + display_name=d.get("displayName", None), + external_id=d.get("externalId", None), + id=d.get("id", None), + members=_repeated_dict(d, "members", ComplexValue), + meta=_from_dict(d, "meta", ResourceMeta), + roles=_repeated_dict(d, "roles", ComplexValue), + ) + + +@dataclass +class AccountServicePrincipal: + account_id: Optional[str] = None + """Databricks account ID""" + + active: Optional[bool] = None + """If this user is active""" + + application_id: Optional[str] = None + """UUID relating to the service principal""" + + display_name: Optional[str] = None + """String that represents a concatenation of given and family names.""" + + external_id: Optional[str] = None + + id: Optional[str] = None + """Databricks service principal ID.""" + + roles: Optional[List[ComplexValue]] = None + """Indicates if the group has the admin role.""" + + def as_dict(self) -> dict: + """Serializes the AccountServicePrincipal into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.active is not None: + body["active"] = self.active + if self.application_id is not None: + body["applicationId"] = self.application_id + if self.display_name is not None: + body["displayName"] = self.display_name + if self.external_id is not None: + body["externalId"] = self.external_id + if self.id is not None: + body["id"] = self.id + if self.roles: + body["roles"] = [v.as_dict() for v in self.roles] + return body + + def as_shallow_dict(self) -> dict: + """Serializes the AccountServicePrincipal into a shallow dictionary of its immediate attributes.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.active is not None: + body["active"] = self.active + if self.application_id is not None: + body["applicationId"] = self.application_id + if self.display_name is not None: + body["displayName"] = self.display_name + if self.external_id is not None: + body["externalId"] = self.external_id + if self.id is not None: + body["id"] = self.id + if self.roles: + body["roles"] = self.roles + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> AccountServicePrincipal: + """Deserializes the AccountServicePrincipal from a dictionary.""" + return cls( + account_id=d.get("account_id", None), + active=d.get("active", None), + application_id=d.get("applicationId", None), + display_name=d.get("displayName", None), + external_id=d.get("externalId", None), + id=d.get("id", None), + roles=_repeated_dict(d, "roles", ComplexValue), + ) + + +@dataclass +class AccountUser: + account_id: Optional[str] = None + """Databricks account ID""" + + active: Optional[bool] = None + """If this user is active""" + + display_name: Optional[str] = None + """String that represents a concatenation of given and family names. For example `John Smith`.""" + + emails: Optional[List[ComplexValue]] = None + """All the emails associated with the Databricks user.""" + + external_id: Optional[str] = None + """External ID is not currently supported. It is reserved for future use.""" + + id: Optional[str] = None + """Databricks user ID.""" + + name: Optional[Name] = None + + roles: Optional[List[ComplexValue]] = None + """Indicates if the group has the admin role.""" + + user_name: Optional[str] = None + """Email address of the Databricks user.""" + + def as_dict(self) -> dict: + """Serializes the AccountUser into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.active is not None: + body["active"] = self.active + if self.display_name is not None: + body["displayName"] = self.display_name + if self.emails: + body["emails"] = [v.as_dict() for v in self.emails] + if self.external_id is not None: + body["externalId"] = self.external_id + if self.id is not None: + body["id"] = self.id + if self.name: + body["name"] = self.name.as_dict() + if self.roles: + body["roles"] = [v.as_dict() for v in self.roles] + if self.user_name is not None: + body["userName"] = self.user_name + return body + + def as_shallow_dict(self) -> dict: + """Serializes the AccountUser into a shallow dictionary of its immediate attributes.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.active is not None: + body["active"] = self.active + if self.display_name is not None: + body["displayName"] = self.display_name + if self.emails: + body["emails"] = self.emails + if self.external_id is not None: + body["externalId"] = self.external_id + if self.id is not None: + body["id"] = self.id + if self.name: + body["name"] = self.name + if self.roles: + body["roles"] = self.roles + if self.user_name is not None: + body["userName"] = self.user_name + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> AccountUser: + """Deserializes the AccountUser from a dictionary.""" + return cls( + account_id=d.get("account_id", None), + active=d.get("active", None), + display_name=d.get("displayName", None), + emails=_repeated_dict(d, "emails", ComplexValue), + external_id=d.get("externalId", None), + id=d.get("id", None), + name=_from_dict(d, "name", Name), + roles=_repeated_dict(d, "roles", ComplexValue), + user_name=d.get("userName", None), + ) + + @dataclass class Actor: """represents an identity trying to access a resource - user or a service principal group can be a @@ -425,6 +663,7 @@ class Group: [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements""" external_id: Optional[str] = None + """external_id should be unique for identifying groups""" groups: Optional[List[ComplexValue]] = None @@ -510,16 +749,13 @@ class GroupSchema(Enum): @dataclass -class ListGroupsResponse: +class ListAccountGroupsResponse: items_per_page: Optional[int] = None """Total results returned in the response.""" - resources: Optional[List[Group]] = None + resources: Optional[List[AccountGroup]] = None """User objects returned in the response.""" - schemas: Optional[List[ListResponseSchema]] = None - """The schema of the service principal.""" - start_index: Optional[int] = None """Starting index of all the results that matched the request filters. First item is number 1.""" @@ -527,14 +763,12 @@ class ListGroupsResponse: """Total results that match the request filters.""" def as_dict(self) -> dict: - """Serializes the ListGroupsResponse into a dictionary suitable for use as a JSON request body.""" + """Serializes the ListAccountGroupsResponse into a dictionary suitable for use as a JSON request body.""" body = {} if self.items_per_page is not None: body["itemsPerPage"] = self.items_per_page if self.resources: body["Resources"] = [v.as_dict() for v in self.resources] - if self.schemas: - body["schemas"] = [v.value for v in self.schemas] if self.start_index is not None: body["startIndex"] = self.start_index if self.total_results is not None: @@ -542,14 +776,12 @@ def as_dict(self) -> dict: return body def as_shallow_dict(self) -> dict: - """Serializes the ListGroupsResponse into a shallow dictionary of its immediate attributes.""" + """Serializes the ListAccountGroupsResponse into a shallow dictionary of its immediate attributes.""" body = {} if self.items_per_page is not None: body["itemsPerPage"] = self.items_per_page if self.resources: body["Resources"] = self.resources - if self.schemas: - body["schemas"] = self.schemas if self.start_index is not None: body["startIndex"] = self.start_index if self.total_results is not None: @@ -557,33 +789,24 @@ def as_shallow_dict(self) -> dict: return body @classmethod - def from_dict(cls, d: Dict[str, Any]) -> ListGroupsResponse: - """Deserializes the ListGroupsResponse from a dictionary.""" + def from_dict(cls, d: Dict[str, Any]) -> ListAccountGroupsResponse: + """Deserializes the ListAccountGroupsResponse from a dictionary.""" return cls( items_per_page=d.get("itemsPerPage", None), - resources=_repeated_dict(d, "Resources", Group), - schemas=_repeated_enum(d, "schemas", ListResponseSchema), + resources=_repeated_dict(d, "Resources", AccountGroup), start_index=d.get("startIndex", None), total_results=d.get("totalResults", None), ) -class ListResponseSchema(Enum): - - URN_IETF_PARAMS_SCIM_API_MESSAGES_2_0_LIST_RESPONSE = "urn:ietf:params:scim:api:messages:2.0:ListResponse" - - @dataclass -class ListServicePrincipalResponse: +class ListAccountServicePrincipalsResponse: items_per_page: Optional[int] = None """Total results returned in the response.""" - resources: Optional[List[ServicePrincipal]] = None + resources: Optional[List[AccountServicePrincipal]] = None """User objects returned in the response.""" - schemas: Optional[List[ListResponseSchema]] = None - """The schema of the List response.""" - start_index: Optional[int] = None """Starting index of all the results that matched the request filters. First item is number 1.""" @@ -591,14 +814,12 @@ class ListServicePrincipalResponse: """Total results that match the request filters.""" def as_dict(self) -> dict: - """Serializes the ListServicePrincipalResponse into a dictionary suitable for use as a JSON request body.""" + """Serializes the ListAccountServicePrincipalsResponse into a dictionary suitable for use as a JSON request body.""" body = {} if self.items_per_page is not None: body["itemsPerPage"] = self.items_per_page if self.resources: body["Resources"] = [v.as_dict() for v in self.resources] - if self.schemas: - body["schemas"] = [v.value for v in self.schemas] if self.start_index is not None: body["startIndex"] = self.start_index if self.total_results is not None: @@ -606,14 +827,12 @@ def as_dict(self) -> dict: return body def as_shallow_dict(self) -> dict: - """Serializes the ListServicePrincipalResponse into a shallow dictionary of its immediate attributes.""" + """Serializes the ListAccountServicePrincipalsResponse into a shallow dictionary of its immediate attributes.""" body = {} if self.items_per_page is not None: body["itemsPerPage"] = self.items_per_page if self.resources: body["Resources"] = self.resources - if self.schemas: - body["schemas"] = self.schemas if self.start_index is not None: body["startIndex"] = self.start_index if self.total_results is not None: @@ -621,33 +840,26 @@ def as_shallow_dict(self) -> dict: return body @classmethod - def from_dict(cls, d: Dict[str, Any]) -> ListServicePrincipalResponse: - """Deserializes the ListServicePrincipalResponse from a dictionary.""" + def from_dict(cls, d: Dict[str, Any]) -> ListAccountServicePrincipalsResponse: + """Deserializes the ListAccountServicePrincipalsResponse from a dictionary.""" return cls( items_per_page=d.get("itemsPerPage", None), - resources=_repeated_dict(d, "Resources", ServicePrincipal), - schemas=_repeated_enum(d, "schemas", ListResponseSchema), + resources=_repeated_dict(d, "Resources", AccountServicePrincipal), start_index=d.get("startIndex", None), total_results=d.get("totalResults", None), ) -class ListSortOrder(Enum): - - ASCENDING = "ascending" - DESCENDING = "descending" - - @dataclass -class ListUsersResponse: +class ListGroupsResponse: items_per_page: Optional[int] = None """Total results returned in the response.""" - resources: Optional[List[User]] = None + resources: Optional[List[Group]] = None """User objects returned in the response.""" schemas: Optional[List[ListResponseSchema]] = None - """The schema of the List response.""" + """The schema of the service principal.""" start_index: Optional[int] = None """Starting index of all the results that matched the request filters. First item is number 1.""" @@ -656,7 +868,7 @@ class ListUsersResponse: """Total results that match the request filters.""" def as_dict(self) -> dict: - """Serializes the ListUsersResponse into a dictionary suitable for use as a JSON request body.""" + """Serializes the ListGroupsResponse into a dictionary suitable for use as a JSON request body.""" body = {} if self.items_per_page is not None: body["itemsPerPage"] = self.items_per_page @@ -671,7 +883,7 @@ def as_dict(self) -> dict: return body def as_shallow_dict(self) -> dict: - """Serializes the ListUsersResponse into a shallow dictionary of its immediate attributes.""" + """Serializes the ListGroupsResponse into a shallow dictionary of its immediate attributes.""" body = {} if self.items_per_page is not None: body["itemsPerPage"] = self.items_per_page @@ -686,19 +898,148 @@ def as_shallow_dict(self) -> dict: return body @classmethod - def from_dict(cls, d: Dict[str, Any]) -> ListUsersResponse: - """Deserializes the ListUsersResponse from a dictionary.""" + def from_dict(cls, d: Dict[str, Any]) -> ListGroupsResponse: + """Deserializes the ListGroupsResponse from a dictionary.""" return cls( items_per_page=d.get("itemsPerPage", None), - resources=_repeated_dict(d, "Resources", User), + resources=_repeated_dict(d, "Resources", Group), schemas=_repeated_enum(d, "schemas", ListResponseSchema), start_index=d.get("startIndex", None), total_results=d.get("totalResults", None), ) -@dataclass -class MigratePermissionsResponse: +class ListResponseSchema(Enum): + + URN_IETF_PARAMS_SCIM_API_MESSAGES_2_0_LIST_RESPONSE = "urn:ietf:params:scim:api:messages:2.0:ListResponse" + + +@dataclass +class ListServicePrincipalResponse: + items_per_page: Optional[int] = None + """Total results returned in the response.""" + + resources: Optional[List[ServicePrincipal]] = None + """User objects returned in the response.""" + + schemas: Optional[List[ListResponseSchema]] = None + """The schema of the List response.""" + + start_index: Optional[int] = None + """Starting index of all the results that matched the request filters. First item is number 1.""" + + total_results: Optional[int] = None + """Total results that match the request filters.""" + + def as_dict(self) -> dict: + """Serializes the ListServicePrincipalResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.items_per_page is not None: + body["itemsPerPage"] = self.items_per_page + if self.resources: + body["Resources"] = [v.as_dict() for v in self.resources] + if self.schemas: + body["schemas"] = [v.value for v in self.schemas] + if self.start_index is not None: + body["startIndex"] = self.start_index + if self.total_results is not None: + body["totalResults"] = self.total_results + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ListServicePrincipalResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.items_per_page is not None: + body["itemsPerPage"] = self.items_per_page + if self.resources: + body["Resources"] = self.resources + if self.schemas: + body["schemas"] = self.schemas + if self.start_index is not None: + body["startIndex"] = self.start_index + if self.total_results is not None: + body["totalResults"] = self.total_results + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ListServicePrincipalResponse: + """Deserializes the ListServicePrincipalResponse from a dictionary.""" + return cls( + items_per_page=d.get("itemsPerPage", None), + resources=_repeated_dict(d, "Resources", ServicePrincipal), + schemas=_repeated_enum(d, "schemas", ListResponseSchema), + start_index=d.get("startIndex", None), + total_results=d.get("totalResults", None), + ) + + +class ListSortOrder(Enum): + + ASCENDING = "ascending" + DESCENDING = "descending" + + +@dataclass +class ListUsersResponse: + items_per_page: Optional[int] = None + """Total results returned in the response.""" + + resources: Optional[List[User]] = None + """User objects returned in the response.""" + + schemas: Optional[List[ListResponseSchema]] = None + """The schema of the List response.""" + + start_index: Optional[int] = None + """Starting index of all the results that matched the request filters. First item is number 1.""" + + total_results: Optional[int] = None + """Total results that match the request filters.""" + + def as_dict(self) -> dict: + """Serializes the ListUsersResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.items_per_page is not None: + body["itemsPerPage"] = self.items_per_page + if self.resources: + body["Resources"] = [v.as_dict() for v in self.resources] + if self.schemas: + body["schemas"] = [v.value for v in self.schemas] + if self.start_index is not None: + body["startIndex"] = self.start_index + if self.total_results is not None: + body["totalResults"] = self.total_results + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ListUsersResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.items_per_page is not None: + body["itemsPerPage"] = self.items_per_page + if self.resources: + body["Resources"] = self.resources + if self.schemas: + body["schemas"] = self.schemas + if self.start_index is not None: + body["startIndex"] = self.start_index + if self.total_results is not None: + body["totalResults"] = self.total_results + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ListUsersResponse: + """Deserializes the ListUsersResponse from a dictionary.""" + return cls( + items_per_page=d.get("itemsPerPage", None), + resources=_repeated_dict(d, "Resources", User), + schemas=_repeated_enum(d, "schemas", ListResponseSchema), + start_index=d.get("startIndex", None), + total_results=d.get("totalResults", None), + ) + + +@dataclass +class MigratePermissionsResponse: permissions_migrated: Optional[int] = None """Number of permissions migrated.""" @@ -1647,24 +1988,6 @@ class ServicePrincipalSchema(Enum): URN_IETF_PARAMS_SCIM_SCHEMAS_CORE_2_0_SERVICE_PRINCIPAL = "urn:ietf:params:scim:schemas:core:2.0:ServicePrincipal" -@dataclass -class UpdateResponse: - def as_dict(self) -> dict: - """Serializes the UpdateResponse into a dictionary suitable for use as a JSON request body.""" - body = {} - return body - - def as_shallow_dict(self) -> dict: - """Serializes the UpdateResponse into a shallow dictionary of its immediate attributes.""" - body = {} - return body - - @classmethod - def from_dict(cls, d: Dict[str, Any]) -> UpdateResponse: - """Deserializes the UpdateResponse from a dictionary.""" - return cls() - - @dataclass class User: active: Optional[bool] = None @@ -1886,7 +2209,8 @@ def get_assignable_roles_for_resource(self, resource: str) -> GetAssignableRoles Examples | Summary :--- | :--- `resource=accounts/` | A resource name for the account. `resource=accounts//groups/` | A resource name for the group. `resource=accounts//servicePrincipals/` | A resource name for the service - principal. + principal. `resource=accounts//tagPolicies/` | A resource name for the + tag policy. :returns: :class:`GetAssignableRolesForResourceResponse` """ @@ -1918,6 +2242,8 @@ def get_rule_set(self, name: str, etag: str) -> RuleSetResponse: set on the group. `name=accounts//servicePrincipals//ruleSets/default` | A name for a rule set on the service principal. + `name=accounts//tagPolicies//ruleSets/default` | A name for a rule set on + the tag policy. :param etag: str Etag used for versioning. The response is at least as fresh as the eTag provided. Etag is used for optimistic concurrency control as a way to help prevent simultaneous updates of a rule set from @@ -1997,7 +2323,8 @@ def get_assignable_roles_for_resource(self, resource: str) -> GetAssignableRoles Examples | Summary :--- | :--- `resource=accounts/` | A resource name for the account. `resource=accounts//groups/` | A resource name for the group. `resource=accounts//servicePrincipals/` | A resource name for the service - principal. + principal. `resource=accounts//tagPolicies/` | A resource name for the + tag policy. :returns: :class:`GetAssignableRolesForResourceResponse` """ @@ -2026,6 +2353,8 @@ def get_rule_set(self, name: str, etag: str) -> RuleSetResponse: set on the group. `name=accounts//servicePrincipals//ruleSets/default` | A name for a rule set on the service principal. + `name=accounts//tagPolicies//ruleSets/default` | A name for a rule set on + the tag policy. :param etag: str Etag used for versioning. The response is at least as fresh as the eTag provided. Etag is used for optimistic concurrency control as a way to help prevent simultaneous updates of a rule set from @@ -2077,6 +2406,2006 @@ def update_rule_set(self, name: str, rule_set: RuleSetUpdateRequest) -> RuleSetR return RuleSetResponse.from_dict(res) +class AccountGroupsV2API: + """Groups simplify identity management, making it easier to assign access to Databricks account, data, and + other securable objects. + + It is best practice to assign access to workspaces and access-control policies in Unity Catalog to groups, + instead of to users individually. All Databricks account identities can be assigned as members of groups, + and members inherit permissions that are assigned to their group.""" + + def __init__(self, api_client): + self._api = api_client + + def create( + self, + *, + display_name: Optional[str] = None, + external_id: Optional[str] = None, + id: Optional[str] = None, + members: Optional[List[ComplexValue]] = None, + meta: Optional[ResourceMeta] = None, + roles: Optional[List[ComplexValue]] = None, + ) -> AccountGroup: + """Creates a group in the Databricks account with a unique name, using the supplied group details. + + :param display_name: str (optional) + String that represents a human-readable group name + :param external_id: str (optional) + :param id: str (optional) + Databricks group ID + :param members: List[:class:`ComplexValue`] (optional) + :param meta: :class:`ResourceMeta` (optional) + Container for the group identifier. Workspace local versus account. + :param roles: List[:class:`ComplexValue`] (optional) + Indicates if the group has the admin role. + + :returns: :class:`AccountGroup` + """ + body = {} + if display_name is not None: + body["displayName"] = display_name + if external_id is not None: + body["externalId"] = external_id + if id is not None: + body["id"] = id + if members is not None: + body["members"] = [v.as_dict() for v in members] + if meta is not None: + body["meta"] = meta.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups", body=body, headers=headers + ) + return AccountGroup.from_dict(res) + + def delete(self, id: str): + """Deletes a group from the Databricks account. + + :param id: str + Unique ID for a group in the Databricks account. + + + """ + + headers = {} + + self._api.do("DELETE", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", headers=headers) + + def get(self, id: str) -> AccountGroup: + """Gets the information for a specific group in the Databricks account. + + :param id: str + Unique ID for a group in the Databricks account. + + :returns: :class:`AccountGroup` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", headers=headers) + return AccountGroup.from_dict(res) + + def list( + self, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[ListSortOrder] = None, + 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`. + + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. Default is 10000. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: Iterator over :class:`AccountGroup` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do( + "GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups", query=query, headers=headers + ) + if "Resources" in json: + for v in json["Resources"]: + yield AccountGroup.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) + + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates the details of a group. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. + + + """ + body = {} + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Content-Type": "application/json", + } + + self._api.do( + "PATCH", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", body=body, headers=headers + ) + + def update( + self, + id: str, + *, + display_name: Optional[str] = None, + external_id: Optional[str] = None, + members: Optional[List[ComplexValue]] = None, + meta: Optional[ResourceMeta] = None, + roles: Optional[List[ComplexValue]] = None, + ): + """Updates the details of a group by replacing the entire group entity. + + :param id: str + Databricks group ID + :param display_name: str (optional) + String that represents a human-readable group name + :param external_id: str (optional) + :param members: List[:class:`ComplexValue`] (optional) + :param meta: :class:`ResourceMeta` (optional) + Container for the group identifier. Workspace local versus account. + :param roles: List[:class:`ComplexValue`] (optional) + Indicates if the group has the admin role. + + + """ + body = {} + if display_name is not None: + body["displayName"] = display_name + if external_id is not None: + body["externalId"] = external_id + if members is not None: + body["members"] = [v.as_dict() for v in members] + if meta is not None: + body["meta"] = meta.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PUT", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Groups/{id}", body=body, headers=headers) + + +class AccountServicePrincipalsV2API: + """Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms. + Databricks recommends creating service principals to run production jobs or modify production data. If all + processes that act on production data run with service principals, interactive users do not need any + write, delete, or modify privileges in production. This eliminates the risk of a user overwriting + production data by accident.""" + + def __init__(self, api_client): + self._api = api_client + + def create( + self, + *, + active: Optional[bool] = None, + application_id: Optional[str] = None, + display_name: Optional[str] = None, + external_id: Optional[str] = None, + id: Optional[str] = None, + roles: Optional[List[ComplexValue]] = None, + ) -> AccountServicePrincipal: + """Creates a new service principal in the Databricks account. + + :param active: bool (optional) + If this user is active + :param application_id: str (optional) + UUID relating to the service principal + :param display_name: str (optional) + String that represents a concatenation of given and family names. + :param external_id: str (optional) + :param id: str (optional) + Databricks service principal ID. + :param roles: List[:class:`ComplexValue`] (optional) + Indicates if the group has the admin role. + + :returns: :class:`AccountServicePrincipal` + """ + body = {} + if active is not None: + body["active"] = active + if application_id is not None: + body["applicationId"] = application_id + if display_name is not None: + body["displayName"] = display_name + if external_id is not None: + body["externalId"] = external_id + if id is not None: + body["id"] = id + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals", body=body, headers=headers + ) + return AccountServicePrincipal.from_dict(res) + + def delete(self, id: str): + """Delete a single service principal in the Databricks account. + + :param id: str + Unique ID for a service principal in the Databricks account. + + + """ + + headers = {} + + self._api.do( + "DELETE", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}", headers=headers + ) + + def get(self, id: str) -> AccountServicePrincipal: + """Gets the details for a single service principal define in the Databricks account. + + :param id: str + Unique ID for a service principal in the Databricks account. + + :returns: :class:`AccountServicePrincipal` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do( + "GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}", headers=headers + ) + return AccountServicePrincipal.from_dict(res) + + def list( + self, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[ListSortOrder] = None, + start_index: Optional[int] = None, + ) -> Iterator[AccountServicePrincipal]: + """Gets the set of service principals associated with a Databricks account. + + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. Default is 10000. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: Iterator over :class:`AccountServicePrincipal` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do( + "GET", + f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals", + query=query, + headers=headers, + ) + if "Resources" in json: + for v in json["Resources"]: + yield AccountServicePrincipal.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) + + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates the details of a single service principal in the Databricks account. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. + + + """ + body = {} + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do( + "PATCH", + f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}", + body=body, + headers=headers, + ) + + def update( + self, + id: str, + *, + active: Optional[bool] = None, + application_id: Optional[str] = None, + display_name: Optional[str] = None, + external_id: Optional[str] = None, + roles: Optional[List[ComplexValue]] = None, + ): + """Updates the details of a single service principal. + + This action replaces the existing service principal with the same name. + + :param id: str + Databricks service principal ID. + :param active: bool (optional) + If this user is active + :param application_id: str (optional) + UUID relating to the service principal + :param display_name: str (optional) + String that represents a concatenation of given and family names. + :param external_id: str (optional) + :param roles: List[:class:`ComplexValue`] (optional) + Indicates if the group has the admin role. + + + """ + body = {} + if active is not None: + body["active"] = active + if application_id is not None: + body["applicationId"] = application_id + if display_name is not None: + body["displayName"] = display_name + if external_id is not None: + body["externalId"] = external_id + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do( + "PUT", + f"/api/2.0/accounts/{self._api.account_id}/scim/v2/ServicePrincipals/{id}", + body=body, + headers=headers, + ) + + +class AccountUsersV2API: + """User identities recognized by Databricks and represented by email addresses. + + Databricks recommends using SCIM provisioning to sync users and groups automatically from your identity + provider to your Databricks account. SCIM streamlines onboarding a new employee or team by using your + identity provider to create users and groups in Databricks account and give them the proper level of + access. When a user leaves your organization or no longer needs access to Databricks account, admins can + terminate the user in your identity provider and that user’s account will also be removed from + Databricks account. This ensures a consistent offboarding process and prevents unauthorized users from + accessing sensitive data.""" + + def __init__(self, api_client): + self._api = api_client + + def create( + self, + *, + active: Optional[bool] = None, + display_name: Optional[str] = None, + emails: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + id: Optional[str] = None, + name: Optional[Name] = None, + roles: Optional[List[ComplexValue]] = None, + user_name: Optional[str] = None, + ) -> AccountUser: + """Creates a new user in the Databricks account. This new user will also be added to the Databricks + account. + + :param active: bool (optional) + If this user is active + :param display_name: str (optional) + String that represents a concatenation of given and family names. For example `John Smith`. + :param emails: List[:class:`ComplexValue`] (optional) + All the emails associated with the Databricks user. + :param external_id: str (optional) + External ID is not currently supported. It is reserved for future use. + :param id: str (optional) + Databricks user ID. + :param name: :class:`Name` (optional) + :param roles: List[:class:`ComplexValue`] (optional) + Indicates if the group has the admin role. + :param user_name: str (optional) + Email address of the Databricks user. + + :returns: :class:`AccountUser` + """ + body = {} + if active is not None: + body["active"] = active + if display_name is not None: + body["displayName"] = display_name + if emails is not None: + body["emails"] = [v.as_dict() for v in emails] + if external_id is not None: + body["externalId"] = external_id + if id is not None: + body["id"] = id + if name is not None: + body["name"] = name.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if user_name is not None: + body["userName"] = user_name + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users", body=body, headers=headers + ) + return AccountUser.from_dict(res) + + def delete(self, id: str): + """Deletes a user. Deleting a user from a Databricks account also removes objects associated with the + user. + + :param id: str + Unique ID for a user in the Databricks account. + + + """ + + headers = {} + + self._api.do("DELETE", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", headers=headers) + + def get( + self, + id: str, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[GetSortOrder] = None, + start_index: Optional[int] = None, + ) -> AccountUser: + """Gets information for a specific user in Databricks account. + + :param id: str + Unique ID for a user in the Databricks account. + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. Default is 10000. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. Multi-part paths are supported. For example, `userName`, + `name.givenName`, and `emails`. + :param sort_order: :class:`GetSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: :class:`AccountUser` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + res = self._api.do( + "GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", query=query, headers=headers + ) + return AccountUser.from_dict(res) + + def list( + self, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[ListSortOrder] = None, + start_index: Optional[int] = None, + ) -> Iterator[AccountGroup]: + """Gets details for all the users associated with a Databricks account. + + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. Default is 10000. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. Multi-part paths are supported. For example, `userName`, + `name.givenName`, and `emails`. + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: Iterator over :class:`AccountGroup` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do( + "GET", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users", query=query, headers=headers + ) + if "Resources" in json: + for v in json["Resources"]: + yield AccountGroup.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) + + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates a user resource by applying the supplied operations on specific user attributes. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. + + + """ + body = {} + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do( + "PATCH", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", body=body, headers=headers + ) + + def update( + self, + id: str, + *, + active: Optional[bool] = None, + display_name: Optional[str] = None, + emails: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + name: Optional[Name] = None, + roles: Optional[List[ComplexValue]] = None, + user_name: Optional[str] = None, + ): + """Replaces a user's information with the data supplied in request. + + :param id: str + Databricks user ID. + :param active: bool (optional) + If this user is active + :param display_name: str (optional) + String that represents a concatenation of given and family names. For example `John Smith`. + :param emails: List[:class:`ComplexValue`] (optional) + All the emails associated with the Databricks user. + :param external_id: str (optional) + External ID is not currently supported. It is reserved for future use. + :param name: :class:`Name` (optional) + :param roles: List[:class:`ComplexValue`] (optional) + Indicates if the group has the admin role. + :param user_name: str (optional) + Email address of the Databricks user. + + + """ + body = {} + if active is not None: + body["active"] = active + if display_name is not None: + body["displayName"] = display_name + if emails is not None: + body["emails"] = [v.as_dict() for v in emails] + if external_id is not None: + body["externalId"] = external_id + if name is not None: + body["name"] = name.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if user_name is not None: + body["userName"] = user_name + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PUT", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", body=body, headers=headers) + + +class CurrentUserAPI: + """This API allows retrieving information about currently authenticated user or service principal.""" + + def __init__(self, api_client): + self._api = api_client + + def me(self) -> User: + """Get details about the current method caller's identity. + + + :returns: :class:`User` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", "/api/2.0/preview/scim/v2/Me", headers=headers) + return User.from_dict(res) + + +class GroupsV2API: + """Groups simplify identity management, making it easier to assign access to Databricks workspace, data, and + other securable objects. + + It is best practice to assign access to workspaces and access-control policies in Unity Catalog to groups, + instead of to users individually. All Databricks workspace identities can be assigned as members of + groups, and members inherit permissions that are assigned to their group.""" + + def __init__(self, api_client): + self._api = api_client + + def create( + self, + *, + display_name: Optional[str] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + id: Optional[str] = None, + members: Optional[List[ComplexValue]] = None, + meta: Optional[ResourceMeta] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[GroupSchema]] = None, + ) -> Group: + """Creates a group in the Databricks workspace with a unique name, using the supplied group details. + + :param display_name: str (optional) + String that represents a human-readable group name + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the group. See [assigning entitlements] for a full list of supported + values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + :param groups: List[:class:`ComplexValue`] (optional) + :param id: str (optional) + Databricks group ID + :param members: List[:class:`ComplexValue`] (optional) + :param meta: :class:`ResourceMeta` (optional) + Container for the group identifier. Workspace local versus account. + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`GroupSchema`] (optional) + The schema of the group. + + :returns: :class:`Group` + """ + body = {} + if display_name is not None: + body["displayName"] = display_name + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if id is not None: + body["id"] = id + if members is not None: + body["members"] = [v.as_dict() for v in members] + if meta is not None: + body["meta"] = meta.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/preview/scim/v2/Groups", body=body, headers=headers) + return Group.from_dict(res) + + def delete(self, id: str): + """Deletes a group from the Databricks workspace. + + :param id: str + Unique ID for a group in the Databricks workspace. + + + """ + + headers = {} + + self._api.do("DELETE", f"/api/2.0/preview/scim/v2/Groups/{id}", headers=headers) + + def get(self, id: str) -> Group: + """Gets the information for a specific group in the Databricks workspace. + + :param id: str + Unique ID for a group in the Databricks workspace. + + :returns: :class:`Group` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", f"/api/2.0/preview/scim/v2/Groups/{id}", headers=headers) + return Group.from_dict(res) + + def list( + self, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[ListSortOrder] = None, + start_index: Optional[int] = None, + ) -> Iterator[Group]: + """Gets all details of the groups associated with the Databricks workspace. + + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: Iterator over :class:`Group` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do("GET", "/api/2.0/preview/scim/v2/Groups", query=query, headers=headers) + if "Resources" in json: + for v in json["Resources"]: + yield Group.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) + + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates the details of a group. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. + + + """ + body = {} + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers) + + def update( + self, + id: str, + *, + display_name: Optional[str] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + members: Optional[List[ComplexValue]] = None, + meta: Optional[ResourceMeta] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[GroupSchema]] = None, + ): + """Updates the details of a group by replacing the entire group entity. + + :param id: str + Databricks group ID + :param display_name: str (optional) + String that represents a human-readable group name + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the group. See [assigning entitlements] for a full list of supported + values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + :param groups: List[:class:`ComplexValue`] (optional) + :param members: List[:class:`ComplexValue`] (optional) + :param meta: :class:`ResourceMeta` (optional) + Container for the group identifier. Workspace local versus account. + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`GroupSchema`] (optional) + The schema of the group. + + + """ + body = {} + if display_name is not None: + body["displayName"] = display_name + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if members is not None: + body["members"] = [v.as_dict() for v in members] + if meta is not None: + body["meta"] = meta.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PUT", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers) + + +class PermissionMigrationAPI: + """APIs for migrating acl permissions, used only by the ucx tool: https://github.com/databrickslabs/ucx""" + + def __init__(self, api_client): + self._api = api_client + + def migrate_permissions( + self, + workspace_id: int, + from_workspace_group_name: str, + to_account_group_name: str, + *, + size: Optional[int] = None, + ) -> MigratePermissionsResponse: + """Migrate Permissions. + + :param workspace_id: int + WorkspaceId of the associated workspace where the permission migration will occur. + :param from_workspace_group_name: str + The name of the workspace group that permissions will be migrated from. + :param to_account_group_name: str + The name of the account group that permissions will be migrated to. + :param size: int (optional) + The maximum number of permissions that will be migrated. + + :returns: :class:`MigratePermissionsResponse` + """ + body = {} + if from_workspace_group_name is not None: + body["from_workspace_group_name"] = from_workspace_group_name + if size is not None: + body["size"] = size + if to_account_group_name is not None: + body["to_account_group_name"] = to_account_group_name + if workspace_id is not None: + body["workspace_id"] = workspace_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/permissionmigration", body=body, headers=headers) + return MigratePermissionsResponse.from_dict(res) + + +class PermissionsAPI: + """Permissions API are used to create read, write, edit, update and manage access for various users on + different objects and endpoints. * **[Apps permissions](:service:apps)** — Manage which users can manage + or use apps. * **[Cluster permissions](:service:clusters)** — Manage which users can manage, restart, or + attach to clusters. * **[Cluster policy permissions](:service:clusterpolicies)** — Manage which users + can use cluster policies. * **[Delta Live Tables pipeline permissions](:service:pipelines)** — Manage + which users can view, manage, run, cancel, or own a Delta Live Tables pipeline. * **[Job + permissions](:service:jobs)** — Manage which users can view, manage, trigger, cancel, or own a job. * + **[MLflow experiment permissions](:service:experiments)** — Manage which users can read, edit, or manage + MLflow experiments. * **[MLflow registered model permissions](:service:modelregistry)** — Manage which + users can read, edit, or manage MLflow registered models. * **[Instance Pool + permissions](:service:instancepools)** — Manage which users can manage or attach to pools. * **[Repo + permissions](repos)** — Manage which users can read, run, edit, or manage a repo. * **[Serving endpoint + permissions](:service:servingendpoints)** — Manage which users can view, query, or manage a serving + endpoint. * **[SQL warehouse permissions](:service:warehouses)** — Manage which users can use or manage + SQL warehouses. * **[Token permissions](:service:tokenmanagement)** — Manage which users can create or + use tokens. * **[Workspace object permissions](:service:workspace)** — Manage which users can read, run, + edit, or manage alerts, dbsql-dashboards, directories, files, notebooks and queries. For the mapping of + the required permissions for specific actions or abilities and other important information, see [Access + Control]. Note that to manage access control on service principals, use **[Account Access Control + Proxy](:service:accountaccesscontrolproxy)**. + + [Access Control]: https://docs.databricks.com/security/auth-authz/access-control/index.html""" + + def __init__(self, api_client): + self._api = api_client + + def get(self, request_object_type: str, request_object_id: str) -> ObjectPermissions: + """Gets the permissions of an object. Objects can inherit permissions from their parent objects or root + object. + + :param request_object_type: str + The type of the request object. Can be one of the following: alerts, alertsv2, authorization, + clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, + instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or + warehouses. + :param request_object_id: str + The id of the request object. + + :returns: :class:`ObjectPermissions` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", headers=headers) + return ObjectPermissions.from_dict(res) + + def get_permission_levels(self, request_object_type: str, request_object_id: str) -> GetPermissionLevelsResponse: + """Gets the permission levels that a user can have on an object. + + :param request_object_type: str + The type of the request object. Can be one of the following: alerts, alertsv2, authorization, + clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, + instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or + warehouses. + :param request_object_id: str + + :returns: :class:`GetPermissionLevelsResponse` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do( + "GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}/permissionLevels", headers=headers + ) + return GetPermissionLevelsResponse.from_dict(res) + + def set( + self, + request_object_type: str, + request_object_id: str, + *, + access_control_list: Optional[List[AccessControlRequest]] = None, + ) -> ObjectPermissions: + """Sets permissions on an object, replacing existing permissions if they exist. Deletes all direct + permissions if none are specified. Objects can inherit permissions from their parent objects or root + object. + + :param request_object_type: str + The type of the request object. Can be one of the following: alerts, alertsv2, authorization, + clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, + instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or + warehouses. + :param request_object_id: str + The id of the request object. + :param access_control_list: List[:class:`AccessControlRequest`] (optional) + + :returns: :class:`ObjectPermissions` + """ + body = {} + if access_control_list is not None: + body["access_control_list"] = [v.as_dict() for v in access_control_list] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "PUT", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers + ) + return ObjectPermissions.from_dict(res) + + def update( + self, + request_object_type: str, + request_object_id: str, + *, + access_control_list: Optional[List[AccessControlRequest]] = None, + ) -> ObjectPermissions: + """Updates the permissions on an object. Objects can inherit permissions from their parent objects or + root object. + + :param request_object_type: str + The type of the request object. Can be one of the following: alerts, alertsv2, authorization, + clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, + instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or + warehouses. + :param request_object_id: str + The id of the request object. + :param access_control_list: List[:class:`AccessControlRequest`] (optional) + + :returns: :class:`ObjectPermissions` + """ + body = {} + if access_control_list is not None: + body["access_control_list"] = [v.as_dict() for v in access_control_list] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "PATCH", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers + ) + return ObjectPermissions.from_dict(res) + + +class ServicePrincipalsV2API: + """Identities for use with jobs, automated tools, and systems such as scripts, apps, and CI/CD platforms. + Databricks recommends creating service principals to run production jobs or modify production data. If all + processes that act on production data run with service principals, interactive users do not need any + write, delete, or modify privileges in production. This eliminates the risk of a user overwriting + production data by accident.""" + + def __init__(self, api_client): + self._api = api_client + + def create( + self, + *, + active: Optional[bool] = None, + application_id: Optional[str] = None, + display_name: Optional[str] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + id: Optional[str] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[ServicePrincipalSchema]] = None, + ) -> ServicePrincipal: + """Creates a new service principal in the Databricks workspace. + + :param active: bool (optional) + If this user is active + :param application_id: str (optional) + UUID relating to the service principal + :param display_name: str (optional) + String that represents a concatenation of given and family names. + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the service principal. See [assigning entitlements] for a full list of + supported values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + :param groups: List[:class:`ComplexValue`] (optional) + :param id: str (optional) + Databricks service principal ID. + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`ServicePrincipalSchema`] (optional) + The schema of the List response. + + :returns: :class:`ServicePrincipal` + """ + body = {} + if active is not None: + body["active"] = active + if application_id is not None: + body["applicationId"] = application_id + if display_name is not None: + body["displayName"] = display_name + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if id is not None: + body["id"] = id + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/preview/scim/v2/ServicePrincipals", body=body, headers=headers) + return ServicePrincipal.from_dict(res) + + def delete(self, id: str): + """Delete a single service principal in the Databricks workspace. + + :param id: str + Unique ID for a service principal in the Databricks workspace. + + + """ + + headers = {} + + self._api.do("DELETE", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", headers=headers) + + def get(self, id: str) -> ServicePrincipal: + """Gets the details for a single service principal define in the Databricks workspace. + + :param id: str + Unique ID for a service principal in the Databricks workspace. + + :returns: :class:`ServicePrincipal` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", headers=headers) + return ServicePrincipal.from_dict(res) + + def list( + self, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[ListSortOrder] = None, + start_index: Optional[int] = None, + ) -> Iterator[ServicePrincipal]: + """Gets the set of service principals associated with a Databricks workspace. + + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: Iterator over :class:`ServicePrincipal` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do("GET", "/api/2.0/preview/scim/v2/ServicePrincipals", query=query, headers=headers) + if "Resources" in json: + for v in json["Resources"]: + yield ServicePrincipal.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) + + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates the details of a single service principal in the Databricks workspace. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. + + + """ + body = {} + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PATCH", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", body=body, headers=headers) + + def update( + self, + id: str, + *, + active: Optional[bool] = None, + application_id: Optional[str] = None, + display_name: Optional[str] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[ServicePrincipalSchema]] = None, + ): + """Updates the details of a single service principal. + + This action replaces the existing service principal with the same name. + + :param id: str + Databricks service principal ID. + :param active: bool (optional) + If this user is active + :param application_id: str (optional) + UUID relating to the service principal + :param display_name: str (optional) + String that represents a concatenation of given and family names. + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the service principal. See [assigning entitlements] for a full list of + supported values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + :param groups: List[:class:`ComplexValue`] (optional) + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`ServicePrincipalSchema`] (optional) + The schema of the List response. + + + """ + body = {} + if active is not None: + body["active"] = active + if application_id is not None: + body["applicationId"] = application_id + if display_name is not None: + body["displayName"] = display_name + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PUT", f"/api/2.0/preview/scim/v2/ServicePrincipals/{id}", body=body, headers=headers) + + +class UsersV2API: + """User identities recognized by Databricks and represented by email addresses. + + Databricks recommends using SCIM provisioning to sync users and groups automatically from your identity + provider to your Databricks workspace. SCIM streamlines onboarding a new employee or team by using your + identity provider to create users and groups in Databricks workspace and give them the proper level of + access. When a user leaves your organization or no longer needs access to Databricks workspace, admins can + terminate the user in your identity provider and that user’s account will also be removed from + Databricks workspace. This ensures a consistent offboarding process and prevents unauthorized users from + accessing sensitive data.""" + + def __init__(self, api_client): + self._api = api_client + + def create( + self, + *, + active: Optional[bool] = None, + display_name: Optional[str] = None, + emails: Optional[List[ComplexValue]] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + id: Optional[str] = None, + name: Optional[Name] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[UserSchema]] = None, + user_name: Optional[str] = None, + ) -> User: + """Creates a new user in the Databricks workspace. This new user will also be added to the Databricks + account. + + :param active: bool (optional) + If this user is active + :param display_name: str (optional) + String that represents a concatenation of given and family names. For example `John Smith`. This + field cannot be updated through the Workspace SCIM APIs when [identity federation is enabled]. Use + Account SCIM APIs to update `displayName`. + + [identity federation is enabled]: https://docs.databricks.com/administration-guide/users-groups/best-practices.html#enable-identity-federation + :param emails: List[:class:`ComplexValue`] (optional) + All the emails associated with the Databricks user. + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the user. See [assigning entitlements] for a full list of supported values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + External ID is not currently supported. It is reserved for future use. + :param groups: List[:class:`ComplexValue`] (optional) + :param id: str (optional) + Databricks user ID. + :param name: :class:`Name` (optional) + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`UserSchema`] (optional) + The schema of the user. + :param user_name: str (optional) + Email address of the Databricks user. + + :returns: :class:`User` + """ + body = {} + if active is not None: + body["active"] = active + if display_name is not None: + body["displayName"] = display_name + if emails is not None: + body["emails"] = [v.as_dict() for v in emails] + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if id is not None: + body["id"] = id + if name is not None: + body["name"] = name.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + if user_name is not None: + body["userName"] = user_name + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/preview/scim/v2/Users", body=body, headers=headers) + return User.from_dict(res) + + def delete(self, id: str): + """Deletes a user. Deleting a user from a Databricks workspace also removes objects associated with the + user. + + :param id: str + Unique ID for a user in the Databricks workspace. + + + """ + + headers = {} + + self._api.do("DELETE", f"/api/2.0/preview/scim/v2/Users/{id}", headers=headers) + + def get( + self, + id: str, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[GetSortOrder] = None, + start_index: Optional[int] = None, + ) -> User: + """Gets information for a specific user in Databricks workspace. + + :param id: str + Unique ID for a user in the Databricks workspace. + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. Multi-part paths are supported. For example, `userName`, + `name.givenName`, and `emails`. + :param sort_order: :class:`GetSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: :class:`User` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", f"/api/2.0/preview/scim/v2/Users/{id}", query=query, headers=headers) + return User.from_dict(res) + + def get_permission_levels(self) -> GetPasswordPermissionLevelsResponse: + """Gets the permission levels that a user can have on an object. + + + :returns: :class:`GetPasswordPermissionLevelsResponse` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", "/api/2.0/permissions/authorization/passwords/permissionLevels", headers=headers) + return GetPasswordPermissionLevelsResponse.from_dict(res) + + def get_permissions(self) -> PasswordPermissions: + """Gets the permissions of all passwords. Passwords can inherit permissions from their root object. + + + :returns: :class:`PasswordPermissions` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", "/api/2.0/permissions/authorization/passwords", headers=headers) + return PasswordPermissions.from_dict(res) + + def list( + self, + *, + attributes: Optional[str] = None, + count: Optional[int] = None, + excluded_attributes: Optional[str] = None, + filter: Optional[str] = None, + sort_by: Optional[str] = None, + sort_order: Optional[ListSortOrder] = None, + start_index: Optional[int] = None, + ) -> Iterator[User]: + """Gets details for all the users associated with a Databricks workspace. + + :param attributes: str (optional) + Comma-separated list of attributes to return in response. + :param count: int (optional) + Desired number of results per page. + :param excluded_attributes: str (optional) + Comma-separated list of attributes to exclude in response. + :param filter: str (optional) + Query by which the results have to be filtered. Supported operators are equals(`eq`), + contains(`co`), starts with(`sw`) and not equals(`ne`). Additionally, simple expressions can be + formed using logical operators - `and` and `or`. The [SCIM RFC] has more details but we currently + only support simple expressions. + + [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 + :param sort_by: str (optional) + Attribute to sort the results. Multi-part paths are supported. For example, `userName`, + `name.givenName`, and `emails`. + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. + + :returns: Iterator over :class:`User` + """ + + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index + headers = { + "Accept": "application/json", + } + + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do("GET", "/api/2.0/preview/scim/v2/Users", query=query, headers=headers) + if "Resources" in json: + for v in json["Resources"]: + yield User.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) + + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates a user resource by applying the supplied operations on specific user attributes. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. + + + """ + body = {} + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Users/{id}", body=body, headers=headers) + + def set_permissions( + self, *, access_control_list: Optional[List[PasswordAccessControlRequest]] = None + ) -> PasswordPermissions: + """Sets permissions on an object, replacing existing permissions if they exist. Deletes all direct + permissions if none are specified. Objects can inherit permissions from their root object. + + :param access_control_list: List[:class:`PasswordAccessControlRequest`] (optional) + + :returns: :class:`PasswordPermissions` + """ + body = {} + if access_control_list is not None: + body["access_control_list"] = [v.as_dict() for v in access_control_list] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("PUT", "/api/2.0/permissions/authorization/passwords", body=body, headers=headers) + return PasswordPermissions.from_dict(res) + + def update( + self, + id: str, + *, + active: Optional[bool] = None, + display_name: Optional[str] = None, + emails: Optional[List[ComplexValue]] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + name: Optional[Name] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[UserSchema]] = None, + user_name: Optional[str] = None, + ): + """Replaces a user's information with the data supplied in request. + + :param id: str + Databricks user ID. + :param active: bool (optional) + If this user is active + :param display_name: str (optional) + String that represents a concatenation of given and family names. For example `John Smith`. This + field cannot be updated through the Workspace SCIM APIs when [identity federation is enabled]. Use + Account SCIM APIs to update `displayName`. + + [identity federation is enabled]: https://docs.databricks.com/administration-guide/users-groups/best-practices.html#enable-identity-federation + :param emails: List[:class:`ComplexValue`] (optional) + All the emails associated with the Databricks user. + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the user. See [assigning entitlements] for a full list of supported values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + External ID is not currently supported. It is reserved for future use. + :param groups: List[:class:`ComplexValue`] (optional) + :param name: :class:`Name` (optional) + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`UserSchema`] (optional) + The schema of the user. + :param user_name: str (optional) + Email address of the Databricks user. + + + """ + body = {} + if active is not None: + body["active"] = active + if display_name is not None: + body["displayName"] = display_name + if emails is not None: + body["emails"] = [v.as_dict() for v in emails] + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if name is not None: + body["name"] = name.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] + if user_name is not None: + body["userName"] = user_name + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + self._api.do("PUT", f"/api/2.0/preview/scim/v2/Users/{id}", body=body, headers=headers) + + def update_permissions( + self, *, access_control_list: Optional[List[PasswordAccessControlRequest]] = None + ) -> PasswordPermissions: + """Updates the permissions on all passwords. Passwords can inherit permissions from their root object. + + :param access_control_list: List[:class:`PasswordAccessControlRequest`] (optional) + + :returns: :class:`PasswordPermissions` + """ + body = {} + if access_control_list is not None: + body["access_control_list"] = [v.as_dict() for v in access_control_list] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("PATCH", "/api/2.0/permissions/authorization/passwords", body=body, headers=headers) + return PasswordPermissions.from_dict(res) + + +class WorkspaceAssignmentAPI: + """The Workspace Permission Assignment API allows you to manage workspace permissions for principals in your + account.""" + + def __init__(self, api_client): + self._api = api_client + + def delete(self, workspace_id: int, principal_id: int): + """Deletes the workspace permissions assignment in a given account and workspace for the specified + principal. + + :param workspace_id: int + The workspace ID for the account. + :param principal_id: int + The ID of the user, service principal, or group. + + + """ + + headers = { + "Accept": "application/json", + } + + self._api.do( + "DELETE", + f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}", + headers=headers, + ) + + def get(self, workspace_id: int) -> WorkspacePermissions: + """Get an array of workspace permissions for the specified account and workspace. + + :param workspace_id: int + The workspace ID. + + :returns: :class:`WorkspacePermissions` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do( + "GET", + f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/permissions", + headers=headers, + ) + return WorkspacePermissions.from_dict(res) + + def list(self, workspace_id: int) -> Iterator[PermissionAssignment]: + """Get the permission assignments for the specified Databricks account and Databricks workspace. + + :param workspace_id: int + The workspace ID for the account. + + :returns: Iterator over :class:`PermissionAssignment` + """ + + headers = { + "Accept": "application/json", + } + + json = self._api.do( + "GET", + f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments", + headers=headers, + ) + parsed = PermissionAssignments.from_dict(json).permission_assignments + return parsed if parsed is not None else [] + + def update( + self, workspace_id: int, principal_id: int, *, permissions: Optional[List[WorkspacePermission]] = None + ) -> PermissionAssignment: + """Creates or updates the workspace permissions assignment in a given account and workspace for the + specified principal. + + :param workspace_id: int + The workspace ID. + :param principal_id: int + The ID of the user, service principal, or group. + :param permissions: List[:class:`WorkspacePermission`] (optional) + Array of permissions assignments to update on the workspace. Valid values are "USER" and "ADMIN" + (case-sensitive). If both "USER" and "ADMIN" are provided, "ADMIN" takes precedence. Other values + will be ignored. Note that excluding this field, or providing unsupported values, will have the same + effect as providing an empty list, which will result in the deletion of all permissions for the + principal. + + :returns: :class:`PermissionAssignment` + """ + body = {} + if permissions is not None: + body["permissions"] = [v.value for v in permissions] + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "PUT", + f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}", + body=body, + headers=headers, + ) + return PermissionAssignment.from_dict(res) + + class AccountGroupsAPI: """Groups simplify identity management, making it easier to assign access to Databricks account, data, and other securable objects. @@ -2193,9 +4522,7 @@ def list( sort_order: Optional[ListSortOrder] = None, start_index: Optional[int] = None, ) -> Iterator[Group]: - """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`. + """Gets all details of the groups associated with the Databricks account. :param attributes: str (optional) Comma-separated list of attributes to return in response. @@ -2971,27 +5298,6 @@ def update( self._api.do("PUT", f"/api/2.0/accounts/{self._api.account_id}/scim/v2/Users/{id}", body=body, headers=headers) -class CurrentUserAPI: - """This API allows retrieving information about currently authenticated user or service principal.""" - - def __init__(self, api_client): - self._api = api_client - - def me(self) -> User: - """Get details about the current method caller's identity. - - - :returns: :class:`User` - """ - - headers = { - "Accept": "application/json", - } - - res = self._api.do("GET", "/api/2.0/preview/scim/v2/Me", headers=headers) - return User.from_dict(res) - - class GroupsAPI: """Groups simplify identity management, making it easier to assign access to Databricks workspace, data, and other securable objects. @@ -3123,317 +5429,131 @@ def list( [SCIM RFC]: https://tools.ietf.org/html/rfc7644#section-3.4.2.2 :param sort_by: str (optional) Attribute to sort the results. - :param sort_order: :class:`ListSortOrder` (optional) - The order to sort the results. - :param start_index: int (optional) - Specifies the index of the first result. First item is number 1. - - :returns: Iterator over :class:`Group` - """ - - query = {} - if attributes is not None: - query["attributes"] = attributes - if count is not None: - query["count"] = count - if excluded_attributes is not None: - query["excludedAttributes"] = excluded_attributes - if filter is not None: - query["filter"] = filter - if sort_by is not None: - query["sortBy"] = sort_by - if sort_order is not None: - query["sortOrder"] = sort_order.value - if start_index is not None: - query["startIndex"] = start_index - headers = { - "Accept": "application/json", - } - - # deduplicate items that may have been added during iteration - seen = set() - query["startIndex"] = 1 - if "count" not in query: - query["count"] = 10000 - while True: - json = self._api.do("GET", "/api/2.0/preview/scim/v2/Groups", query=query, headers=headers) - if "Resources" in json: - for v in json["Resources"]: - i = v["id"] - if i in seen: - continue - seen.add(i) - yield Group.from_dict(v) - if "Resources" not in json or not json["Resources"]: - return - query["startIndex"] += len(json["Resources"]) - - def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): - """Partially updates the details of a group. - - :param id: str - Unique ID in the Databricks workspace. - :param operations: List[:class:`Patch`] (optional) - :param schemas: List[:class:`PatchSchema`] (optional) - The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. - - - """ - body = {} - if operations is not None: - body["Operations"] = [v.as_dict() for v in operations] - if schemas is not None: - body["schemas"] = [v.value for v in schemas] - headers = { - "Content-Type": "application/json", - } - - self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers) - - def update( - self, - id: str, - *, - display_name: Optional[str] = None, - entitlements: Optional[List[ComplexValue]] = None, - external_id: Optional[str] = None, - groups: Optional[List[ComplexValue]] = None, - members: Optional[List[ComplexValue]] = None, - meta: Optional[ResourceMeta] = None, - roles: Optional[List[ComplexValue]] = None, - schemas: Optional[List[GroupSchema]] = None, - ): - """Updates the details of a group by replacing the entire group entity. - - :param id: str - Databricks group ID - :param display_name: str (optional) - String that represents a human-readable group name - :param entitlements: List[:class:`ComplexValue`] (optional) - Entitlements assigned to the group. See [assigning entitlements] for a full list of supported - values. - - [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements - :param external_id: str (optional) - :param groups: List[:class:`ComplexValue`] (optional) - :param members: List[:class:`ComplexValue`] (optional) - :param meta: :class:`ResourceMeta` (optional) - Container for the group identifier. Workspace local versus account. - :param roles: List[:class:`ComplexValue`] (optional) - Corresponds to AWS instance profile/arn role. - :param schemas: List[:class:`GroupSchema`] (optional) - The schema of the group. - - - """ - body = {} - if display_name is not None: - body["displayName"] = display_name - if entitlements is not None: - body["entitlements"] = [v.as_dict() for v in entitlements] - if external_id is not None: - body["externalId"] = external_id - if groups is not None: - body["groups"] = [v.as_dict() for v in groups] - if members is not None: - body["members"] = [v.as_dict() for v in members] - if meta is not None: - body["meta"] = meta.as_dict() - if roles is not None: - body["roles"] = [v.as_dict() for v in roles] - if schemas is not None: - body["schemas"] = [v.value for v in schemas] - headers = { - "Content-Type": "application/json", - } - - self._api.do("PUT", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers) - - -class PermissionMigrationAPI: - """APIs for migrating acl permissions, used only by the ucx tool: https://github.com/databrickslabs/ucx""" - - def __init__(self, api_client): - self._api = api_client - - def migrate_permissions( - self, - workspace_id: int, - from_workspace_group_name: str, - to_account_group_name: str, - *, - size: Optional[int] = None, - ) -> MigratePermissionsResponse: - """Migrate Permissions. - - :param workspace_id: int - WorkspaceId of the associated workspace where the permission migration will occur. - :param from_workspace_group_name: str - The name of the workspace group that permissions will be migrated from. - :param to_account_group_name: str - The name of the account group that permissions will be migrated to. - :param size: int (optional) - The maximum number of permissions that will be migrated. - - :returns: :class:`MigratePermissionsResponse` - """ - body = {} - if from_workspace_group_name is not None: - body["from_workspace_group_name"] = from_workspace_group_name - if size is not None: - body["size"] = size - if to_account_group_name is not None: - body["to_account_group_name"] = to_account_group_name - if workspace_id is not None: - body["workspace_id"] = workspace_id - headers = { - "Accept": "application/json", - "Content-Type": "application/json", - } - - res = self._api.do("POST", "/api/2.0/permissionmigration", body=body, headers=headers) - return MigratePermissionsResponse.from_dict(res) - - -class PermissionsAPI: - """Permissions API are used to create read, write, edit, update and manage access for various users on - different objects and endpoints. * **[Apps permissions](:service:apps)** — Manage which users can manage - or use apps. * **[Cluster permissions](:service:clusters)** — Manage which users can manage, restart, or - attach to clusters. * **[Cluster policy permissions](:service:clusterpolicies)** — Manage which users - can use cluster policies. * **[Delta Live Tables pipeline permissions](:service:pipelines)** — Manage - which users can view, manage, run, cancel, or own a Delta Live Tables pipeline. * **[Job - permissions](:service:jobs)** — Manage which users can view, manage, trigger, cancel, or own a job. * - **[MLflow experiment permissions](:service:experiments)** — Manage which users can read, edit, or manage - MLflow experiments. * **[MLflow registered model permissions](:service:modelregistry)** — Manage which - users can read, edit, or manage MLflow registered models. * **[Instance Pool - permissions](:service:instancepools)** — Manage which users can manage or attach to pools. * **[Repo - permissions](repos)** — Manage which users can read, run, edit, or manage a repo. * **[Serving endpoint - permissions](:service:servingendpoints)** — Manage which users can view, query, or manage a serving - endpoint. * **[SQL warehouse permissions](:service:warehouses)** — Manage which users can use or manage - SQL warehouses. * **[Token permissions](:service:tokenmanagement)** — Manage which users can create or - use tokens. * **[Workspace object permissions](:service:workspace)** — Manage which users can read, run, - edit, or manage alerts, dbsql-dashboards, directories, files, notebooks and queries. For the mapping of - the required permissions for specific actions or abilities and other important information, see [Access - Control]. Note that to manage access control on service principals, use **[Account Access Control - Proxy](:service:accountaccesscontrolproxy)**. - - [Access Control]: https://docs.databricks.com/security/auth-authz/access-control/index.html""" - - def __init__(self, api_client): - self._api = api_client - - def get(self, request_object_type: str, request_object_id: str) -> ObjectPermissions: - """Gets the permissions of an object. Objects can inherit permissions from their parent objects or root - object. - - :param request_object_type: str - The type of the request object. Can be one of the following: alerts, alertsv2, authorization, - clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, - instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or - warehouses. - :param request_object_id: str - The id of the request object. - - :returns: :class:`ObjectPermissions` - """ - - headers = { - "Accept": "application/json", - } - - res = self._api.do("GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", headers=headers) - return ObjectPermissions.from_dict(res) - - def get_permission_levels(self, request_object_type: str, request_object_id: str) -> GetPermissionLevelsResponse: - """Gets the permission levels that a user can have on an object. - - :param request_object_type: str - The type of the request object. Can be one of the following: alerts, alertsv2, authorization, - clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, - instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or - warehouses. - :param request_object_id: str + :param sort_order: :class:`ListSortOrder` (optional) + The order to sort the results. + :param start_index: int (optional) + Specifies the index of the first result. First item is number 1. - :returns: :class:`GetPermissionLevelsResponse` + :returns: Iterator over :class:`Group` """ + query = {} + if attributes is not None: + query["attributes"] = attributes + if count is not None: + query["count"] = count + if excluded_attributes is not None: + query["excludedAttributes"] = excluded_attributes + if filter is not None: + query["filter"] = filter + if sort_by is not None: + query["sortBy"] = sort_by + if sort_order is not None: + query["sortOrder"] = sort_order.value + if start_index is not None: + query["startIndex"] = start_index headers = { "Accept": "application/json", } - res = self._api.do( - "GET", f"/api/2.0/permissions/{request_object_type}/{request_object_id}/permissionLevels", headers=headers - ) - return GetPermissionLevelsResponse.from_dict(res) + # deduplicate items that may have been added during iteration + seen = set() + query["startIndex"] = 1 + if "count" not in query: + query["count"] = 10000 + while True: + json = self._api.do("GET", "/api/2.0/preview/scim/v2/Groups", query=query, headers=headers) + if "Resources" in json: + for v in json["Resources"]: + i = v["id"] + if i in seen: + continue + seen.add(i) + yield Group.from_dict(v) + if "Resources" not in json or not json["Resources"]: + return + query["startIndex"] += len(json["Resources"]) - def set( - self, - request_object_type: str, - request_object_id: str, - *, - access_control_list: Optional[List[AccessControlRequest]] = None, - ) -> ObjectPermissions: - """Sets permissions on an object, replacing existing permissions if they exist. Deletes all direct - permissions if none are specified. Objects can inherit permissions from their parent objects or root - object. + def patch(self, id: str, *, operations: Optional[List[Patch]] = None, schemas: Optional[List[PatchSchema]] = None): + """Partially updates the details of a group. + + :param id: str + Unique ID in the Databricks workspace. + :param operations: List[:class:`Patch`] (optional) + :param schemas: List[:class:`PatchSchema`] (optional) + The schema of the patch request. Must be ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. - :param request_object_type: str - The type of the request object. Can be one of the following: alerts, alertsv2, authorization, - clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, - instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or - warehouses. - :param request_object_id: str - The id of the request object. - :param access_control_list: List[:class:`AccessControlRequest`] (optional) - :returns: :class:`ObjectPermissions` """ body = {} - if access_control_list is not None: - body["access_control_list"] = [v.as_dict() for v in access_control_list] + if operations is not None: + body["Operations"] = [v.as_dict() for v in operations] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] headers = { - "Accept": "application/json", "Content-Type": "application/json", } - res = self._api.do( - "PUT", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers - ) - return ObjectPermissions.from_dict(res) + self._api.do("PATCH", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers) def update( self, - request_object_type: str, - request_object_id: str, + id: str, *, - access_control_list: Optional[List[AccessControlRequest]] = None, - ) -> ObjectPermissions: - """Updates the permissions on an object. Objects can inherit permissions from their parent objects or - root object. + display_name: Optional[str] = None, + entitlements: Optional[List[ComplexValue]] = None, + external_id: Optional[str] = None, + groups: Optional[List[ComplexValue]] = None, + members: Optional[List[ComplexValue]] = None, + meta: Optional[ResourceMeta] = None, + roles: Optional[List[ComplexValue]] = None, + schemas: Optional[List[GroupSchema]] = None, + ): + """Updates the details of a group by replacing the entire group entity. + + :param id: str + Databricks group ID + :param display_name: str (optional) + String that represents a human-readable group name + :param entitlements: List[:class:`ComplexValue`] (optional) + Entitlements assigned to the group. See [assigning entitlements] for a full list of supported + values. + + [assigning entitlements]: https://docs.databricks.com/administration-guide/users-groups/index.html#assigning-entitlements + :param external_id: str (optional) + :param groups: List[:class:`ComplexValue`] (optional) + :param members: List[:class:`ComplexValue`] (optional) + :param meta: :class:`ResourceMeta` (optional) + Container for the group identifier. Workspace local versus account. + :param roles: List[:class:`ComplexValue`] (optional) + Corresponds to AWS instance profile/arn role. + :param schemas: List[:class:`GroupSchema`] (optional) + The schema of the group. - :param request_object_type: str - The type of the request object. Can be one of the following: alerts, alertsv2, authorization, - clusters, cluster-policies, dashboards, dbsql-dashboards, directories, experiments, files, - instance-pools, jobs, notebooks, pipelines, queries, registered-models, repos, serving-endpoints, or - warehouses. - :param request_object_id: str - The id of the request object. - :param access_control_list: List[:class:`AccessControlRequest`] (optional) - :returns: :class:`ObjectPermissions` """ body = {} - if access_control_list is not None: - body["access_control_list"] = [v.as_dict() for v in access_control_list] + if display_name is not None: + body["displayName"] = display_name + if entitlements is not None: + body["entitlements"] = [v.as_dict() for v in entitlements] + if external_id is not None: + body["externalId"] = external_id + if groups is not None: + body["groups"] = [v.as_dict() for v in groups] + if members is not None: + body["members"] = [v.as_dict() for v in members] + if meta is not None: + body["meta"] = meta.as_dict() + if roles is not None: + body["roles"] = [v.as_dict() for v in roles] + if schemas is not None: + body["schemas"] = [v.value for v in schemas] headers = { - "Accept": "application/json", "Content-Type": "application/json", } - res = self._api.do( - "PATCH", f"/api/2.0/permissions/{request_object_type}/{request_object_id}", body=body, headers=headers - ) - return ObjectPermissions.from_dict(res) + self._api.do("PUT", f"/api/2.0/preview/scim/v2/Groups/{id}", body=body, headers=headers) class ServicePrincipalsAPI: @@ -4102,109 +6222,3 @@ def update_permissions( res = self._api.do("PATCH", "/api/2.0/permissions/authorization/passwords", body=body, headers=headers) return PasswordPermissions.from_dict(res) - - -class WorkspaceAssignmentAPI: - """The Workspace Permission Assignment API allows you to manage workspace permissions for principals in your - account.""" - - def __init__(self, api_client): - self._api = api_client - - def delete(self, workspace_id: int, principal_id: int): - """Deletes the workspace permissions assignment in a given account and workspace for the specified - principal. - - :param workspace_id: int - The workspace ID for the account. - :param principal_id: int - The ID of the user, service principal, or group. - - - """ - - headers = { - "Accept": "application/json", - } - - self._api.do( - "DELETE", - f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}", - headers=headers, - ) - - def get(self, workspace_id: int) -> WorkspacePermissions: - """Get an array of workspace permissions for the specified account and workspace. - - :param workspace_id: int - The workspace ID. - - :returns: :class:`WorkspacePermissions` - """ - - headers = { - "Accept": "application/json", - } - - res = self._api.do( - "GET", - f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/permissions", - headers=headers, - ) - return WorkspacePermissions.from_dict(res) - - def list(self, workspace_id: int) -> Iterator[PermissionAssignment]: - """Get the permission assignments for the specified Databricks account and Databricks workspace. - - :param workspace_id: int - The workspace ID for the account. - - :returns: Iterator over :class:`PermissionAssignment` - """ - - headers = { - "Accept": "application/json", - } - - json = self._api.do( - "GET", - f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments", - headers=headers, - ) - parsed = PermissionAssignments.from_dict(json).permission_assignments - return parsed if parsed is not None else [] - - def update( - self, workspace_id: int, principal_id: int, *, permissions: Optional[List[WorkspacePermission]] = None - ) -> PermissionAssignment: - """Creates or updates the workspace permissions assignment in a given account and workspace for the - specified principal. - - :param workspace_id: int - The workspace ID. - :param principal_id: int - The ID of the user, service principal, or group. - :param permissions: List[:class:`WorkspacePermission`] (optional) - Array of permissions assignments to update on the workspace. Valid values are "USER" and "ADMIN" - (case-sensitive). If both "USER" and "ADMIN" are provided, "ADMIN" takes precedence. Other values - will be ignored. Note that excluding this field, or providing unsupported values, will have the same - effect as providing an empty list, which will result in the deletion of all permissions for the - principal. - - :returns: :class:`PermissionAssignment` - """ - body = {} - if permissions is not None: - body["permissions"] = [v.value for v in permissions] - headers = { - "Accept": "application/json", - "Content-Type": "application/json", - } - - res = self._api.do( - "PUT", - f"/api/2.0/accounts/{self._api.account_id}/workspaces/{workspace_id}/permissionassignments/principals/{principal_id}", - body=body, - headers=headers, - ) - return PermissionAssignment.from_dict(res) diff --git a/databricks/sdk/service/iamv2.py b/databricks/sdk/service/iamv2.py new file mode 100755 index 000000000..25cd2ad25 --- /dev/null +++ b/databricks/sdk/service/iamv2.py @@ -0,0 +1,643 @@ +# Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +from __future__ import annotations + +import logging +from dataclasses import dataclass +from enum import Enum +from typing import Any, Dict, List, Optional + +from ._internal import _enum, _from_dict, _repeated_enum + +_LOG = logging.getLogger("databricks.sdk") + + +# all definitions in this file are in alphabetical order + + +@dataclass +class Group: + """The details of a Group resource.""" + + account_id: Optional[str] = None + """The parent account ID for group in Databricks.""" + + external_id: Optional[str] = None + """ExternalId of the group in the customer's IdP.""" + + group_name: Optional[str] = None + """Display name of the group.""" + + internal_id: Optional[int] = None + """Internal group ID of the group in Databricks.""" + + def as_dict(self) -> dict: + """Serializes the Group into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.external_id is not None: + body["external_id"] = self.external_id + if self.group_name is not None: + body["group_name"] = self.group_name + if self.internal_id is not None: + body["internal_id"] = self.internal_id + return body + + def as_shallow_dict(self) -> dict: + """Serializes the Group into a shallow dictionary of its immediate attributes.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.external_id is not None: + body["external_id"] = self.external_id + if self.group_name is not None: + body["group_name"] = self.group_name + if self.internal_id is not None: + body["internal_id"] = self.internal_id + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> Group: + """Deserializes the Group from a dictionary.""" + return cls( + account_id=d.get("account_id", None), + external_id=d.get("external_id", None), + group_name=d.get("group_name", None), + internal_id=d.get("internal_id", None), + ) + + +class PrincipalType(Enum): + """The type of the principal (user/sp/group).""" + + GROUP = "GROUP" + SERVICE_PRINCIPAL = "SERVICE_PRINCIPAL" + USER = "USER" + + +@dataclass +class ResolveGroupResponse: + group: Optional[Group] = None + """The group that was resolved.""" + + def as_dict(self) -> dict: + """Serializes the ResolveGroupResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.group: + body["group"] = self.group.as_dict() + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ResolveGroupResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.group: + body["group"] = self.group + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ResolveGroupResponse: + """Deserializes the ResolveGroupResponse from a dictionary.""" + return cls(group=_from_dict(d, "group", Group)) + + +@dataclass +class ResolveServicePrincipalResponse: + service_principal: Optional[ServicePrincipal] = None + """The service principal that was resolved.""" + + def as_dict(self) -> dict: + """Serializes the ResolveServicePrincipalResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.service_principal: + body["service_principal"] = self.service_principal.as_dict() + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ResolveServicePrincipalResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.service_principal: + body["service_principal"] = self.service_principal + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ResolveServicePrincipalResponse: + """Deserializes the ResolveServicePrincipalResponse from a dictionary.""" + return cls(service_principal=_from_dict(d, "service_principal", ServicePrincipal)) + + +@dataclass +class ResolveUserResponse: + user: Optional[User] = None + """The user that was resolved.""" + + def as_dict(self) -> dict: + """Serializes the ResolveUserResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.user: + body["user"] = self.user.as_dict() + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ResolveUserResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.user: + body["user"] = self.user + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ResolveUserResponse: + """Deserializes the ResolveUserResponse from a dictionary.""" + return cls(user=_from_dict(d, "user", User)) + + +@dataclass +class ServicePrincipal: + """The details of a ServicePrincipal resource.""" + + account_id: Optional[str] = None + """The parent account ID for the service principal in Databricks.""" + + account_sp_status: Optional[State] = None + """The activity status of a service principal in a Databricks account.""" + + application_id: Optional[str] = None + """Application ID of the service principal.""" + + display_name: Optional[str] = None + """Display name of the service principal.""" + + external_id: Optional[str] = None + """ExternalId of the service principal in the customer's IdP.""" + + internal_id: Optional[int] = None + """Internal service principal ID of the service principal in Databricks.""" + + def as_dict(self) -> dict: + """Serializes the ServicePrincipal into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.account_sp_status is not None: + body["account_sp_status"] = self.account_sp_status.value + if self.application_id is not None: + body["application_id"] = self.application_id + if self.display_name is not None: + body["display_name"] = self.display_name + if self.external_id is not None: + body["external_id"] = self.external_id + if self.internal_id is not None: + body["internal_id"] = self.internal_id + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ServicePrincipal into a shallow dictionary of its immediate attributes.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.account_sp_status is not None: + body["account_sp_status"] = self.account_sp_status + if self.application_id is not None: + body["application_id"] = self.application_id + if self.display_name is not None: + body["display_name"] = self.display_name + if self.external_id is not None: + body["external_id"] = self.external_id + if self.internal_id is not None: + body["internal_id"] = self.internal_id + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ServicePrincipal: + """Deserializes the ServicePrincipal from a dictionary.""" + return cls( + account_id=d.get("account_id", None), + account_sp_status=_enum(d, "account_sp_status", State), + application_id=d.get("application_id", None), + display_name=d.get("display_name", None), + external_id=d.get("external_id", None), + internal_id=d.get("internal_id", None), + ) + + +class State(Enum): + """The activity status of a user or service principal in a Databricks account or workspace.""" + + ACTIVE = "ACTIVE" + INACTIVE = "INACTIVE" + + +@dataclass +class User: + """The details of a User resource.""" + + username: str + """Username/email of the user.""" + + account_id: Optional[str] = None + """The accountId parent of the user in Databricks.""" + + account_user_status: Optional[State] = None + """The activity status of a user in a Databricks account.""" + + external_id: Optional[str] = None + """ExternalId of the user in the customer's IdP.""" + + internal_id: Optional[int] = None + """Internal userId of the user in Databricks.""" + + name: Optional[UserName] = None + + def as_dict(self) -> dict: + """Serializes the User into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.account_user_status is not None: + body["account_user_status"] = self.account_user_status.value + if self.external_id is not None: + body["external_id"] = self.external_id + if self.internal_id is not None: + body["internal_id"] = self.internal_id + if self.name: + body["name"] = self.name.as_dict() + if self.username is not None: + body["username"] = self.username + return body + + def as_shallow_dict(self) -> dict: + """Serializes the User into a shallow dictionary of its immediate attributes.""" + body = {} + if self.account_id is not None: + body["account_id"] = self.account_id + if self.account_user_status is not None: + body["account_user_status"] = self.account_user_status + if self.external_id is not None: + body["external_id"] = self.external_id + if self.internal_id is not None: + body["internal_id"] = self.internal_id + if self.name: + body["name"] = self.name + if self.username is not None: + body["username"] = self.username + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> User: + """Deserializes the User from a dictionary.""" + return cls( + account_id=d.get("account_id", None), + account_user_status=_enum(d, "account_user_status", State), + external_id=d.get("external_id", None), + internal_id=d.get("internal_id", None), + name=_from_dict(d, "name", UserName), + username=d.get("username", None), + ) + + +@dataclass +class UserName: + family_name: Optional[str] = None + + given_name: Optional[str] = None + + def as_dict(self) -> dict: + """Serializes the UserName into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.family_name is not None: + body["family_name"] = self.family_name + if self.given_name is not None: + body["given_name"] = self.given_name + return body + + def as_shallow_dict(self) -> dict: + """Serializes the UserName into a shallow dictionary of its immediate attributes.""" + body = {} + if self.family_name is not None: + body["family_name"] = self.family_name + if self.given_name is not None: + body["given_name"] = self.given_name + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> UserName: + """Deserializes the UserName from a dictionary.""" + return cls(family_name=d.get("family_name", None), given_name=d.get("given_name", None)) + + +@dataclass +class WorkspaceAccessDetail: + """The details of a principal's access to a workspace.""" + + access_type: Optional[WorkspaceAccessDetailAccessType] = None + + account_id: Optional[str] = None + """The account ID parent of the workspace where the principal has access.""" + + permissions: Optional[List[WorkspacePermission]] = None + """The permissions granted to the principal in the workspace.""" + + principal_id: Optional[int] = None + """The internal ID of the principal (user/sp/group) in Databricks.""" + + principal_type: Optional[PrincipalType] = None + + status: Optional[State] = None + """The activity status of the principal in the workspace. Not applicable for groups at the moment.""" + + workspace_id: Optional[int] = None + """The workspace ID where the principal has access.""" + + def as_dict(self) -> dict: + """Serializes the WorkspaceAccessDetail into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.access_type is not None: + body["access_type"] = self.access_type.value + if self.account_id is not None: + body["account_id"] = self.account_id + if self.permissions: + body["permissions"] = [v.value for v in self.permissions] + if self.principal_id is not None: + body["principal_id"] = self.principal_id + if self.principal_type is not None: + body["principal_type"] = self.principal_type.value + if self.status is not None: + body["status"] = self.status.value + if self.workspace_id is not None: + body["workspace_id"] = self.workspace_id + return body + + def as_shallow_dict(self) -> dict: + """Serializes the WorkspaceAccessDetail into a shallow dictionary of its immediate attributes.""" + body = {} + if self.access_type is not None: + body["access_type"] = self.access_type + if self.account_id is not None: + body["account_id"] = self.account_id + if self.permissions: + body["permissions"] = self.permissions + if self.principal_id is not None: + body["principal_id"] = self.principal_id + if self.principal_type is not None: + body["principal_type"] = self.principal_type + if self.status is not None: + body["status"] = self.status + if self.workspace_id is not None: + body["workspace_id"] = self.workspace_id + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> WorkspaceAccessDetail: + """Deserializes the WorkspaceAccessDetail from a dictionary.""" + return cls( + access_type=_enum(d, "access_type", WorkspaceAccessDetailAccessType), + account_id=d.get("account_id", None), + permissions=_repeated_enum(d, "permissions", WorkspacePermission), + principal_id=d.get("principal_id", None), + principal_type=_enum(d, "principal_type", PrincipalType), + status=_enum(d, "status", State), + workspace_id=d.get("workspace_id", None), + ) + + +class WorkspaceAccessDetailAccessType(Enum): + """The type of access the principal has to the workspace.""" + + DIRECT = "DIRECT" + INDIRECT = "INDIRECT" + + +class WorkspaceAccessDetailView(Enum): + """Controls what fields are returned in the GetWorkspaceAccessDetail response.""" + + BASIC = "BASIC" + FULL = "FULL" + + +class WorkspacePermission(Enum): + """The type of permission a principal has to a workspace (admin/user).""" + + ADMIN_PERMISSION = "ADMIN_PERMISSION" + USER_PERMISSION = "USER_PERMISSION" + + +class AccountIamV2API: + """These APIs are used to manage identities and the workspace access of these identities in .""" + + def __init__(self, api_client): + self._api = api_client + + def get_workspace_access_detail( + self, workspace_id: int, principal_id: int, *, view: Optional[WorkspaceAccessDetailView] = None + ) -> WorkspaceAccessDetail: + """Returns the access details for a principal in a workspace. Allows for checking access details for any + provisioned principal (user, service principal, or group) in a workspace. * Provisioned principal here + refers to one that has been synced into Databricks from the customer's IdP or added explicitly to + Databricks via SCIM/UI. Allows for passing in a "view" parameter to control what fields are returned + (BASIC by default or FULL). + + :param workspace_id: int + Required. The workspace ID for which the access details are being requested. + :param principal_id: int + Required. The internal ID of the principal (user/sp/group) for which the access details are being + requested. + :param view: :class:`WorkspaceAccessDetailView` (optional) + Controls what fields are returned. + + :returns: :class:`WorkspaceAccessDetail` + """ + + query = {} + if view is not None: + query["view"] = view.value + headers = { + "Accept": "application/json", + } + + res = self._api.do( + "GET", + f"/api/2.0/identity/accounts/{self._api.account_id}/workspaces/{workspace_id}/workspaceAccessDetails/{principal_id}", + query=query, + headers=headers, + ) + return WorkspaceAccessDetail.from_dict(res) + + def resolve_group(self, external_id: str) -> ResolveGroupResponse: + """Resolves a group with the given external ID from the customer's IdP. If the group does not exist, it + will be created in the account. If the customer is not onboarded onto Automatic Identity Management + (AIM), this will return an error. + + :param external_id: str + Required. The external ID of the group in the customer's IdP. + + :returns: :class:`ResolveGroupResponse` + """ + body = {} + if external_id is not None: + body["external_id"] = external_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", + f"/api/2.0/identity/accounts/{self._api.account_id}/groups/resolveByExternalId", + body=body, + headers=headers, + ) + return ResolveGroupResponse.from_dict(res) + + def resolve_service_principal(self, external_id: str) -> ResolveServicePrincipalResponse: + """Resolves an SP with the given external ID from the customer's IdP. If the SP does not exist, it will + be created. If the customer is not onboarded onto Automatic Identity Management (AIM), this will + return an error. + + :param external_id: str + Required. The external ID of the service principal in the customer's IdP. + + :returns: :class:`ResolveServicePrincipalResponse` + """ + body = {} + if external_id is not None: + body["external_id"] = external_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", + f"/api/2.0/identity/accounts/{self._api.account_id}/servicePrincipals/resolveByExternalId", + body=body, + headers=headers, + ) + return ResolveServicePrincipalResponse.from_dict(res) + + def resolve_user(self, external_id: str) -> ResolveUserResponse: + """Resolves a user with the given external ID from the customer's IdP. If the user does not exist, it + will be created. If the customer is not onboarded onto Automatic Identity Management (AIM), this will + return an error. + + :param external_id: str + Required. The external ID of the user in the customer's IdP. + + :returns: :class:`ResolveUserResponse` + """ + body = {} + if external_id is not None: + body["external_id"] = external_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", + f"/api/2.0/identity/accounts/{self._api.account_id}/users/resolveByExternalId", + body=body, + headers=headers, + ) + return ResolveUserResponse.from_dict(res) + + +class WorkspaceIamV2API: + """These APIs are used to manage identities and the workspace access of these identities in .""" + + def __init__(self, api_client): + self._api = api_client + + def get_workspace_access_detail_local( + self, principal_id: int, *, view: Optional[WorkspaceAccessDetailView] = None + ) -> WorkspaceAccessDetail: + """Returns the access details for a principal in the current workspace. Allows for checking access + details for any provisioned principal (user, service principal, or group) in the current workspace. * + Provisioned principal here refers to one that has been synced into Databricks from the customer's IdP + or added explicitly to Databricks via SCIM/UI. Allows for passing in a "view" parameter to control + what fields are returned (BASIC by default or FULL). + + :param principal_id: int + Required. The internal ID of the principal (user/sp/group) for which the access details are being + requested. + :param view: :class:`WorkspaceAccessDetailView` (optional) + Controls what fields are returned. + + :returns: :class:`WorkspaceAccessDetail` + """ + + query = {} + if view is not None: + query["view"] = view.value + headers = { + "Accept": "application/json", + } + + res = self._api.do( + "GET", f"/api/2.0/identity/workspaceAccessDetails/{principal_id}", query=query, headers=headers + ) + return WorkspaceAccessDetail.from_dict(res) + + def resolve_group_proxy(self, external_id: str) -> ResolveGroupResponse: + """Resolves a group with the given external ID from the customer's IdP. If the group does not exist, it + will be created in the account. If the customer is not onboarded onto Automatic Identity Management + (AIM), this will return an error. + + :param external_id: str + Required. The external ID of the group in the customer's IdP. + + :returns: :class:`ResolveGroupResponse` + """ + body = {} + if external_id is not None: + body["external_id"] = external_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/identity/groups/resolveByExternalId", body=body, headers=headers) + return ResolveGroupResponse.from_dict(res) + + def resolve_service_principal_proxy(self, external_id: str) -> ResolveServicePrincipalResponse: + """Resolves an SP with the given external ID from the customer's IdP. If the SP does not exist, it will + be created. If the customer is not onboarded onto Automatic Identity Management (AIM), this will + return an error. + + :param external_id: str + Required. The external ID of the service principal in the customer's IdP. + + :returns: :class:`ResolveServicePrincipalResponse` + """ + body = {} + if external_id is not None: + body["external_id"] = external_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "POST", "/api/2.0/identity/servicePrincipals/resolveByExternalId", body=body, headers=headers + ) + return ResolveServicePrincipalResponse.from_dict(res) + + def resolve_user_proxy(self, external_id: str) -> ResolveUserResponse: + """Resolves a user with the given external ID from the customer's IdP. If the user does not exist, it + will be created. If the customer is not onboarded onto Automatic Identity Management (AIM), this will + return an error. + + :param external_id: str + Required. The external ID of the user in the customer's IdP. + + :returns: :class:`ResolveUserResponse` + """ + body = {} + if external_id is not None: + body["external_id"] = external_id + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/identity/users/resolveByExternalId", body=body, headers=headers) + return ResolveUserResponse.from_dict(res) diff --git a/databricks/sdk/service/jobs.py b/databricks/sdk/service/jobs.py index 9f023448b..4445c2310 100755 --- a/databricks/sdk/service/jobs.py +++ b/databricks/sdk/service/jobs.py @@ -5696,9 +5696,6 @@ class RunTask: description: Optional[str] = None """An optional description for this task.""" - disabled: Optional[bool] = None - """Deprecated, field was never used in production.""" - effective_performance_target: Optional[PerformanceTarget] = None """The actual performance target used by the serverless run during execution. This can differ from the client-set performance target on the request depending on whether the performance mode is @@ -5873,8 +5870,6 @@ def as_dict(self) -> dict: body["depends_on"] = [v.as_dict() for v in self.depends_on] if self.description is not None: body["description"] = self.description - if self.disabled is not None: - body["disabled"] = self.disabled if self.effective_performance_target is not None: body["effective_performance_target"] = self.effective_performance_target.value if self.email_notifications: @@ -5972,8 +5967,6 @@ def as_shallow_dict(self) -> dict: body["depends_on"] = self.depends_on if self.description is not None: body["description"] = self.description - if self.disabled is not None: - body["disabled"] = self.disabled if self.effective_performance_target is not None: body["effective_performance_target"] = self.effective_performance_target if self.email_notifications: @@ -6061,7 +6054,6 @@ def from_dict(cls, d: Dict[str, Any]) -> RunTask: dbt_task=_from_dict(d, "dbt_task", DbtTask), depends_on=_repeated_dict(d, "depends_on", TaskDependency), description=d.get("description", None), - disabled=d.get("disabled", None), effective_performance_target=_enum(d, "effective_performance_target", PerformanceTarget), email_notifications=_from_dict(d, "email_notifications", JobEmailNotifications), end_time=d.get("end_time", None), @@ -7438,6 +7430,10 @@ class Task: disable_auto_optimization: Optional[bool] = None """An option to disable auto optimization in serverless""" + disabled: Optional[bool] = None + """An optional flag to disable the task. If set to true, the task will not run even if it is part + of a job.""" + email_notifications: Optional[TaskEmailNotifications] = None """An optional set of email addresses that is notified when runs of this task begin or complete as well as when this task is deleted. The default behavior is to not send any emails.""" @@ -7568,6 +7564,8 @@ def as_dict(self) -> dict: body["description"] = self.description if self.disable_auto_optimization is not None: body["disable_auto_optimization"] = self.disable_auto_optimization + if self.disabled is not None: + body["disabled"] = self.disabled if self.email_notifications: body["email_notifications"] = self.email_notifications.as_dict() if self.environment_key is not None: @@ -7643,6 +7641,8 @@ def as_shallow_dict(self) -> dict: body["description"] = self.description if self.disable_auto_optimization is not None: body["disable_auto_optimization"] = self.disable_auto_optimization + if self.disabled is not None: + body["disabled"] = self.disabled if self.email_notifications: body["email_notifications"] = self.email_notifications if self.environment_key is not None: @@ -7710,6 +7710,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Task: depends_on=_repeated_dict(d, "depends_on", TaskDependency), description=d.get("description", None), disable_auto_optimization=d.get("disable_auto_optimization", None), + disabled=d.get("disabled", None), email_notifications=_from_dict(d, "email_notifications", TaskEmailNotifications), environment_key=d.get("environment_key", None), existing_cluster_id=d.get("existing_cluster_id", None), diff --git a/databricks/sdk/service/ml.py b/databricks/sdk/service/ml.py index 6ca964fd4..6a132360c 100755 --- a/databricks/sdk/service/ml.py +++ b/databricks/sdk/service/ml.py @@ -512,6 +512,30 @@ def from_dict(cls, d: Dict[str, Any]) -> CreateWebhookResponse: return cls(webhook=_from_dict(d, "webhook", RegistryWebhook)) +@dataclass +class DataSource: + delta_table_source: Optional[DeltaTableSource] = None + + def as_dict(self) -> dict: + """Serializes the DataSource into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.delta_table_source: + body["delta_table_source"] = self.delta_table_source.as_dict() + return body + + def as_shallow_dict(self) -> dict: + """Serializes the DataSource into a shallow dictionary of its immediate attributes.""" + body = {} + if self.delta_table_source: + body["delta_table_source"] = self.delta_table_source + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> DataSource: + """Deserializes the DataSource from a dictionary.""" + return cls(delta_table_source=_from_dict(d, "delta_table_source", DeltaTableSource)) + + @dataclass class Dataset: """Dataset. Represents a reference to data used for training, testing, or evaluation during the @@ -868,6 +892,49 @@ def from_dict(cls, d: Dict[str, Any]) -> DeleteWebhookResponse: return cls() +@dataclass +class DeltaTableSource: + full_name: str + """The full three-part (catalog, schema, table) name of the Delta table.""" + + entity_columns: List[str] + """The entity columns of the Delta table.""" + + timeseries_column: str + """The timeseries column of the Delta table.""" + + def as_dict(self) -> dict: + """Serializes the DeltaTableSource into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.entity_columns: + body["entity_columns"] = [v for v in self.entity_columns] + if self.full_name is not None: + body["full_name"] = self.full_name + if self.timeseries_column is not None: + body["timeseries_column"] = self.timeseries_column + return body + + def as_shallow_dict(self) -> dict: + """Serializes the DeltaTableSource into a shallow dictionary of its immediate attributes.""" + body = {} + if self.entity_columns: + body["entity_columns"] = self.entity_columns + if self.full_name is not None: + body["full_name"] = self.full_name + if self.timeseries_column is not None: + body["timeseries_column"] = self.timeseries_column + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> DeltaTableSource: + """Deserializes the DeltaTableSource from a dictionary.""" + return cls( + entity_columns=d.get("entity_columns", None), + full_name=d.get("full_name", None), + timeseries_column=d.get("timeseries_column", None), + ) + + @dataclass class Experiment: """An experiment and its metadata.""" @@ -1210,6 +1277,73 @@ def from_dict(cls, d: Dict[str, Any]) -> ExperimentTag: return cls(key=d.get("key", None), value=d.get("value", None)) +@dataclass +class Feature: + full_name: str + """The full three-part name (catalog, schema, name) of the feature.""" + + source: DataSource + """The data source of the feature.""" + + inputs: List[str] + """The input columns from which the feature is computed.""" + + function: Function + """The function by which the feature is computed.""" + + time_window: TimeWindow + """The time window in which the feature is computed.""" + + description: Optional[str] = None + """The description of the feature.""" + + def as_dict(self) -> dict: + """Serializes the Feature into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.description is not None: + body["description"] = self.description + if self.full_name is not None: + body["full_name"] = self.full_name + if self.function: + body["function"] = self.function.as_dict() + if self.inputs: + body["inputs"] = [v for v in self.inputs] + if self.source: + body["source"] = self.source.as_dict() + if self.time_window: + body["time_window"] = self.time_window.as_dict() + return body + + def as_shallow_dict(self) -> dict: + """Serializes the Feature into a shallow dictionary of its immediate attributes.""" + body = {} + if self.description is not None: + body["description"] = self.description + if self.full_name is not None: + body["full_name"] = self.full_name + if self.function: + body["function"] = self.function + if self.inputs: + body["inputs"] = self.inputs + if self.source: + body["source"] = self.source + if self.time_window: + body["time_window"] = self.time_window + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> Feature: + """Deserializes the Feature from a dictionary.""" + return cls( + description=d.get("description", None), + full_name=d.get("full_name", None), + function=_from_dict(d, "function", Function), + inputs=d.get("inputs", None), + source=_from_dict(d, "source", DataSource), + time_window=_from_dict(d, "time_window", TimeWindow), + ) + + @dataclass class FeatureLineage: feature_specs: Optional[List[FeatureLineageFeatureSpec]] = None @@ -1520,6 +1654,90 @@ class ForecastingExperimentState(Enum): SUCCEEDED = "SUCCEEDED" +@dataclass +class Function: + function_type: FunctionFunctionType + """The type of the function.""" + + extra_parameters: Optional[List[FunctionExtraParameter]] = None + """Extra parameters for parameterized functions.""" + + def as_dict(self) -> dict: + """Serializes the Function into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.extra_parameters: + body["extra_parameters"] = [v.as_dict() for v in self.extra_parameters] + if self.function_type is not None: + body["function_type"] = self.function_type.value + return body + + def as_shallow_dict(self) -> dict: + """Serializes the Function into a shallow dictionary of its immediate attributes.""" + body = {} + if self.extra_parameters: + body["extra_parameters"] = self.extra_parameters + if self.function_type is not None: + body["function_type"] = self.function_type + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> Function: + """Deserializes the Function from a dictionary.""" + return cls( + extra_parameters=_repeated_dict(d, "extra_parameters", FunctionExtraParameter), + function_type=_enum(d, "function_type", FunctionFunctionType), + ) + + +@dataclass +class FunctionExtraParameter: + key: str + """The name of the parameter.""" + + value: str + """The value of the parameter.""" + + def as_dict(self) -> dict: + """Serializes the FunctionExtraParameter into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.key is not None: + body["key"] = self.key + if self.value is not None: + body["value"] = self.value + return body + + def as_shallow_dict(self) -> dict: + """Serializes the FunctionExtraParameter into a shallow dictionary of its immediate attributes.""" + body = {} + if self.key is not None: + body["key"] = self.key + if self.value is not None: + body["value"] = self.value + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> FunctionExtraParameter: + """Deserializes the FunctionExtraParameter from a dictionary.""" + return cls(key=d.get("key", None), value=d.get("value", None)) + + +class FunctionFunctionType(Enum): + + APPROX_COUNT_DISTINCT = "APPROX_COUNT_DISTINCT" + APPROX_PERCENTILE = "APPROX_PERCENTILE" + AVG = "AVG" + COUNT = "COUNT" + FIRST = "FIRST" + LAST = "LAST" + MAX = "MAX" + MIN = "MIN" + STDDEV_POP = "STDDEV_POP" + STDDEV_SAMP = "STDDEV_SAMP" + SUM = "SUM" + VAR_POP = "VAR_POP" + VAR_SAMP = "VAR_SAMP" + + @dataclass class GetExperimentByNameResponse: experiment: Optional[Experiment] = None @@ -2167,6 +2385,38 @@ def from_dict(cls, d: Dict[str, Any]) -> ListFeatureTagsResponse: ) +@dataclass +class ListFeaturesResponse: + features: Optional[List[Feature]] = None + """List of features.""" + + next_page_token: Optional[str] = None + """Pagination token to request the next page of results for this query.""" + + def as_dict(self) -> dict: + """Serializes the ListFeaturesResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.features: + body["features"] = [v.as_dict() for v in self.features] + 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 ListFeaturesResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.features: + body["features"] = self.features + 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]) -> ListFeaturesResponse: + """Deserializes the ListFeaturesResponse from a dictionary.""" + return cls(features=_repeated_dict(d, "features", Feature), next_page_token=d.get("next_page_token", None)) + + @dataclass class ListModelsResponse: next_page_token: Optional[str] = None @@ -4734,6 +4984,38 @@ def from_dict(cls, d: Dict[str, Any]) -> TestRegistryWebhookResponse: return cls(body=d.get("body", None), status_code=d.get("status_code", None)) +@dataclass +class TimeWindow: + duration: str + """The duration of the time window.""" + + offset: Optional[str] = None + """The offset of the time window.""" + + def as_dict(self) -> dict: + """Serializes the TimeWindow into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.duration is not None: + body["duration"] = self.duration + if self.offset is not None: + body["offset"] = self.offset + return body + + def as_shallow_dict(self) -> dict: + """Serializes the TimeWindow into a shallow dictionary of its immediate attributes.""" + body = {} + if self.duration is not None: + body["duration"] = self.duration + if self.offset is not None: + body["offset"] = self.offset + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> TimeWindow: + """Deserializes the TimeWindow from a dictionary.""" + return cls(duration=d.get("duration", None), offset=d.get("offset", None)) + + @dataclass class TransitionRequest: """For activities, this contains the activity recorded for the action. For comments, this contains @@ -6256,6 +6538,116 @@ def update_run( return UpdateRunResponse.from_dict(res) +class FeatureEngineeringAPI: + """[description]""" + + def __init__(self, api_client): + self._api = api_client + + def create_feature(self, feature: Feature) -> Feature: + """Create a Feature. + + :param feature: :class:`Feature` + Feature to create. + + :returns: :class:`Feature` + """ + body = feature.as_dict() + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do("POST", "/api/2.0/feature-engineering/features", body=body, headers=headers) + return Feature.from_dict(res) + + def delete_feature(self, full_name: str): + """Delete a Feature. + + :param full_name: str + Name of the feature to delete. + + + """ + + headers = { + "Accept": "application/json", + } + + self._api.do("DELETE", f"/api/2.0/feature-engineering/features/{full_name}", headers=headers) + + def get_feature(self, full_name: str) -> Feature: + """Get a Feature. + + :param full_name: str + Name of the feature to get. + + :returns: :class:`Feature` + """ + + headers = { + "Accept": "application/json", + } + + res = self._api.do("GET", f"/api/2.0/feature-engineering/features/{full_name}", headers=headers) + return Feature.from_dict(res) + + def list_features(self, *, page_size: Optional[int] = None, page_token: Optional[str] = None) -> Iterator[Feature]: + """List Features. + + :param page_size: int (optional) + The maximum number of results to return. + :param page_token: str (optional) + Pagination token to go to the next page based on a previous query. + + :returns: Iterator over :class:`Feature` + """ + + 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", + } + + while True: + json = self._api.do("GET", "/api/2.0/feature-engineering/features", query=query, headers=headers) + if "features" in json: + for v in json["features"]: + yield Feature.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 update_feature(self, full_name: str, feature: Feature, update_mask: str) -> Feature: + """Update a Feature. + + :param full_name: str + The full three-part name (catalog, schema, name) of the feature. + :param feature: :class:`Feature` + Feature to update. + :param update_mask: str + The list of fields to update. + + :returns: :class:`Feature` + """ + body = feature.as_dict() + query = {} + if update_mask is not None: + query["update_mask"] = update_mask + headers = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + res = self._api.do( + "PATCH", f"/api/2.0/feature-engineering/features/{full_name}", query=query, body=body, headers=headers + ) + return Feature.from_dict(res) + + class FeatureStoreAPI: """A feature store is a centralized repository that enables data scientists to find and share features. Using a feature store also ensures that the code used to compute feature values is the same during model diff --git a/databricks/sdk/service/oauth2.py b/databricks/sdk/service/oauth2.py index 4e762e763..58c57808d 100755 --- a/databricks/sdk/service/oauth2.py +++ b/databricks/sdk/service/oauth2.py @@ -232,11 +232,11 @@ class FederationPolicy: oidc_policy: Optional[OidcFederationPolicy] = None policy_id: Optional[str] = None - """The ID of the federation policy.""" + """The ID of the federation policy. Output only.""" service_principal_id: Optional[int] = None - """The service principal ID that this federation policy applies to. Only set for service principal - federation policies.""" + """The service principal ID that this federation policy applies to. Output only. Only set for + service principal federation policies.""" uid: Optional[str] = None """Unique, immutable id of the federation policy.""" diff --git a/databricks/sdk/service/pipelines.py b/databricks/sdk/service/pipelines.py index a9e8ee11b..ff309b6ae 100755 --- a/databricks/sdk/service/pipelines.py +++ b/databricks/sdk/service/pipelines.py @@ -610,6 +610,10 @@ class IngestionPipelineDefinition: """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.""" + netsuite_jar_path: Optional[str] = None + """Netsuite only configuration. When the field is set for a netsuite connector, the jar stored in + the field will be validated and added to the classpath of pipeline's cluster.""" + objects: Optional[List[IngestionConfig]] = None """Required. Settings specifying tables to replicate and the destination for the replicated tables.""" @@ -631,6 +635,8 @@ def as_dict(self) -> dict: body["connection_name"] = self.connection_name if self.ingestion_gateway_id is not None: body["ingestion_gateway_id"] = self.ingestion_gateway_id + if self.netsuite_jar_path is not None: + body["netsuite_jar_path"] = self.netsuite_jar_path if self.objects: body["objects"] = [v.as_dict() for v in self.objects] if self.source_configurations: @@ -648,6 +654,8 @@ def as_shallow_dict(self) -> dict: body["connection_name"] = self.connection_name if self.ingestion_gateway_id is not None: body["ingestion_gateway_id"] = self.ingestion_gateway_id + if self.netsuite_jar_path is not None: + body["netsuite_jar_path"] = self.netsuite_jar_path if self.objects: body["objects"] = self.objects if self.source_configurations: @@ -664,6 +672,7 @@ def from_dict(cls, d: Dict[str, Any]) -> IngestionPipelineDefinition: return cls( connection_name=d.get("connection_name", 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), source_configurations=_repeated_dict(d, "source_configurations", SourceConfig), source_type=_enum(d, "source_type", IngestionSourceType), @@ -730,11 +739,97 @@ def from_dict(cls, d: Dict[str, Any]) -> IngestionPipelineDefinitionTableSpecifi ) +@dataclass +class IngestionPipelineDefinitionWorkdayReportParameters: + incremental: Optional[bool] = None + """(Optional) Marks the report as incremental. This field is deprecated and should not be used. Use + `parameters` instead. The incremental behavior is now controlled by the `parameters` field.""" + + parameters: Optional[Dict[str, str]] = None + """Parameters for the Workday report. Each key represents the parameter name (e.g., "start_date", + "end_date"), and the corresponding value is a SQL-like expression used to compute the parameter + value at runtime. Example: { "start_date": "{ coalesce(current_offset(), date(\"2025-02-01\")) + }", "end_date": "{ current_date() - INTERVAL 1 DAY }" }""" + + report_parameters: Optional[List[IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue]] = None + """(Optional) Additional custom parameters for Workday Report This field is deprecated and should + not be used. Use `parameters` instead.""" + + def as_dict(self) -> dict: + """Serializes the IngestionPipelineDefinitionWorkdayReportParameters into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.incremental is not None: + body["incremental"] = self.incremental + if self.parameters: + body["parameters"] = self.parameters + if self.report_parameters: + body["report_parameters"] = [v.as_dict() for v in self.report_parameters] + return body + + def as_shallow_dict(self) -> dict: + """Serializes the IngestionPipelineDefinitionWorkdayReportParameters into a shallow dictionary of its immediate attributes.""" + body = {} + if self.incremental is not None: + body["incremental"] = self.incremental + if self.parameters: + body["parameters"] = self.parameters + if self.report_parameters: + body["report_parameters"] = self.report_parameters + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> IngestionPipelineDefinitionWorkdayReportParameters: + """Deserializes the IngestionPipelineDefinitionWorkdayReportParameters from a dictionary.""" + return cls( + incremental=d.get("incremental", None), + parameters=d.get("parameters", None), + report_parameters=_repeated_dict( + d, "report_parameters", IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue + ), + ) + + +@dataclass +class IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue: + key: Optional[str] = None + """Key for the report parameter, can be a column name or other metadata""" + + value: Optional[str] = None + """Value for the report parameter. Possible values it can take are these sql functions: 1. + coalesce(current_offset(), date("YYYY-MM-DD")) -> if current_offset() is null, then the passed + date, else current_offset() 2. current_date() 3. date_sub(current_date(), x) -> subtract x (some + non-negative integer) days from current date""" + + def as_dict(self) -> dict: + """Serializes the IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.key is not None: + body["key"] = self.key + if self.value is not None: + body["value"] = self.value + return body + + def as_shallow_dict(self) -> dict: + """Serializes the IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue into a shallow dictionary of its immediate attributes.""" + body = {} + if self.key is not None: + body["key"] = self.key + if self.value is not None: + body["value"] = self.value + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue: + """Deserializes the IngestionPipelineDefinitionWorkdayReportParametersQueryKeyValue from a dictionary.""" + return cls(key=d.get("key", None), value=d.get("value", None)) + + class IngestionSourceType(Enum): BIGQUERY = "BIGQUERY" CONFLUENCE = "CONFLUENCE" DYNAMICS365 = "DYNAMICS365" + FOREIGN_CATALOG = "FOREIGN_CATALOG" GA4_RAW_DATA = "GA4_RAW_DATA" MANAGED_POSTGRESQL = "MANAGED_POSTGRESQL" META_MARKETING = "META_MARKETING" @@ -2871,6 +2966,9 @@ class TableSpecificConfig: """The column names specifying the logical order of events in the source data. Delta Live Tables uses this sequencing to handle change events that arrive out of order.""" + workday_report_parameters: Optional[IngestionPipelineDefinitionWorkdayReportParameters] = None + """(Optional) Additional custom parameters for Workday Report""" + def as_dict(self) -> dict: """Serializes the TableSpecificConfig into a dictionary suitable for use as a JSON request body.""" body = {} @@ -2888,6 +2986,8 @@ def as_dict(self) -> dict: body["scd_type"] = self.scd_type.value if self.sequence_by: body["sequence_by"] = [v for v in self.sequence_by] + if self.workday_report_parameters: + body["workday_report_parameters"] = self.workday_report_parameters.as_dict() return body def as_shallow_dict(self) -> dict: @@ -2907,6 +3007,8 @@ def as_shallow_dict(self) -> dict: body["scd_type"] = self.scd_type if self.sequence_by: body["sequence_by"] = self.sequence_by + if self.workday_report_parameters: + body["workday_report_parameters"] = self.workday_report_parameters return body @classmethod @@ -2924,6 +3026,9 @@ def from_dict(cls, d: Dict[str, Any]) -> TableSpecificConfig: salesforce_include_formula_fields=d.get("salesforce_include_formula_fields", None), scd_type=_enum(d, "scd_type", TableSpecificConfigScdType), sequence_by=d.get("sequence_by", None), + workday_report_parameters=_from_dict( + d, "workday_report_parameters", IngestionPipelineDefinitionWorkdayReportParameters + ), ) diff --git a/databricks/sdk/service/settingsv2.py b/databricks/sdk/service/settingsv2.py index 10e609f3b..babfb1a09 100755 --- a/databricks/sdk/service/settingsv2.py +++ b/databricks/sdk/service/settingsv2.py @@ -322,44 +322,6 @@ def from_dict(cls, d: Dict[str, Any]) -> ClusterAutoRestartMessageMaintenanceWin return cls(hours=d.get("hours", None), minutes=d.get("minutes", None)) -@dataclass -class DefaultDataSecurityModeMessage: - """Changes the behaviour of Jobs service when creating job clusters. - - Before this setting is introduced, all workspaces with metastore attached had behaviour matching - SINGLE_USER setting. - - See: - go/defaultdatasecuritymode - go/defaultdatasecuritymode/setting - go/datasecuritymode""" - - status: DefaultDataSecurityModeMessageStatus - - def as_dict(self) -> dict: - """Serializes the DefaultDataSecurityModeMessage into a dictionary suitable for use as a JSON request body.""" - body = {} - if self.status is not None: - body["status"] = self.status.value - return body - - def as_shallow_dict(self) -> dict: - """Serializes the DefaultDataSecurityModeMessage into a shallow dictionary of its immediate attributes.""" - body = {} - if self.status is not None: - body["status"] = self.status - return body - - @classmethod - def from_dict(cls, d: Dict[str, Any]) -> DefaultDataSecurityModeMessage: - """Deserializes the DefaultDataSecurityModeMessage from a dictionary.""" - return cls(status=_enum(d, "status", DefaultDataSecurityModeMessageStatus)) - - -class DefaultDataSecurityModeMessageStatus(Enum): - - NOT_SET = "NOT_SET" - SINGLE_USER = "SINGLE_USER" - USER_ISOLATION = "USER_ISOLATION" - - @dataclass class IntegerMessage: value: Optional[int] = None @@ -528,12 +490,9 @@ class Setting: aibi_dashboard_embedding_approved_domains: Optional[AibiDashboardEmbeddingApprovedDomains] = None automatic_cluster_update_workspace: Optional[ClusterAutoRestartMessage] = None - """todo: Mark these Public after onboarded to DSL""" boolean_val: Optional[BooleanMessage] = None - default_data_security_mode: Optional[DefaultDataSecurityModeMessage] = None - effective_aibi_dashboard_embedding_access_policy: Optional[AibiDashboardEmbeddingAccessPolicy] = None effective_aibi_dashboard_embedding_approved_domains: Optional[AibiDashboardEmbeddingApprovedDomains] = None @@ -542,8 +501,6 @@ class Setting: effective_boolean_val: Optional[BooleanMessage] = None - effective_default_data_security_mode: Optional[DefaultDataSecurityModeMessage] = None - effective_integer_val: Optional[IntegerMessage] = None effective_personal_compute: Optional[PersonalComputeMessage] = None @@ -574,8 +531,6 @@ def as_dict(self) -> dict: body["automatic_cluster_update_workspace"] = self.automatic_cluster_update_workspace.as_dict() if self.boolean_val: body["boolean_val"] = self.boolean_val.as_dict() - if self.default_data_security_mode: - body["default_data_security_mode"] = self.default_data_security_mode.as_dict() if self.effective_aibi_dashboard_embedding_access_policy: body["effective_aibi_dashboard_embedding_access_policy"] = ( self.effective_aibi_dashboard_embedding_access_policy.as_dict() @@ -590,8 +545,6 @@ def as_dict(self) -> dict: ) if self.effective_boolean_val: body["effective_boolean_val"] = self.effective_boolean_val.as_dict() - if self.effective_default_data_security_mode: - body["effective_default_data_security_mode"] = self.effective_default_data_security_mode.as_dict() if self.effective_integer_val: body["effective_integer_val"] = self.effective_integer_val.as_dict() if self.effective_personal_compute: @@ -623,8 +576,6 @@ def as_shallow_dict(self) -> dict: body["automatic_cluster_update_workspace"] = self.automatic_cluster_update_workspace if self.boolean_val: body["boolean_val"] = self.boolean_val - if self.default_data_security_mode: - body["default_data_security_mode"] = self.default_data_security_mode if self.effective_aibi_dashboard_embedding_access_policy: body["effective_aibi_dashboard_embedding_access_policy"] = ( self.effective_aibi_dashboard_embedding_access_policy @@ -637,8 +588,6 @@ def as_shallow_dict(self) -> dict: body["effective_automatic_cluster_update_workspace"] = self.effective_automatic_cluster_update_workspace if self.effective_boolean_val: body["effective_boolean_val"] = self.effective_boolean_val - if self.effective_default_data_security_mode: - body["effective_default_data_security_mode"] = self.effective_default_data_security_mode if self.effective_integer_val: body["effective_integer_val"] = self.effective_integer_val if self.effective_personal_compute: @@ -673,7 +622,6 @@ def from_dict(cls, d: Dict[str, Any]) -> Setting: d, "automatic_cluster_update_workspace", ClusterAutoRestartMessage ), boolean_val=_from_dict(d, "boolean_val", BooleanMessage), - default_data_security_mode=_from_dict(d, "default_data_security_mode", DefaultDataSecurityModeMessage), effective_aibi_dashboard_embedding_access_policy=_from_dict( d, "effective_aibi_dashboard_embedding_access_policy", AibiDashboardEmbeddingAccessPolicy ), @@ -684,9 +632,6 @@ def from_dict(cls, d: Dict[str, Any]) -> Setting: d, "effective_automatic_cluster_update_workspace", ClusterAutoRestartMessage ), effective_boolean_val=_from_dict(d, "effective_boolean_val", BooleanMessage), - effective_default_data_security_mode=_from_dict( - d, "effective_default_data_security_mode", DefaultDataSecurityModeMessage - ), effective_integer_val=_from_dict(d, "effective_integer_val", IntegerMessage), effective_personal_compute=_from_dict(d, "effective_personal_compute", PersonalComputeMessage), effective_restrict_workspace_admins=_from_dict( @@ -784,7 +729,8 @@ def __init__(self, api_client): self._api = api_client def get_public_account_setting(self, name: str) -> Setting: - """Get a setting value at account level + """Get a setting value at account level. See :method:settingsv2/listaccountsettingsmetadata for list of + setting available via public APIs at account level. :param name: str @@ -801,9 +747,8 @@ def get_public_account_setting(self, name: str) -> Setting: def list_account_settings_metadata( self, *, page_size: Optional[int] = None, page_token: Optional[str] = None ) -> Iterator[SettingsMetadata]: - """List valid setting keys and metadata. These settings are available to referenced via [GET - /api/2.1/settings/{name}](#~1api~1account~1settingsv2~1getpublicaccountsetting) and [PATCH - /api/2.1/settings/{name}](#~1api~1account~1settingsv2~patchpublicaccountsetting) APIs + """List valid setting keys and metadata. These settings are available to be referenced via GET + :method:settingsv2/getpublicaccountsetting and PATCH :method:settingsv2/patchpublicaccountsetting APIs :param page_size: int (optional) The maximum number of settings to return. The service may return fewer than this value. If @@ -840,7 +785,8 @@ def list_account_settings_metadata( query["page_token"] = json["next_page_token"] def patch_public_account_setting(self, name: str, setting: Setting) -> Setting: - """Patch a setting value at account level + """Patch a setting value at account level. See :method:settingsv2/listaccountsettingsmetadata for list of + setting available via public APIs at account level. :param name: str :param setting: :class:`Setting` @@ -866,7 +812,8 @@ def __init__(self, api_client): self._api = api_client def get_public_workspace_setting(self, name: str) -> Setting: - """Get a setting value at workspace level + """Get a setting value at workspace level. See :method:settingsv2/listworkspacesettingsmetadata for list + of setting available via public APIs. :param name: str @@ -883,9 +830,9 @@ def get_public_workspace_setting(self, name: str) -> Setting: def list_workspace_settings_metadata( self, *, page_size: Optional[int] = None, page_token: Optional[str] = None ) -> Iterator[SettingsMetadata]: - """List valid setting keys and metadata. These settings are available to referenced via [GET - /api/2.1/settings/{name}](#~1api~1workspace~1settingsv2~1getpublicworkspacesetting) and [PATCH - /api/2.1/settings/{name}](#~1api~1workspace~1settingsv2~patchpublicworkspacesetting) APIs + """List valid setting keys and metadata. These settings are available to be referenced via GET + :method:settingsv2/getpublicworkspacesetting and PATCH :method:settingsv2/patchpublicworkspacesetting + APIs :param page_size: int (optional) The maximum number of settings to return. The service may return fewer than this value. If @@ -920,7 +867,8 @@ def list_workspace_settings_metadata( query["page_token"] = json["next_page_token"] def patch_public_workspace_setting(self, name: str, setting: Setting) -> Setting: - """Patch a setting value at workspace level + """Patch a setting value at workspace level. See :method:settingsv2/listworkspacesettingsmetadata for + list of setting available via public APIs at workspace level. :param name: str :param setting: :class:`Setting` diff --git a/databricks/sdk/service/sharing.py b/databricks/sdk/service/sharing.py index fd8063c3d..92b5dac68 100755 --- a/databricks/sdk/service/sharing.py +++ b/databricks/sdk/service/sharing.py @@ -2307,6 +2307,9 @@ def from_dict(cls, d: Dict[str, Any]) -> Table: class TableInternalAttributes: """Internal information for D2D sharing that should not be disclosed to external users.""" + auxiliary_managed_location: Optional[str] = None + """Managed Delta Metadata location for foreign iceberg tables.""" + parent_storage_location: Optional[str] = None """Will be populated in the reconciliation response for VIEW and FOREIGN_TABLE, with the value of the parent UC entity's storage_location, following the same logic as getManagedEntityPath in @@ -2327,6 +2330,8 @@ class TableInternalAttributes: def as_dict(self) -> dict: """Serializes the TableInternalAttributes into a dictionary suitable for use as a JSON request body.""" body = {} + if self.auxiliary_managed_location is not None: + body["auxiliary_managed_location"] = self.auxiliary_managed_location if self.parent_storage_location is not None: body["parent_storage_location"] = self.parent_storage_location if self.storage_location is not None: @@ -2340,6 +2345,8 @@ def as_dict(self) -> dict: def as_shallow_dict(self) -> dict: """Serializes the TableInternalAttributes into a shallow dictionary of its immediate attributes.""" body = {} + if self.auxiliary_managed_location is not None: + body["auxiliary_managed_location"] = self.auxiliary_managed_location if self.parent_storage_location is not None: body["parent_storage_location"] = self.parent_storage_location if self.storage_location is not None: @@ -2354,6 +2361,7 @@ def as_shallow_dict(self) -> dict: def from_dict(cls, d: Dict[str, Any]) -> TableInternalAttributes: """Deserializes the TableInternalAttributes from a dictionary.""" return cls( + auxiliary_managed_location=d.get("auxiliary_managed_location", None), parent_storage_location=d.get("parent_storage_location", None), storage_location=d.get("storage_location", None), type=_enum(d, "type", TableInternalAttributesSharedTableType), @@ -2366,6 +2374,7 @@ class TableInternalAttributesSharedTableType(Enum): DELTA_ICEBERG_TABLE = "DELTA_ICEBERG_TABLE" DIRECTORY_BASED_TABLE = "DIRECTORY_BASED_TABLE" FILE_BASED_TABLE = "FILE_BASED_TABLE" + FOREIGN_ICEBERG_TABLE = "FOREIGN_ICEBERG_TABLE" FOREIGN_TABLE = "FOREIGN_TABLE" MATERIALIZED_VIEW = "MATERIALIZED_VIEW" STREAMING_TABLE = "STREAMING_TABLE" diff --git a/databricks/sdk/service/sql.py b/databricks/sdk/service/sql.py index 9a80d1f5b..33b80c3c9 100755 --- a/databricks/sdk/service/sql.py +++ b/databricks/sdk/service/sql.py @@ -792,7 +792,8 @@ class AlertV2Evaluation: """Operator used for comparison in alert evaluation.""" empty_result_state: Optional[AlertEvaluationState] = None - """Alert state if result is empty.""" + """Alert state if result is empty. Please avoid setting this field to be `UNKNOWN` because + `UNKNOWN` state is planned to be deprecated.""" last_evaluated_at: Optional[str] = None """Timestamp of the last evaluation.""" @@ -3914,13 +3915,18 @@ def from_dict(cls, d: Dict[str, Any]) -> ListAlertsResponseAlert: @dataclass class ListAlertsV2Response: + alerts: Optional[List[AlertV2]] = None + next_page_token: Optional[str] = None results: Optional[List[AlertV2]] = None + """Deprecated. Use `alerts` instead.""" def as_dict(self) -> dict: """Serializes the ListAlertsV2Response into a dictionary suitable for use as a JSON request body.""" body = {} + if self.alerts: + body["alerts"] = [v.as_dict() for v in self.alerts] if self.next_page_token is not None: body["next_page_token"] = self.next_page_token if self.results: @@ -3930,6 +3936,8 @@ def as_dict(self) -> dict: def as_shallow_dict(self) -> dict: """Serializes the ListAlertsV2Response into a shallow dictionary of its immediate attributes.""" body = {} + if self.alerts: + body["alerts"] = self.alerts if self.next_page_token is not None: body["next_page_token"] = self.next_page_token if self.results: @@ -3939,7 +3947,11 @@ def as_shallow_dict(self) -> dict: @classmethod def from_dict(cls, d: Dict[str, Any]) -> ListAlertsV2Response: """Deserializes the ListAlertsV2Response from a dictionary.""" - return cls(next_page_token=d.get("next_page_token", None), results=_repeated_dict(d, "results", AlertV2)) + return cls( + alerts=_repeated_dict(d, "alerts", AlertV2), + next_page_token=d.get("next_page_token", None), + results=_repeated_dict(d, "results", AlertV2), + ) class ListOrder(Enum): @@ -9534,7 +9546,7 @@ def get_workspace_warehouse_config(self) -> GetWorkspaceWarehouseConfigResponse: return GetWorkspaceWarehouseConfigResponse.from_dict(res) def list(self, *, run_as_user_id: Optional[int] = None) -> Iterator[EndpointInfo]: - """Lists all SQL warehouses that a user has manager permissions on. + """Lists all SQL warehouses that a user has access to. :param run_as_user_id: int (optional) Service Principal which will be used to fetch the list of warehouses. If not specified, the user diff --git a/databricks/sdk/service/tags.py b/databricks/sdk/service/tags.py index 8962682fa..9fa90681a 100755 --- a/databricks/sdk/service/tags.py +++ b/databricks/sdk/service/tags.py @@ -50,21 +50,31 @@ def from_dict(cls, d: Dict[str, Any]) -> ListTagPoliciesResponse: class TagPolicy: tag_key: str + create_time: Optional[str] = None + """Timestamp when the tag policy was created""" + description: Optional[str] = None id: Optional[str] = None + update_time: Optional[str] = None + """Timestamp when the tag policy was last updated""" + values: Optional[List[Value]] = None def as_dict(self) -> dict: """Serializes the TagPolicy 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.description is not None: body["description"] = self.description if self.id is not None: body["id"] = self.id if self.tag_key is not None: body["tag_key"] = self.tag_key + if self.update_time is not None: + body["update_time"] = self.update_time if self.values: body["values"] = [v.as_dict() for v in self.values] return body @@ -72,12 +82,16 @@ def as_dict(self) -> dict: def as_shallow_dict(self) -> dict: """Serializes the TagPolicy into a shallow dictionary of its immediate attributes.""" body = {} + if self.create_time is not None: + body["create_time"] = self.create_time if self.description is not None: body["description"] = self.description if self.id is not None: body["id"] = self.id if self.tag_key is not None: body["tag_key"] = self.tag_key + if self.update_time is not None: + body["update_time"] = self.update_time if self.values: body["values"] = self.values return body @@ -86,9 +100,11 @@ def as_shallow_dict(self) -> dict: def from_dict(cls, d: Dict[str, Any]) -> TagPolicy: """Deserializes the TagPolicy from a dictionary.""" return cls( + create_time=d.get("create_time", None), description=d.get("description", None), id=d.get("id", None), tag_key=d.get("tag_key", None), + update_time=d.get("update_time", None), values=_repeated_dict(d, "values", Value), ) @@ -118,13 +134,16 @@ def from_dict(cls, d: Dict[str, Any]) -> Value: class TagPoliciesAPI: - """The Tag Policy API allows you to manage tag policies in Databricks.""" + """The Tag Policy API allows you to manage policies for governed tags in Databricks. Permissions for tag + policies can be managed using the [Account Access Control Proxy API]. + + [Account Access Control Proxy API]: https://docs.databricks.com/api/workspace/accountaccesscontrolproxy""" def __init__(self, api_client): self._api = api_client def create_tag_policy(self, tag_policy: TagPolicy) -> TagPolicy: - """Creates a new tag policy. + """Creates a new tag policy, making the associated tag key governed. :param tag_policy: :class:`TagPolicy` @@ -140,7 +159,7 @@ def create_tag_policy(self, tag_policy: TagPolicy) -> TagPolicy: return TagPolicy.from_dict(res) def delete_tag_policy(self, tag_key: str): - """Deletes a tag policy by its key. + """Deletes a tag policy by its associated governed tag's key, leaving that tag key ungoverned. :param tag_key: str @@ -154,7 +173,7 @@ def delete_tag_policy(self, tag_key: str): self._api.do("DELETE", f"/api/2.1/tag-policies/{tag_key}", headers=headers) def get_tag_policy(self, tag_key: str) -> TagPolicy: - """Gets a single tag policy by its key. + """Gets a single tag policy by its associated governed tag's key. :param tag_key: str @@ -171,7 +190,7 @@ def get_tag_policy(self, tag_key: str) -> TagPolicy: def list_tag_policies( self, *, page_size: Optional[int] = None, page_token: Optional[str] = None ) -> Iterator[TagPolicy]: - """Lists all tag policies in the account. + """Lists the tag policies for all governed tags in the account. :param page_size: int (optional) The maximum number of results to return in this request. Fewer results may be returned than @@ -202,7 +221,7 @@ def list_tag_policies( query["page_token"] = json["next_page_token"] def update_tag_policy(self, tag_key: str, tag_policy: TagPolicy, update_mask: str) -> TagPolicy: - """Updates an existing tag policy. + """Updates an existing tag policy for a single governed tag. :param tag_key: str :param tag_policy: :class:`TagPolicy` diff --git a/docs/gen-client-docs.py b/docs/gen-client-docs.py index 3db599ebe..e352c28e1 100644 --- a/docs/gen-client-docs.py +++ b/docs/gen-client-docs.py @@ -265,6 +265,11 @@ class Generator: "agentbricks", "Agent Bricks", "Create and manage Agent Bricks resources." + ), + Package( + "iamv2", + "Identity and Access Management", + "Manage identities and workspace access." ) ] From 004650f8af956fe4e98925c0337168e72244c988 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Wed, 17 Sep 2025 14:18:40 +0000 Subject: [PATCH 2/3] update --- .codegen/_openapi_sha | 2 +- NEXT_CHANGELOG.md | 81 +------------------------------ databricks/sdk/__init__.py | 5 +- databricks/sdk/mixins/sharing.py | 44 +++++++++++++++++ databricks/sdk/service/jobs.py | 51 ++++--------------- databricks/sdk/service/sharing.py | 4 +- docs/gen-client-docs.py | 4 ++ 7 files changed, 65 insertions(+), 126 deletions(-) create mode 100644 databricks/sdk/mixins/sharing.py diff --git a/.codegen/_openapi_sha b/.codegen/_openapi_sha index 05ebbd8c0..fbe17bac0 100644 --- a/.codegen/_openapi_sha +++ b/.codegen/_openapi_sha @@ -1 +1 @@ -3da28310c39d8ab0067e1c5fecd0707add475a86 \ No newline at end of file +5a1f970dc9331ab41755d374a90b811365927b42 \ No newline at end of file diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 802055bbe..f7b39d9b4 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -32,85 +32,6 @@ * Added `internal_catalog_path_overlap_exception` and `internal_catalog_missing_uc_path_exception` enum values for `databricks.sdk.service.dashboards.MessageErrorType`. * Added `foreign_catalog` enum value for `databricks.sdk.service.pipelines.IngestionSourceType`. * Added `foreign_iceberg_table` enum value for `databricks.sdk.service.sharing.TableInternalAttributesSharedTableType`. -* [Breaking] Changed `creation_time` field for `databricks.sdk.service.agentbricks.CustomLlm` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.agentbricks.UpdateCustomLlmRequest` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.apps.App` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.apps.AppDeployment` to type `str` dataclass. -* [Breaking] Changed `timestamp` field for `databricks.sdk.service.catalog.ContinuousUpdateStatus` to type `str` dataclass. -* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageExternalMetadataInfo` to type `str` dataclass. -* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageFileInfo` to type `str` dataclass. -* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageModelVersionInfo` to type `str` dataclass. -* [Breaking] Changed `event_time` field for `databricks.sdk.service.catalog.ExternalLineageTableInfo` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.catalog.ExternalMetadata` to type `str` dataclass. -* [Breaking] Changed `timestamp` field for `databricks.sdk.service.catalog.FailedStatus` to type `str` dataclass. -* [Breaking] Changed `timestamp` field for `databricks.sdk.service.catalog.TriggeredUpdateStatus` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateAccessRequestDestinationsRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateEntityTagAssignmentRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateExternalLineageRelationshipRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdateExternalMetadataRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.catalog.UpdatePolicyRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.compute.UpdateCluster` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.dashboards.Dashboard` to type `str` dataclass. -* [Breaking] Changed `revision_create_time` field for `databricks.sdk.service.dashboards.PublishedDashboard` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.dashboards.Schedule` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.dashboards.Subscription` to type `str` dataclass. -* [Breaking] Changed `expiration_time` field for `databricks.sdk.service.database.DatabaseCredential` to type `str` dataclass. -* [Breaking] Changed `creation_time` field for `databricks.sdk.service.database.DatabaseInstance` to type `str` dataclass. -* [Breaking] Changed `branch_time` field for `databricks.sdk.service.database.DatabaseInstanceRef` to type `str` dataclass. -* [Breaking] Changed `delta_commit_timestamp` field for `databricks.sdk.service.database.DeltaTableSyncInfo` to type `str` dataclass. -* [Breaking] Changed `timestamp` field for `databricks.sdk.service.database.SyncedTableContinuousUpdateStatus` to type `str` dataclass. -* [Breaking] Changed `timestamp` field for `databricks.sdk.service.database.SyncedTableFailedStatus` to type `str` dataclass. -* [Breaking] Changed `sync_end_timestamp` and `sync_start_timestamp` fields for `databricks.sdk.service.database.SyncedTablePosition` to type `str` dataclass. -* [Breaking] Changed `timestamp` field for `databricks.sdk.service.database.SyncedTableTriggeredUpdateStatus` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.database.UpdateDatabaseCatalogRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.database.UpdateDatabaseInstanceRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.database.UpdateSyncedDatabaseTableRequest` to type `str` dataclass. -* [Breaking] Changed `creation_time` field for `databricks.sdk.service.ml.OnlineStore` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.ml.UpdateFeatureTagRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.ml.UpdateOnlineStoreRequest` to type `str` dataclass. -* [Breaking] Changed `lifetime` field for `databricks.sdk.service.oauth2.CreateServicePrincipalSecretRequest` to type `str` dataclass. -* [Breaking] Changed `expire_time` field for `databricks.sdk.service.oauth2.CreateServicePrincipalSecretResponse` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.oauth2.FederationPolicy` to type `str` dataclass. -* [Breaking] Changed `expire_time` field for `databricks.sdk.service.oauth2.SecretInfo` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.oauth2.UpdateAccountFederationPolicyRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.oauth2.UpdateServicePrincipalFederationPolicyRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAccountIpAccessEnableRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAibiDashboardEmbeddingAccessPolicySettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAibiDashboardEmbeddingApprovedDomainsSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateAutomaticClusterUpdateSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateComplianceSecurityProfileSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateCspEnablementAccountSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDashboardEmailSubscriptionsRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDefaultNamespaceSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDefaultWarehouseIdRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDisableLegacyAccessRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDisableLegacyDbfsRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateDisableLegacyFeaturesRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnableExportNotebookRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnableNotebookTableClipboardRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnableResultsDownloadingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEnhancedSecurityMonitoringSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateEsmEnablementAccountSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateLlmProxyPartnerPoweredAccountRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateLlmProxyPartnerPoweredEnforceRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateLlmProxyPartnerPoweredWorkspaceRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.settings.UpdateNccPrivateEndpointRuleRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdatePersonalComputeSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateRestrictWorkspaceAdminsSettingRequest` to type `str` dataclass. -* [Breaking] Changed `field_mask` field for `databricks.sdk.service.settings.UpdateSqlResultsDownloadRequest` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sharing.FederationPolicy` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sharing.UpdateFederationPolicyRequest` to type `str` dataclass. -* [Breaking] Changed `create_time`, `trigger_time` and `update_time` fields for `databricks.sdk.service.sql.Alert` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.AlertV2` to type `str` dataclass. -* [Breaking] Changed `last_evaluated_at` field for `databricks.sdk.service.sql.AlertV2Evaluation` to type `str` dataclass. -* [Breaking] Changed `create_time`, `trigger_time` and `update_time` fields for `databricks.sdk.service.sql.ListAlertsResponseAlert` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.ListQueryObjectsResponseQuery` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.Query` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateAlertRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateAlertV2Request` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateQueryRequest` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.sql.UpdateVisualizationRequest` to type `str` dataclass. -* [Breaking] Changed `create_time` and `update_time` fields for `databricks.sdk.service.sql.Visualization` to type `str` dataclass. -* [Breaking] Changed `update_mask` field for `databricks.sdk.service.tags.UpdateTagPolicyRequest` to type `str` dataclass. * [Breaking] Removed `disabled` field for `databricks.sdk.service.jobs.RunTask`. * [Breaking] Removed `default_data_security_mode` and `effective_default_data_security_mode` fields for `databricks.sdk.service.settingsv2.Setting`. +* Added `list_shares()` method for [w.shares](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/sharing/shares.html) workspace-level service. diff --git a/databricks/sdk/__init__.py b/databricks/sdk/__init__.py index ef42d1c34..56782a611 100755 --- a/databricks/sdk/__init__.py +++ b/databricks/sdk/__init__.py @@ -12,6 +12,7 @@ from databricks.sdk.mixins.files import DbfsExt, FilesExt from databricks.sdk.mixins.jobs import JobsExt from databricks.sdk.mixins.open_ai_client import ServingEndpointsExt +from databricks.sdk.mixins.sharing import SharesExt from databricks.sdk.mixins.workspace import WorkspaceExt from databricks.sdk.service import agentbricks as pkg_agentbricks from databricks.sdk.service import apps as pkg_apps @@ -357,7 +358,7 @@ def __init__( self._api_client, serving_endpoints, serving_endpoints_data_plane_token_source ) self._settings = pkg_settings.SettingsAPI(self._api_client) - self._shares = pkg_sharing.SharesAPI(self._api_client) + self._shares = SharesExt(self._api_client) self._statement_execution = pkg_sql.StatementExecutionAPI(self._api_client) self._storage_credentials = pkg_catalog.StorageCredentialsAPI(self._api_client) self._system_schemas = pkg_catalog.SystemSchemasAPI(self._api_client) @@ -881,7 +882,7 @@ def settings(self) -> pkg_settings.SettingsAPI: return self._settings @property - def shares(self) -> pkg_sharing.SharesAPI: + def shares(self) -> SharesExt: """A share is a container instantiated with :method:shares/create.""" return self._shares diff --git a/databricks/sdk/mixins/sharing.py b/databricks/sdk/mixins/sharing.py new file mode 100644 index 000000000..65e03d665 --- /dev/null +++ b/databricks/sdk/mixins/sharing.py @@ -0,0 +1,44 @@ +from typing import Iterator, Optional + +from databricks.sdk.service import sharing +from databricks.sdk.service.sharing import ShareInfo + + +class SharesExt(sharing.SharesAPI): + def list(self, *, max_results: Optional[int] = None, page_token: Optional[str] = None) -> Iterator[ShareInfo]: + """Gets an array of data object shares from the metastore. The caller must be a metastore admin or the + owner of the share. There is no guarantee of a specific ordering of the elements in the array. + + :param max_results: int (optional) + Maximum number of shares to return. - when set to 0, the page length is set to a server configured + value (recommended); - when set to a value greater than 0, the page length is the minimum of this + value and a server configured value; - when set to a value less than 0, an invalid parameter error + is returned; - If not set, all valid shares are returned (not recommended). - Note: The number of + returned shares might be less than the specified max_results size, even zero. The only definitive + indication that no further shares can be fetched is when the next_page_token is unset from the + response. + :param page_token: str (optional) + Opaque pagination token to go to next page based on previous query. + + :returns: Iterator over :class:`ShareInfo` + """ + + query = {} + if max_results is not None: + query["max_results"] = max_results + if page_token is not None: + query["page_token"] = page_token + headers = { + "Accept": "application/json", + } + + if "max_results" not in query: + query["max_results"] = 0 + while True: + json = self._api.do("GET", "/api/2.1/unity-catalog/shares", query=query, headers=headers) + if "shares" in json: + for v in json["shares"]: + yield ShareInfo.from_dict(v) + if "next_page_token" not in json or not json["next_page_token"]: + return + query["page_token"] = json["next_page_token"] diff --git a/databricks/sdk/service/jobs.py b/databricks/sdk/service/jobs.py index 4445c2310..13ff0c430 100755 --- a/databricks/sdk/service/jobs.py +++ b/databricks/sdk/service/jobs.py @@ -5807,21 +5807,10 @@ class RunTask: """The task runs a Python file when the `spark_python_task` field is present.""" spark_submit_task: Optional[SparkSubmitTask] = None - """(Legacy) The task runs the spark-submit script when the `spark_submit_task` field is present. - This task can run only on new clusters and is not compatible with serverless compute. + """(Legacy) The task runs the spark-submit script when the spark_submit_task field is present. + Databricks recommends using the spark_jar_task instead; see [Spark Submit task for jobs]. - In the `new_cluster` specification, `libraries` and `spark_conf` are not supported. Instead, use - `--jars` and `--py-files` to add Java and Python libraries and `--conf` to set the Spark - configurations. - - `master`, `deploy-mode`, and `executor-cores` are automatically configured by Databricks; you - _cannot_ specify them in parameters. - - By default, the Spark submit job uses all available memory (excluding reserved memory for - Databricks services). You can set `--driver-memory`, and `--executor-memory` to a smaller value - to leave some room for off-heap usage. - - The `--jars`, `--py-files`, `--files` arguments support DBFS and S3 paths.""" + [Spark Submit task for jobs]: https://docs.databricks.com/jobs/spark-submit.html""" sql_task: Optional[SqlTask] = None """The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when @@ -6995,21 +6984,10 @@ class SubmitTask: """The task runs a Python file when the `spark_python_task` field is present.""" spark_submit_task: Optional[SparkSubmitTask] = None - """(Legacy) The task runs the spark-submit script when the `spark_submit_task` field is present. - This task can run only on new clusters and is not compatible with serverless compute. - - In the `new_cluster` specification, `libraries` and `spark_conf` are not supported. Instead, use - `--jars` and `--py-files` to add Java and Python libraries and `--conf` to set the Spark - configurations. - - `master`, `deploy-mode`, and `executor-cores` are automatically configured by Databricks; you - _cannot_ specify them in parameters. + """(Legacy) The task runs the spark-submit script when the spark_submit_task field is present. + Databricks recommends using the spark_jar_task instead; see [Spark Submit task for jobs]. - By default, the Spark submit job uses all available memory (excluding reserved memory for - Databricks services). You can set `--driver-memory`, and `--executor-memory` to a smaller value - to leave some room for off-heap usage. - - The `--jars`, `--py-files`, `--files` arguments support DBFS and S3 paths.""" + [Spark Submit task for jobs]: https://docs.databricks.com/jobs/spark-submit.html""" sql_task: Optional[SqlTask] = None """The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when @@ -7516,21 +7494,10 @@ class Task: """The task runs a Python file when the `spark_python_task` field is present.""" spark_submit_task: Optional[SparkSubmitTask] = None - """(Legacy) The task runs the spark-submit script when the `spark_submit_task` field is present. - This task can run only on new clusters and is not compatible with serverless compute. - - In the `new_cluster` specification, `libraries` and `spark_conf` are not supported. Instead, use - `--jars` and `--py-files` to add Java and Python libraries and `--conf` to set the Spark - configurations. - - `master`, `deploy-mode`, and `executor-cores` are automatically configured by Databricks; you - _cannot_ specify them in parameters. - - By default, the Spark submit job uses all available memory (excluding reserved memory for - Databricks services). You can set `--driver-memory`, and `--executor-memory` to a smaller value - to leave some room for off-heap usage. + """(Legacy) The task runs the spark-submit script when the spark_submit_task field is present. + Databricks recommends using the spark_jar_task instead; see [Spark Submit task for jobs]. - The `--jars`, `--py-files`, `--files` arguments support DBFS and S3 paths.""" + [Spark Submit task for jobs]: https://docs.databricks.com/jobs/spark-submit.html""" sql_task: Optional[SqlTask] = None """The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when diff --git a/databricks/sdk/service/sharing.py b/databricks/sdk/service/sharing.py index 92b5dac68..e68d110dc 100755 --- a/databricks/sdk/service/sharing.py +++ b/databricks/sdk/service/sharing.py @@ -3372,7 +3372,9 @@ def get(self, name: str, *, include_shared_data: Optional[bool] = None) -> Share res = self._api.do("GET", f"/api/2.1/unity-catalog/shares/{name}", query=query, headers=headers) return ShareInfo.from_dict(res) - def list(self, *, max_results: Optional[int] = None, page_token: Optional[str] = None) -> Iterator[ShareInfo]: + def list_shares( + self, *, max_results: Optional[int] = None, page_token: Optional[str] = None + ) -> Iterator[ShareInfo]: """Gets an array of data object shares from the metastore. The caller must be a metastore admin or the owner of the share. There is no guarantee of a specific ordering of the elements in the array. diff --git a/docs/gen-client-docs.py b/docs/gen-client-docs.py index e352c28e1..7db1b3c25 100644 --- a/docs/gen-client-docs.py +++ b/docs/gen-client-docs.py @@ -372,6 +372,10 @@ def service_docs(self, client_inst, client_prefix: str) -> list[ServiceDoc]: ignore_client_fields = ('config', 'dbutils', 'api_client', 'get_workspace_client', 'get_workspace_id') all = [] for service_name, service_inst in inspect.getmembers(client_inst, lambda o: not inspect.ismethod(o)): + # These services are frozen in the SDK, so we don't need to update + # their docs. + if service_name in ['groups', 'service_principals', 'users']: + continue if service_name.startswith('_'): continue if service_name in ignore_client_fields: From 4ed6b76607489ca51f41fa212f20e4f2292f736a Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Thu, 18 Sep 2025 10:41:50 +0000 Subject: [PATCH 3/3] update --- .codegen/_openapi_sha | 2 +- NEXT_CHANGELOG.md | 9 +++ databricks/sdk/service/catalog.py | 8 +- databricks/sdk/service/compute.py | 1 + databricks/sdk/service/dashboards.py | 107 +++++++++++++-------------- databricks/sdk/service/iam.py | 57 +++++++++++++- databricks/sdk/service/jobs.py | 25 +++---- databricks/sdk/service/sharing.py | 1 + 8 files changed, 131 insertions(+), 79 deletions(-) diff --git a/.codegen/_openapi_sha b/.codegen/_openapi_sha index fbe17bac0..f09edb728 100644 --- a/.codegen/_openapi_sha +++ b/.codegen/_openapi_sha @@ -1 +1 @@ -5a1f970dc9331ab41755d374a90b811365927b42 \ No newline at end of file +c3a3e3055fe11cb9683f398a665c225a03563ff1 \ No newline at end of file diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index f7b39d9b4..869a88d02 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -35,3 +35,12 @@ * [Breaking] Removed `disabled` field for `databricks.sdk.service.jobs.RunTask`. * [Breaking] Removed `default_data_security_mode` and `effective_default_data_security_mode` fields for `databricks.sdk.service.settingsv2.Setting`. * Added `list_shares()` method for [w.shares](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/sharing/shares.html) workspace-level service. +* Added `suggested_questions` field for `databricks.sdk.service.dashboards.GenieAttachment`. +* Added `warehouse_id` field for `databricks.sdk.service.dashboards.GenieSpace`. +* Added `palantir` enum value for `databricks.sdk.service.catalog.ConnectionType`. +* Added `table_metric_view_deltasharing` and `table_foreign_palantir` enum values for `databricks.sdk.service.catalog.SecurableKind`. +* Added `no_activated_k8s_testing_tag` enum value for `databricks.sdk.service.compute.TerminationReasonCode`. +* Added `metric_view` enum value for `databricks.sdk.service.sharing.TableInternalAttributesSharedTableType`. +* [Breaking] Removed `followup_questions` field for `databricks.sdk.service.dashboards.GenieAttachment`. +* [Breaking] Removed `comment` field for `databricks.sdk.service.dashboards.GenieFeedback`. +* [Breaking] Removed `comment` field for `databricks.sdk.service.dashboards.GenieSendMessageFeedbackRequest`. \ No newline at end of file diff --git a/databricks/sdk/service/catalog.py b/databricks/sdk/service/catalog.py index c05285d67..fed76f073 100755 --- a/databricks/sdk/service/catalog.py +++ b/databricks/sdk/service/catalog.py @@ -1505,7 +1505,7 @@ def from_dict(cls, d: Dict[str, Any]) -> ConnectionInfo: class ConnectionType(Enum): - """Next Id: 37""" + """Next Id: 38""" BIGQUERY = "BIGQUERY" DATABRICKS = "DATABRICKS" @@ -1515,6 +1515,7 @@ class ConnectionType(Enum): HTTP = "HTTP" MYSQL = "MYSQL" ORACLE = "ORACLE" + PALANTIR = "PALANTIR" POSTGRESQL = "POSTGRESQL" POWER_BI = "POWER_BI" REDSHIFT = "REDSHIFT" @@ -2892,8 +2893,6 @@ def from_dict(cls, d: Dict[str, Any]) -> EffectivePredictiveOptimizationFlag: class EffectivePredictiveOptimizationFlagInheritedFromType(Enum): - """The type of the object from which the flag was inherited. If there was no inheritance, this - field is left blank.""" CATALOG = "CATALOG" SCHEMA = "SCHEMA" @@ -8540,6 +8539,7 @@ def from_dict(cls, d: Dict[str, Any]) -> Securable: class SecurableKind(Enum): + """Latest kind: CONNECTION_PALANTIR_OAUTH_M2M = 263; Next id:264""" TABLE_DB_STORAGE = "TABLE_DB_STORAGE" TABLE_DELTA = "TABLE_DELTA" @@ -8581,6 +8581,7 @@ class SecurableKind(Enum): TABLE_FOREIGN_MYSQL = "TABLE_FOREIGN_MYSQL" TABLE_FOREIGN_NETSUITE = "TABLE_FOREIGN_NETSUITE" TABLE_FOREIGN_ORACLE = "TABLE_FOREIGN_ORACLE" + TABLE_FOREIGN_PALANTIR = "TABLE_FOREIGN_PALANTIR" TABLE_FOREIGN_POSTGRESQL = "TABLE_FOREIGN_POSTGRESQL" TABLE_FOREIGN_REDSHIFT = "TABLE_FOREIGN_REDSHIFT" TABLE_FOREIGN_SALESFORCE = "TABLE_FOREIGN_SALESFORCE" @@ -8598,6 +8599,7 @@ class SecurableKind(Enum): TABLE_MATERIALIZED_VIEW = "TABLE_MATERIALIZED_VIEW" TABLE_MATERIALIZED_VIEW_DELTASHARING = "TABLE_MATERIALIZED_VIEW_DELTASHARING" TABLE_METRIC_VIEW = "TABLE_METRIC_VIEW" + TABLE_METRIC_VIEW_DELTASHARING = "TABLE_METRIC_VIEW_DELTASHARING" TABLE_ONLINE_VECTOR_INDEX_DIRECT = "TABLE_ONLINE_VECTOR_INDEX_DIRECT" TABLE_ONLINE_VECTOR_INDEX_REPLICA = "TABLE_ONLINE_VECTOR_INDEX_REPLICA" TABLE_ONLINE_VIEW = "TABLE_ONLINE_VIEW" diff --git a/databricks/sdk/service/compute.py b/databricks/sdk/service/compute.py index 8dcf75ee8..11a2a2b78 100755 --- a/databricks/sdk/service/compute.py +++ b/databricks/sdk/service/compute.py @@ -7160,6 +7160,7 @@ class TerminationReasonCode(Enum): NETWORK_CONFIGURATION_FAILURE = "NETWORK_CONFIGURATION_FAILURE" NFS_MOUNT_FAILURE = "NFS_MOUNT_FAILURE" NO_ACTIVATED_K8S = "NO_ACTIVATED_K8S" + NO_ACTIVATED_K8S_TESTING_TAG = "NO_ACTIVATED_K8S_TESTING_TAG" NO_MATCHED_K8S = "NO_MATCHED_K8S" NO_MATCHED_K8S_TESTING_TAG = "NO_MATCHED_K8S_TESTING_TAG" NPIP_TUNNEL_SETUP_FAILURE = "NPIP_TUNNEL_SETUP_FAILURE" diff --git a/databricks/sdk/service/dashboards.py b/databricks/sdk/service/dashboards.py index 7bd8caf6b..33f8b7382 100755 --- a/databricks/sdk/service/dashboards.py +++ b/databricks/sdk/service/dashboards.py @@ -260,12 +260,12 @@ class GenieAttachment: attachment_id: Optional[str] = None """Attachment ID""" - followup_questions: Optional[GenieFollowupQuestionsAttachment] = None - """Follow-up questions suggested by Genie""" - 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""" @@ -274,10 +274,10 @@ def as_dict(self) -> dict: body = {} if self.attachment_id is not None: body["attachment_id"] = self.attachment_id - if self.followup_questions: - body["followup_questions"] = self.followup_questions.as_dict() 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 @@ -287,10 +287,10 @@ def as_shallow_dict(self) -> dict: body = {} if self.attachment_id is not None: body["attachment_id"] = self.attachment_id - if self.followup_questions: - body["followup_questions"] = self.followup_questions 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 @@ -300,8 +300,8 @@ def from_dict(cls, d: Dict[str, Any]) -> GenieAttachment: """Deserializes the GenieAttachment from a dictionary.""" return cls( attachment_id=d.get("attachment_id", None), - followup_questions=_from_dict(d, "followup_questions", GenieFollowupQuestionsAttachment), query=_from_dict(d, "query", GenieQueryAttachment), + suggested_questions=_from_dict(d, "suggested_questions", GenieSuggestedQuestionsAttachment), text=_from_dict(d, "text", TextAttachment), ) @@ -425,17 +425,12 @@ def from_dict(cls, d: Dict[str, Any]) -> GenieConversationSummary: class GenieFeedback: """Feedback containing rating and optional comment""" - comment: Optional[str] = None - """Optional feedback comment text""" - 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.comment is not None: - body["comment"] = self.comment if self.rating is not None: body["rating"] = self.rating.value return body @@ -443,8 +438,6 @@ def as_dict(self) -> dict: def as_shallow_dict(self) -> dict: """Serializes the GenieFeedback into a shallow dictionary of its immediate attributes.""" body = {} - if self.comment is not None: - body["comment"] = self.comment if self.rating is not None: body["rating"] = self.rating return body @@ -452,7 +445,7 @@ def as_shallow_dict(self) -> dict: @classmethod def from_dict(cls, d: Dict[str, Any]) -> GenieFeedback: """Deserializes the GenieFeedback from a dictionary.""" - return cls(comment=d.get("comment", None), rating=_enum(d, "rating", GenieFeedbackRating)) + return cls(rating=_enum(d, "rating", GenieFeedbackRating)) class GenieFeedbackRating(Enum): @@ -463,33 +456,6 @@ class GenieFeedbackRating(Enum): POSITIVE = "POSITIVE" -@dataclass -class GenieFollowupQuestionsAttachment: - """Follow-up questions suggested by Genie""" - - questions: Optional[List[str]] = None - """The suggested follow-up questions""" - - def as_dict(self) -> dict: - """Serializes the GenieFollowupQuestionsAttachment 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 GenieFollowupQuestionsAttachment 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]) -> GenieFollowupQuestionsAttachment: - """Deserializes the GenieFollowupQuestionsAttachment from a dictionary.""" - return cls(questions=d.get("questions", None)) - - @dataclass class GenieGetMessageQueryResultResponse: statement_response: Optional[sql.StatementResponse] = None @@ -856,6 +822,9 @@ class GenieSpace: description: Optional[str] = None """Description of the Genie Space""" + 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 = {} @@ -865,6 +834,8 @@ def as_dict(self) -> dict: 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: @@ -876,12 +847,19 @@ def as_shallow_dict(self) -> dict: 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), space_id=d.get("space_id", None), title=d.get("title", None)) + return cls( + description=d.get("description", None), + space_id=d.get("space_id", None), + title=d.get("title", None), + warehouse_id=d.get("warehouse_id", None), + ) @dataclass @@ -933,6 +911,33 @@ def from_dict(cls, d: Dict[str, Any]) -> GenieStartConversationResponse: ) +@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 @@ -2049,15 +2054,7 @@ def list_spaces( 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, - *, - comment: Optional[str] = None, - ): + 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 @@ -2068,14 +2065,10 @@ def send_message_feedback( The ID associated with the message to provide feedback for. :param rating: :class:`GenieFeedbackRating` The rating (POSITIVE, NEGATIVE, or NONE). - :param comment: str (optional) - Optional text feedback that will be stored as a comment. """ body = {} - if comment is not None: - body["comment"] = comment if rating is not None: body["rating"] = rating.value headers = { diff --git a/databricks/sdk/service/iam.py b/databricks/sdk/service/iam.py index e38498296..e42fbd0f7 100755 --- a/databricks/sdk/service/iam.py +++ b/databricks/sdk/service/iam.py @@ -850,6 +850,57 @@ def from_dict(cls, d: Dict[str, Any]) -> ListAccountServicePrincipalsResponse: ) +@dataclass +class ListAccountUsersResponse: + items_per_page: Optional[int] = None + """Total results returned in the response.""" + + resources: Optional[List[AccountUser]] = None + """User objects returned in the response.""" + + start_index: Optional[int] = None + """Starting index of all the results that matched the request filters. First item is number 1.""" + + total_results: Optional[int] = None + """Total results that match the request filters.""" + + def as_dict(self) -> dict: + """Serializes the ListAccountUsersResponse into a dictionary suitable for use as a JSON request body.""" + body = {} + if self.items_per_page is not None: + body["itemsPerPage"] = self.items_per_page + if self.resources: + body["Resources"] = [v.as_dict() for v in self.resources] + if self.start_index is not None: + body["startIndex"] = self.start_index + if self.total_results is not None: + body["totalResults"] = self.total_results + return body + + def as_shallow_dict(self) -> dict: + """Serializes the ListAccountUsersResponse into a shallow dictionary of its immediate attributes.""" + body = {} + if self.items_per_page is not None: + body["itemsPerPage"] = self.items_per_page + if self.resources: + body["Resources"] = self.resources + if self.start_index is not None: + body["startIndex"] = self.start_index + if self.total_results is not None: + body["totalResults"] = self.total_results + return body + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> ListAccountUsersResponse: + """Deserializes the ListAccountUsersResponse from a dictionary.""" + return cls( + items_per_page=d.get("itemsPerPage", None), + resources=_repeated_dict(d, "Resources", AccountUser), + start_index=d.get("startIndex", None), + total_results=d.get("totalResults", None), + ) + + @dataclass class ListGroupsResponse: items_per_page: Optional[int] = None @@ -3039,7 +3090,7 @@ def list( sort_by: Optional[str] = None, sort_order: Optional[ListSortOrder] = None, start_index: Optional[int] = None, - ) -> Iterator[AccountGroup]: + ) -> Iterator[AccountUser]: """Gets details for all the users associated with a Databricks account. :param attributes: str (optional) @@ -3063,7 +3114,7 @@ def list( :param start_index: int (optional) Specifies the index of the first result. First item is number 1. - :returns: Iterator over :class:`AccountGroup` + :returns: Iterator over :class:`AccountUser` """ query = {} @@ -3094,7 +3145,7 @@ def list( ) if "Resources" in json: for v in json["Resources"]: - yield AccountGroup.from_dict(v) + yield AccountUser.from_dict(v) if "Resources" not in json or not json["Resources"]: return query["startIndex"] += len(json["Resources"]) diff --git a/databricks/sdk/service/jobs.py b/databricks/sdk/service/jobs.py index 13ff0c430..9519e8ba7 100755 --- a/databricks/sdk/service/jobs.py +++ b/databricks/sdk/service/jobs.py @@ -1651,9 +1651,7 @@ class ExportRunOutput: views: Optional[List[ViewItem]] = None """The exported content in HTML format (one for every view item). To extract the HTML notebook from - the JSON response, download and run this [Python script]. - - [Python script]: https://docs.databricks.com/en/_static/examples/extract.py""" + the JSON response, download and run this [Python script](/_static/examples/extract.py).""" def as_dict(self) -> dict: """Serializes the ExportRunOutput into a dictionary suitable for use as a JSON request body.""" @@ -5659,7 +5657,7 @@ class RunTask: clean_rooms_notebook_task: Optional[CleanRoomsNotebookTask] = None """The task runs a [clean rooms] notebook when the `clean_rooms_notebook_task` field is present. - [clean rooms]: https://docs.databricks.com/en/clean-rooms/index.html""" + [clean rooms]: https://docs.databricks.com/clean-rooms/index.html""" cleanup_duration: Optional[int] = None """The time in milliseconds it took to terminate the cluster and clean up any associated artifacts. @@ -5808,9 +5806,8 @@ class RunTask: spark_submit_task: Optional[SparkSubmitTask] = None """(Legacy) The task runs the spark-submit script when the spark_submit_task field is present. - Databricks recommends using the spark_jar_task instead; see [Spark Submit task for jobs]. - - [Spark Submit task for jobs]: https://docs.databricks.com/jobs/spark-submit.html""" + Databricks recommends using the spark_jar_task instead; see [Spark Submit task for + jobs](/jobs/spark-submit).""" sql_task: Optional[SqlTask] = None """The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when @@ -6897,7 +6894,7 @@ class SubmitTask: clean_rooms_notebook_task: Optional[CleanRoomsNotebookTask] = None """The task runs a [clean rooms] notebook when the `clean_rooms_notebook_task` field is present. - [clean rooms]: https://docs.databricks.com/en/clean-rooms/index.html""" + [clean rooms]: https://docs.databricks.com/clean-rooms/index.html""" condition_task: Optional[ConditionTask] = None """The task evaluates a condition that can be used to control the execution of other tasks when the @@ -6985,9 +6982,8 @@ class SubmitTask: spark_submit_task: Optional[SparkSubmitTask] = None """(Legacy) The task runs the spark-submit script when the spark_submit_task field is present. - Databricks recommends using the spark_jar_task instead; see [Spark Submit task for jobs]. - - [Spark Submit task for jobs]: https://docs.databricks.com/jobs/spark-submit.html""" + Databricks recommends using the spark_jar_task instead; see [Spark Submit task for + jobs](/jobs/spark-submit).""" sql_task: Optional[SqlTask] = None """The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when @@ -7377,7 +7373,7 @@ class Task: clean_rooms_notebook_task: Optional[CleanRoomsNotebookTask] = None """The task runs a [clean rooms] notebook when the `clean_rooms_notebook_task` field is present. - [clean rooms]: https://docs.databricks.com/en/clean-rooms/index.html""" + [clean rooms]: https://docs.databricks.com/clean-rooms/index.html""" condition_task: Optional[ConditionTask] = None """The task evaluates a condition that can be used to control the execution of other tasks when the @@ -7495,9 +7491,8 @@ class Task: spark_submit_task: Optional[SparkSubmitTask] = None """(Legacy) The task runs the spark-submit script when the spark_submit_task field is present. - Databricks recommends using the spark_jar_task instead; see [Spark Submit task for jobs]. - - [Spark Submit task for jobs]: https://docs.databricks.com/jobs/spark-submit.html""" + Databricks recommends using the spark_jar_task instead; see [Spark Submit task for + jobs](/jobs/spark-submit).""" sql_task: Optional[SqlTask] = None """The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when diff --git a/databricks/sdk/service/sharing.py b/databricks/sdk/service/sharing.py index e68d110dc..ad791cc15 100755 --- a/databricks/sdk/service/sharing.py +++ b/databricks/sdk/service/sharing.py @@ -2377,6 +2377,7 @@ class TableInternalAttributesSharedTableType(Enum): FOREIGN_ICEBERG_TABLE = "FOREIGN_ICEBERG_TABLE" FOREIGN_TABLE = "FOREIGN_TABLE" MATERIALIZED_VIEW = "MATERIALIZED_VIEW" + METRIC_VIEW = "METRIC_VIEW" STREAMING_TABLE = "STREAMING_TABLE" VIEW = "VIEW"