databricks-sdk 0.158.0__tar.gz → 0.159.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/CHANGELOG.md +136 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/PKG-INFO +1 -1
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/__init__.py +16 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/config.py +4 -7
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/files.py +4 -278
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/billing.py +3 -2
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/catalog.py +18 -13
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/compute.py +19 -16
- databricks_sdk-0.159.0/databricks/sdk/service/computemigrations.py +934 -0
- databricks_sdk-0.159.0/databricks/sdk/service/genieagents.py +1524 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/iamv2.py +462 -323
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/jobs.py +977 -9
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/ml.py +21 -16
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/postgres.py +42 -11
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/sandbox.py +203 -1
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/settings.py +45 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/sql.py +12 -8
- databricks_sdk-0.159.0/databricks/sdk/version.py +1 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks_sdk.egg-info/PKG-INFO +1 -1
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks_sdk.egg-info/SOURCES.txt +2 -0
- databricks_sdk-0.158.0/databricks/sdk/version.py +0 -1
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/CONTRIBUTING.md +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/DCO +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/LICENSE +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/MANIFEST.in +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/Makefile +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/NOTICE +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/README.md +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/SECURITY.md +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_base_client.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_property.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_sandbox_grpc/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_sandbox_grpc/sandbox_service_pb2.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_sandbox_grpc/sandbox_service_pb2_grpc.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_widgets/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_widgets/default_widgets_utils.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/_widgets/ipywidgets_utils.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/azure.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/casing.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/client_types.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/clock.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/common/lro.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/common/types/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/common/types/fieldmask.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/core.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/credentials_provider.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/data_plane.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/dbutils.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/environments.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/base.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/customizer.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/deserializer.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/details.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/mapper.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/overrides.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/parser.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/platform.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/private_link.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/errors/sdk.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/logger/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/logger/round_trip_logger.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/_grpc_transport.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/compute.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/files_utils.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/jobs.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/open_ai_client.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/sandbox.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/sharing.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/mixins/workspace.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/oauth.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/oidc.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/oidc_token_supplier.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/py.typed +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/retries.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/runtime/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/runtime/dbutils_stub.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/__init__.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/_internal.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/agentbricks.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/agentkit.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/aifunctions.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/aisearch.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/apps.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/bundle.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/bundledeployments.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/cleanrooms.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/dashboards.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/database.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/dataclassification.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/dataquality.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/disasterrecovery.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/domains.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/environments.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/files.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/iam.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/knowledgeassistants.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/marketplace.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/networking.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/oauth2.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/pipelines.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/provisioning.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/qualitymonitorv2.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/serving.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/settingsv2.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/sharing.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/supervisoragents.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/tags.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/vectorsearch.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/service/workspace.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks/sdk/useragent.py +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks_sdk.egg-info/dependency_links.txt +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks_sdk.egg-info/requires.txt +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/databricks_sdk.egg-info/top_level.txt +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/pyproject.toml +0 -0
- {databricks_sdk-0.158.0 → databricks_sdk-0.159.0}/setup.cfg +0 -0
|
@@ -1,5 +1,141 @@
|
|
|
1
1
|
# Version changelog
|
|
2
2
|
|
|
3
|
+
## Release v0.159.0 (2026-11-02)
|
|
4
|
+
|
|
5
|
+
### API Changes
|
|
6
|
+
* Add `databricks.sdk.service.computemigrations` and `databricks.sdk.service.genieagents` packages.
|
|
7
|
+
* Add [w.compute_migrations](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/computemigrations/compute_migrations.html) workspace-level service.
|
|
8
|
+
* Add [w.genie_agents](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/genieagents/genie_agents.html) workspace-level service.
|
|
9
|
+
* Add `download_file()` and `upload_file()` methods for [w.sandbox](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/sandbox/sandbox.html) workspace-level service.
|
|
10
|
+
* Add `update_network_connectivity_config()` method for [a.network_connectivity](https://databricks-sdk-py.readthedocs.io/en/latest/account/settings/network_connectivity.html) account-level service.
|
|
11
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.CreateDirectGroupMemberProxyRequest`.
|
|
12
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.CreateDirectGroupMemberRequest`.
|
|
13
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.CreateGroupProxyRequest`.
|
|
14
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.CreateGroupRequest`.
|
|
15
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.CreateServicePrincipalProxyRequest`.
|
|
16
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.CreateServicePrincipalRequest`.
|
|
17
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.CreateUserProxyRequest`.
|
|
18
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.CreateUserRequest`.
|
|
19
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.CreateWorkspaceAssignmentProxyRequest`.
|
|
20
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.CreateWorkspaceAssignmentRequest`.
|
|
21
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteDirectGroupMemberProxyRequest`.
|
|
22
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteDirectGroupMemberRequest`.
|
|
23
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteGroupProxyRequest`.
|
|
24
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteGroupRequest`.
|
|
25
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteServicePrincipalProxyRequest`.
|
|
26
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteServicePrincipalRequest`.
|
|
27
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteUserProxyRequest`.
|
|
28
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteUserRequest`.
|
|
29
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteWorkspaceAssignmentProxyRequest`.
|
|
30
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.DeleteWorkspaceAssignmentRequest`.
|
|
31
|
+
* Add `name` and `parent` fields for `databricks.sdk.service.iamv2.DirectGroupMember`.
|
|
32
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetDirectGroupMemberProxyRequest`.
|
|
33
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetDirectGroupMemberRequest`.
|
|
34
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetGroupProxyRequest`.
|
|
35
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetGroupRequest`.
|
|
36
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetServicePrincipalProxyRequest`.
|
|
37
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetServicePrincipalRequest`.
|
|
38
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetUserProxyRequest`.
|
|
39
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetUserRequest`.
|
|
40
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetWorkspaceAccessDetailLocalRequest`.
|
|
41
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetWorkspaceAccessDetailRequest`.
|
|
42
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetWorkspaceAssignmentProxyRequest`.
|
|
43
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetWorkspaceAssignmentRequest`.
|
|
44
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.GetWorkspaceIdentityDetailRequest`.
|
|
45
|
+
* Add `name` and `parent` fields for `databricks.sdk.service.iamv2.Group`.
|
|
46
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListDirectGroupMembersProxyRequest`.
|
|
47
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListDirectGroupMembersRequest`.
|
|
48
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.ListGroupsProxyRequest`.
|
|
49
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListGroupsRequest`.
|
|
50
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.ListServicePrincipalsProxyRequest`.
|
|
51
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListServicePrincipalsRequest`.
|
|
52
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListTransitiveParentGroupsProxyRequest`.
|
|
53
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListTransitiveParentGroupsRequest`.
|
|
54
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.ListUsersProxyRequest`.
|
|
55
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListUsersRequest`.
|
|
56
|
+
* Add `parent` field for `databricks.sdk.service.iamv2.ListWorkspaceAssignmentsProxyRequest`.
|
|
57
|
+
* [Breaking] Add `parent` field for `databricks.sdk.service.iamv2.ListWorkspaceAssignmentsRequest`.
|
|
58
|
+
* Add `name` and `parent` fields for `databricks.sdk.service.iamv2.ServicePrincipal`.
|
|
59
|
+
* Add `name` field for `databricks.sdk.service.iamv2.TransitiveParentGroup`.
|
|
60
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateGroupProxyRequest`.
|
|
61
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateGroupRequest`.
|
|
62
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateServicePrincipalProxyRequest`.
|
|
63
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateServicePrincipalRequest`.
|
|
64
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateUserProxyRequest`.
|
|
65
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateUserRequest`.
|
|
66
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateWorkspaceAssignmentProxyRequest`.
|
|
67
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateWorkspaceAssignmentRequest`.
|
|
68
|
+
* [Breaking] Add `name` field for `databricks.sdk.service.iamv2.UpdateWorkspaceIdentityDetailRequest`.
|
|
69
|
+
* Add `name` and `parent` fields for `databricks.sdk.service.iamv2.User`.
|
|
70
|
+
* Add `name` field for `databricks.sdk.service.iamv2.WorkspaceAccessDetail`.
|
|
71
|
+
* Add `name` and `parent` fields for `databricks.sdk.service.iamv2.WorkspaceAssignment`.
|
|
72
|
+
* Add `name` field for `databricks.sdk.service.iamv2.WorkspaceIdentityDetail`.
|
|
73
|
+
* Add `serverless_compute` field for `databricks.sdk.service.jobs.JobCluster`.
|
|
74
|
+
* Add `job_completion` field for `databricks.sdk.service.jobs.PerTriggerState`.
|
|
75
|
+
* Add `ai_function_task` field for `databricks.sdk.service.jobs.ResolvedValues`.
|
|
76
|
+
* Add `ai_function_task_output` field for `databricks.sdk.service.jobs.RunOutput`.
|
|
77
|
+
* Add `ai_function_task` field for `databricks.sdk.service.jobs.RunTask`.
|
|
78
|
+
* Add `ai_function_task` field for `databricks.sdk.service.jobs.SubmitTask`.
|
|
79
|
+
* Add `ai_function_task` field for `databricks.sdk.service.jobs.Task`.
|
|
80
|
+
* Add `job_completion` field for `databricks.sdk.service.jobs.TriggerConfiguration`.
|
|
81
|
+
* Add `job_completion` field for `databricks.sdk.service.jobs.TriggerInfo`.
|
|
82
|
+
* Add `job_completion` field for `databricks.sdk.service.jobs.TriggerSettings`.
|
|
83
|
+
* Add `job_completion` field for `databricks.sdk.service.jobs.TriggerStateProto`.
|
|
84
|
+
* Add `billing_workspace_id` field for `databricks.sdk.service.settings.NetworkConnectivityConfiguration`.
|
|
85
|
+
* Add `create_feature` and `read_feature` enum values for `databricks.sdk.service.catalog.Privilege`.
|
|
86
|
+
* Add `feature` enum value for `databricks.sdk.service.catalog.SecurableType`.
|
|
87
|
+
* Add `job_completion` enum value for `databricks.sdk.service.jobs.TriggerType`.
|
|
88
|
+
* [Breaking] Change `create_direct_group_member()`, `create_group()`, `create_service_principal()`, `create_user()`, `create_workspace_assignment()`, `delete_direct_group_member()`, `delete_group()`, `delete_service_principal()`, `delete_user()`, `delete_workspace_assignment()`, `get_direct_group_member()`, `get_group()`, `get_service_principal()`, `get_user()`, `get_workspace_access_detail()`, `get_workspace_assignment()`, `list_direct_group_members()`, `list_groups()`, `list_service_principals()`, `list_transitive_parent_groups()`, `list_users()`, `list_workspace_assignments()`, `update_group()`, `update_service_principal()`, `update_user()` and `update_workspace_assignment()` methods for [a.account_iam_v2](https://databricks-sdk-py.readthedocs.io/en/latest/account/iamv2/account_iam_v2.html) account-level service with new required argument order.
|
|
89
|
+
* [Breaking] Change `create_direct_group_member()`, `create_group()`, `create_service_principal()`, `create_user()`, `create_workspace_assignment()`, `delete_direct_group_member()`, `delete_group()`, `delete_service_principal()`, `delete_user()`, `delete_workspace_assignment()`, `get_direct_group_member()`, `get_group()`, `get_service_principal()`, `get_user()`, `get_workspace_access_detail()`, `get_workspace_assignment()`, `list_direct_group_members()`, `list_groups()`, `list_service_principals()`, `list_transitive_parent_groups()`, `list_users()`, `list_workspace_assignments()`, `update_group()`, `update_service_principal()`, `update_user()` and `update_workspace_assignment()` methods for [a.account_iam_v2](https://databricks-sdk-py.readthedocs.io/en/latest/account/iamv2/account_iam_v2.html) account-level service. Method path has changed.
|
|
90
|
+
* [Breaking] Change `create_direct_group_member_proxy()`, `delete_direct_group_member_proxy()`, `delete_group_proxy()`, `delete_service_principal_proxy()`, `delete_user_proxy()`, `delete_workspace_assignment_proxy()`, `get_direct_group_member_proxy()`, `get_group_proxy()`, `get_service_principal_proxy()`, `get_user_proxy()`, `get_workspace_access_detail_local()`, `get_workspace_assignment_proxy()`, `get_workspace_identity_detail()`, `list_direct_group_members_proxy()`, `list_transitive_parent_groups_proxy()`, `update_group_proxy()`, `update_service_principal_proxy()`, `update_user_proxy()`, `update_workspace_assignment_proxy()` and `update_workspace_identity_detail()` methods for [w.workspace_iam_v2](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/iamv2/workspace_iam_v2.html) workspace-level service. Method path has changed.
|
|
91
|
+
* [Breaking] Change `create_direct_group_member_proxy()`, `delete_direct_group_member_proxy()`, `delete_group_proxy()`, `delete_service_principal_proxy()`, `delete_user_proxy()`, `delete_workspace_assignment_proxy()`, `get_direct_group_member_proxy()`, `get_group_proxy()`, `get_service_principal_proxy()`, `get_user_proxy()`, `get_workspace_access_detail_local()`, `get_workspace_assignment_proxy()`, `get_workspace_identity_detail()`, `list_direct_group_members_proxy()`, `list_transitive_parent_groups_proxy()`, `update_group_proxy()`, `update_service_principal_proxy()`, `update_user_proxy()`, `update_workspace_assignment_proxy()` and `update_workspace_identity_detail()` methods for [w.workspace_iam_v2](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/iamv2/workspace_iam_v2.html) workspace-level service with new required argument order.
|
|
92
|
+
* [Breaking] Remove `group_id` field for `databricks.sdk.service.iamv2.CreateDirectGroupMemberProxyRequest`.
|
|
93
|
+
* [Breaking] Remove `account_id` and `group_id` fields for `databricks.sdk.service.iamv2.CreateDirectGroupMemberRequest`.
|
|
94
|
+
* [Breaking] Remove `account_id` field for `databricks.sdk.service.iamv2.CreateGroupRequest`.
|
|
95
|
+
* [Breaking] Remove `account_id` field for `databricks.sdk.service.iamv2.CreateServicePrincipalRequest`.
|
|
96
|
+
* [Breaking] Remove `account_id` field for `databricks.sdk.service.iamv2.CreateUserRequest`.
|
|
97
|
+
* [Breaking] Remove `account_id` and `workspace_id` fields for `databricks.sdk.service.iamv2.CreateWorkspaceAssignmentRequest`.
|
|
98
|
+
* [Breaking] Remove `group_id` and `principal_id` fields for `databricks.sdk.service.iamv2.DeleteDirectGroupMemberProxyRequest`.
|
|
99
|
+
* [Breaking] Remove `account_id`, `group_id` and `principal_id` fields for `databricks.sdk.service.iamv2.DeleteDirectGroupMemberRequest`.
|
|
100
|
+
* [Breaking] Remove `group_id` field for `databricks.sdk.service.iamv2.DeleteGroupProxyRequest`.
|
|
101
|
+
* [Breaking] Remove `account_id` and `group_id` fields for `databricks.sdk.service.iamv2.DeleteGroupRequest`.
|
|
102
|
+
* [Breaking] Remove `service_principal_id` field for `databricks.sdk.service.iamv2.DeleteServicePrincipalProxyRequest`.
|
|
103
|
+
* [Breaking] Remove `account_id` and `service_principal_id` fields for `databricks.sdk.service.iamv2.DeleteServicePrincipalRequest`.
|
|
104
|
+
* [Breaking] Remove `user_id` field for `databricks.sdk.service.iamv2.DeleteUserProxyRequest`.
|
|
105
|
+
* [Breaking] Remove `account_id` and `user_id` fields for `databricks.sdk.service.iamv2.DeleteUserRequest`.
|
|
106
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.DeleteWorkspaceAssignmentProxyRequest`.
|
|
107
|
+
* [Breaking] Remove `account_id`, `workspace_id` and `principal_id` fields for `databricks.sdk.service.iamv2.DeleteWorkspaceAssignmentRequest`.
|
|
108
|
+
* [Breaking] Remove `group_id` and `principal_id` fields for `databricks.sdk.service.iamv2.GetDirectGroupMemberProxyRequest`.
|
|
109
|
+
* [Breaking] Remove `account_id`, `group_id` and `principal_id` fields for `databricks.sdk.service.iamv2.GetDirectGroupMemberRequest`.
|
|
110
|
+
* [Breaking] Remove `group_id` field for `databricks.sdk.service.iamv2.GetGroupProxyRequest`.
|
|
111
|
+
* [Breaking] Remove `account_id` and `group_id` fields for `databricks.sdk.service.iamv2.GetGroupRequest`.
|
|
112
|
+
* [Breaking] Remove `service_principal_id` field for `databricks.sdk.service.iamv2.GetServicePrincipalProxyRequest`.
|
|
113
|
+
* [Breaking] Remove `account_id` and `service_principal_id` fields for `databricks.sdk.service.iamv2.GetServicePrincipalRequest`.
|
|
114
|
+
* [Breaking] Remove `user_id` field for `databricks.sdk.service.iamv2.GetUserProxyRequest`.
|
|
115
|
+
* [Breaking] Remove `account_id` and `user_id` fields for `databricks.sdk.service.iamv2.GetUserRequest`.
|
|
116
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.GetWorkspaceAccessDetailLocalRequest`.
|
|
117
|
+
* [Breaking] Remove `account_id`, `workspace_id` and `principal_id` fields for `databricks.sdk.service.iamv2.GetWorkspaceAccessDetailRequest`.
|
|
118
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.GetWorkspaceAssignmentProxyRequest`.
|
|
119
|
+
* [Breaking] Remove `account_id`, `workspace_id` and `principal_id` fields for `databricks.sdk.service.iamv2.GetWorkspaceAssignmentRequest`.
|
|
120
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.GetWorkspaceIdentityDetailRequest`.
|
|
121
|
+
* [Breaking] Remove `group_id` field for `databricks.sdk.service.iamv2.ListDirectGroupMembersProxyRequest`.
|
|
122
|
+
* [Breaking] Remove `account_id` and `group_id` fields for `databricks.sdk.service.iamv2.ListDirectGroupMembersRequest`.
|
|
123
|
+
* [Breaking] Remove `account_id` field for `databricks.sdk.service.iamv2.ListGroupsRequest`.
|
|
124
|
+
* [Breaking] Remove `account_id` field for `databricks.sdk.service.iamv2.ListServicePrincipalsRequest`.
|
|
125
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.ListTransitiveParentGroupsProxyRequest`.
|
|
126
|
+
* [Breaking] Remove `account_id` and `principal_id` fields for `databricks.sdk.service.iamv2.ListTransitiveParentGroupsRequest`.
|
|
127
|
+
* [Breaking] Remove `account_id` field for `databricks.sdk.service.iamv2.ListUsersRequest`.
|
|
128
|
+
* [Breaking] Remove `account_id` and `workspace_id` fields for `databricks.sdk.service.iamv2.ListWorkspaceAssignmentsRequest`.
|
|
129
|
+
* [Breaking] Remove `group_id` field for `databricks.sdk.service.iamv2.UpdateGroupProxyRequest`.
|
|
130
|
+
* [Breaking] Remove `account_id` and `group_id` fields for `databricks.sdk.service.iamv2.UpdateGroupRequest`.
|
|
131
|
+
* [Breaking] Remove `service_principal_id` field for `databricks.sdk.service.iamv2.UpdateServicePrincipalProxyRequest`.
|
|
132
|
+
* [Breaking] Remove `account_id` and `service_principal_id` fields for `databricks.sdk.service.iamv2.UpdateServicePrincipalRequest`.
|
|
133
|
+
* [Breaking] Remove `user_id` field for `databricks.sdk.service.iamv2.UpdateUserProxyRequest`.
|
|
134
|
+
* [Breaking] Remove `account_id` and `user_id` fields for `databricks.sdk.service.iamv2.UpdateUserRequest`.
|
|
135
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.UpdateWorkspaceAssignmentProxyRequest`.
|
|
136
|
+
* [Breaking] Remove `account_id`, `workspace_id` and `principal_id` fields for `databricks.sdk.service.iamv2.UpdateWorkspaceAssignmentRequest`.
|
|
137
|
+
* [Breaking] Remove `principal_id` field for `databricks.sdk.service.iamv2.UpdateWorkspaceIdentityDetailRequest`.
|
|
138
|
+
|
|
3
139
|
## Release v0.158.0 (2026-10-29)
|
|
4
140
|
|
|
5
141
|
### API Changes
|
|
@@ -19,6 +19,7 @@ from databricks.sdk.service import bundledeployments as pkg_bundledeployments
|
|
|
19
19
|
from databricks.sdk.service import catalog as pkg_catalog
|
|
20
20
|
from databricks.sdk.service import cleanrooms as pkg_cleanrooms
|
|
21
21
|
from databricks.sdk.service import compute as pkg_compute
|
|
22
|
+
from databricks.sdk.service import computemigrations as pkg_computemigrations
|
|
22
23
|
from databricks.sdk.service import dashboards as pkg_dashboards
|
|
23
24
|
from databricks.sdk.service import database as pkg_database
|
|
24
25
|
from databricks.sdk.service import dataclassification as pkg_dataclassification
|
|
@@ -27,6 +28,7 @@ from databricks.sdk.service import disasterrecovery as pkg_disasterrecovery
|
|
|
27
28
|
from databricks.sdk.service import domains as pkg_domains
|
|
28
29
|
from databricks.sdk.service import environments as pkg_environments
|
|
29
30
|
from databricks.sdk.service import files as pkg_files
|
|
31
|
+
from databricks.sdk.service import genieagents as pkg_genieagents
|
|
30
32
|
from databricks.sdk.service import iam as pkg_iam
|
|
31
33
|
from databricks.sdk.service import iamv2 as pkg_iamv2
|
|
32
34
|
from databricks.sdk.service import jobs as pkg_jobs
|
|
@@ -88,6 +90,7 @@ from databricks.sdk.service.compute import ClusterPoliciesAPI
|
|
|
88
90
|
from databricks.sdk.service.compute import ClustersAPI
|
|
89
91
|
from databricks.sdk.service.compute import CommandExecutionAPI
|
|
90
92
|
from databricks.sdk.service.settings import ComplianceSecurityProfileAPI
|
|
93
|
+
from databricks.sdk.service.computemigrations import ComputeMigrationsAPI
|
|
91
94
|
from databricks.sdk.service.catalog import ConnectionsAPI
|
|
92
95
|
from databricks.sdk.service.marketplace import ConsumerFulfillmentsAPI
|
|
93
96
|
from databricks.sdk.service.marketplace import ConsumerInstallationsAPI
|
|
@@ -137,6 +140,7 @@ from databricks.sdk.service.files import FilesAPI
|
|
|
137
140
|
from databricks.sdk.service.ml import ForecastingAPI
|
|
138
141
|
from databricks.sdk.service.catalog import FunctionsAPI
|
|
139
142
|
from databricks.sdk.service.dashboards import GenieAPI
|
|
143
|
+
from databricks.sdk.service.genieagents import GenieAgentsAPI
|
|
140
144
|
from databricks.sdk.service.workspace import GitCredentialsAPI
|
|
141
145
|
from databricks.sdk.service.compute import GlobalInitScriptsAPI
|
|
142
146
|
from databricks.sdk.service.catalog import GrantsAPI
|
|
@@ -389,6 +393,7 @@ class WorkspaceClient:
|
|
|
389
393
|
self._cluster_policies = pkg_compute.ClusterPoliciesAPI(self._api_client)
|
|
390
394
|
self._clusters = ClustersExt(self._api_client)
|
|
391
395
|
self._command_execution = pkg_compute.CommandExecutionAPI(self._api_client)
|
|
396
|
+
self._compute_migrations = pkg_computemigrations.ComputeMigrationsAPI(self._api_client)
|
|
392
397
|
self._connections = pkg_catalog.ConnectionsAPI(self._api_client)
|
|
393
398
|
self._consumer_fulfillments = pkg_marketplace.ConsumerFulfillmentsAPI(self._api_client)
|
|
394
399
|
self._consumer_installations = pkg_marketplace.ConsumerInstallationsAPI(self._api_client)
|
|
@@ -419,6 +424,7 @@ class WorkspaceClient:
|
|
|
419
424
|
self._forecasting = pkg_ml.ForecastingAPI(self._api_client)
|
|
420
425
|
self._functions = pkg_catalog.FunctionsAPI(self._api_client)
|
|
421
426
|
self._genie = pkg_dashboards.GenieAPI(self._api_client)
|
|
427
|
+
self._genie_agents = pkg_genieagents.GenieAgentsAPI(self._api_client)
|
|
422
428
|
self._git_credentials = pkg_workspace.GitCredentialsAPI(self._api_client)
|
|
423
429
|
self._global_init_scripts = pkg_compute.GlobalInitScriptsAPI(self._api_client)
|
|
424
430
|
self._grants = pkg_catalog.GrantsAPI(self._api_client)
|
|
@@ -642,6 +648,11 @@ class WorkspaceClient:
|
|
|
642
648
|
"""This API allows execution of Python, Scala, SQL, or R commands on running Databricks Clusters."""
|
|
643
649
|
return self._command_execution
|
|
644
650
|
|
|
651
|
+
@property
|
|
652
|
+
def compute_migrations(self) -> pkg_computemigrations.ComputeMigrationsAPI:
|
|
653
|
+
"""Manage migrations of Classic compute workloads to Serverless."""
|
|
654
|
+
return self._compute_migrations
|
|
655
|
+
|
|
645
656
|
@property
|
|
646
657
|
def connections(self) -> pkg_catalog.ConnectionsAPI:
|
|
647
658
|
"""A connection represents an external data source for use within Databricks."""
|
|
@@ -787,6 +798,11 @@ class WorkspaceClient:
|
|
|
787
798
|
"""Genie provides a no-code experience for business users, powered by AI/BI."""
|
|
788
799
|
return self._genie
|
|
789
800
|
|
|
801
|
+
@property
|
|
802
|
+
def genie_agents(self) -> pkg_genieagents.GenieAgentsAPI:
|
|
803
|
+
"""Genie provides a no-code experience for business users, powered by AI/BI."""
|
|
804
|
+
return self._genie_agents
|
|
805
|
+
|
|
790
806
|
@property
|
|
791
807
|
def git_credentials(self) -> pkg_workspace.GitCredentialsAPI:
|
|
792
808
|
"""Registers personal access token for Databricks to do operations on behalf of the user."""
|
|
@@ -179,7 +179,7 @@ class Config:
|
|
|
179
179
|
# File multipart upload/download parameters
|
|
180
180
|
# ----------------------
|
|
181
181
|
|
|
182
|
-
# Minimal input stream size (bytes) to use multipart
|
|
182
|
+
# Minimal input stream size (bytes) to use multipart uploads.
|
|
183
183
|
# For small files it's more efficient to make one single-shot upload request.
|
|
184
184
|
# When uploading a file, SDK will initially buffer this many bytes from input stream.
|
|
185
185
|
# This parameter can be less or bigger than multipart_upload_chunk_size.
|
|
@@ -247,12 +247,9 @@ class Config:
|
|
|
247
247
|
# but a maximum time between consecutive data reception events (even 1 byte) from the server
|
|
248
248
|
files_ext_network_transfer_inactivity_timeout_seconds: float = 60
|
|
249
249
|
|
|
250
|
-
# Cap on the number of custom retries during
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
# retrieved to continue the upload.
|
|
254
|
-
# In these two cases standard SDK retries (which are capped by the `retry_timeout_seconds` option) are not used.
|
|
255
|
-
# Note that retry counter is reset when upload is successfully resumed.
|
|
250
|
+
# Cap on the number of custom retries during multipart uploads, when an upload part URL is expired and new
|
|
251
|
+
# upload URLs must be requested to continue the upload. Standard SDK retries (capped by the
|
|
252
|
+
# `retry_timeout_seconds` option) are not used in this case.
|
|
256
253
|
files_ext_multipart_upload_max_retries = 3
|
|
257
254
|
|
|
258
255
|
# Cap on the number of custom retries during parallel downloads.
|
|
@@ -7,7 +7,6 @@ import math
|
|
|
7
7
|
import os
|
|
8
8
|
import pathlib
|
|
9
9
|
import platform
|
|
10
|
-
import re
|
|
11
10
|
import shutil
|
|
12
11
|
import xml.etree.ElementTree as ET
|
|
13
12
|
from abc import ABC, abstractmethod
|
|
@@ -32,7 +31,7 @@ from requests import RequestException
|
|
|
32
31
|
from .._base_client import _BaseClient, _RawResponse, _StreamingResponse
|
|
33
32
|
from .._property import _cached_property
|
|
34
33
|
from ..config import Config
|
|
35
|
-
from ..errors import
|
|
34
|
+
from ..errors import InternalError, NotFound, PermissionDenied
|
|
36
35
|
from ..errors.mapper import _error_mapper
|
|
37
36
|
from ..retries import retried
|
|
38
37
|
from databricks.sdk.service import files
|
|
@@ -779,8 +778,8 @@ class _Endpoint:
|
|
|
779
778
|
class _PresignedUrlRequestBuilder:
|
|
780
779
|
"""Builds presigned URL requests for file upload operations.
|
|
781
780
|
|
|
782
|
-
Encapsulates the coordination API calls (create-upload-part-urls,
|
|
783
|
-
|
|
781
|
+
Encapsulates the coordination API calls (create-upload-part-urls, create-download-url) and response parsing
|
|
782
|
+
into a single place.
|
|
784
783
|
"""
|
|
785
784
|
|
|
786
785
|
def __init__(self, api, hostname: str):
|
|
@@ -817,27 +816,6 @@ class _PresignedUrlRequestBuilder:
|
|
|
817
816
|
results.append(_PresignedUrl(url=url, headers=headers, part_number=part_number))
|
|
818
817
|
return results
|
|
819
818
|
|
|
820
|
-
def build_resumable_upload_url(self, path: str, session_token: str) -> _PresignedUrl:
|
|
821
|
-
"""Fetches a presigned URL for resumable upload."""
|
|
822
|
-
body = {"path": path, "session_token": session_token}
|
|
823
|
-
# The _api.do() method handles retries and will raise an exception in case of failure.
|
|
824
|
-
response = self._api.do(
|
|
825
|
-
"POST",
|
|
826
|
-
url=f"{self._hostname}/api/2.0/fs/create-resumable-upload-url",
|
|
827
|
-
headers={"Content-Type": "application/json"},
|
|
828
|
-
body=body,
|
|
829
|
-
)
|
|
830
|
-
url_node = response.get("resumable_upload_url")
|
|
831
|
-
if not url_node:
|
|
832
|
-
raise ValueError(f"Unexpected server response: {response}")
|
|
833
|
-
url = url_node.get("url")
|
|
834
|
-
if not url:
|
|
835
|
-
raise ValueError(f"Unexpected server response: {response}")
|
|
836
|
-
headers: dict[str, str] = {}
|
|
837
|
-
for h in url_node.get("headers", []):
|
|
838
|
-
headers[h["name"]] = h["value"]
|
|
839
|
-
return _PresignedUrl(url=url, headers=headers)
|
|
840
|
-
|
|
841
819
|
def build_download_url(self, path: str, expire_time: str) -> CreateDownloadUrlResponse:
|
|
842
820
|
"""Fetches a presigned URL for downloading a file."""
|
|
843
821
|
response = self._api.do(
|
|
@@ -888,21 +866,6 @@ class _StorageProxyRequestBuilder:
|
|
|
888
866
|
)
|
|
889
867
|
return results
|
|
890
868
|
|
|
891
|
-
def build_resumable_upload_url(self, path: str, session_token: str) -> _PresignedUrl:
|
|
892
|
-
"""Builds a URL for resumable upload directly to the storage proxy."""
|
|
893
|
-
escaped = _escape_multi_segment_path_parameter(path)
|
|
894
|
-
base = f"{self._hostname}/api/2.0/fs/files{escaped}"
|
|
895
|
-
query = parse.urlencode(
|
|
896
|
-
{
|
|
897
|
-
"session_token": session_token,
|
|
898
|
-
"upload_type": "resumable",
|
|
899
|
-
}
|
|
900
|
-
)
|
|
901
|
-
return _PresignedUrl(
|
|
902
|
-
url=f"{base}?{query}",
|
|
903
|
-
headers={"Content-Type": "application/octet-stream"},
|
|
904
|
-
)
|
|
905
|
-
|
|
906
869
|
def build_download_url(self, path: str, expire_time: str) -> CreateDownloadUrlResponse:
|
|
907
870
|
"""Builds a URL for downloading a file directly from the storage proxy."""
|
|
908
871
|
escaped = _escape_multi_segment_path_parameter(path)
|
|
@@ -952,7 +915,6 @@ class FilesExt(files.FilesAPI):
|
|
|
952
915
|
def __init__(self, api_client, config: Config):
|
|
953
916
|
super().__init__(api_client)
|
|
954
917
|
self._config = config.copy()
|
|
955
|
-
self._multipart_upload_read_ahead_bytes = 1
|
|
956
918
|
self._cached_cloud_provider_session: Optional[requests.Session] = None
|
|
957
919
|
self._cloud_provider_session_lock = Lock()
|
|
958
920
|
self._dp_hostname_available: Optional[bool] = None
|
|
@@ -1713,16 +1675,6 @@ class FilesExt(files.FilesAPI):
|
|
|
1713
1675
|
# Rethrow the original exception
|
|
1714
1676
|
raise e from None
|
|
1715
1677
|
|
|
1716
|
-
elif initiate_upload_response.get("resumable_upload"):
|
|
1717
|
-
session_token = initiate_upload_response["resumable_upload"]["session_token"]
|
|
1718
|
-
|
|
1719
|
-
try:
|
|
1720
|
-
self._perform_resumable_upload(ctx, contents, session_token, pre_read_buffer)
|
|
1721
|
-
except FallbackToUploadUsingFilesApi as e:
|
|
1722
|
-
_LOG.info(f"Falling back to single-shot upload with Files API: {e}")
|
|
1723
|
-
# Concatenate the buffered part and the rest of the stream.
|
|
1724
|
-
full_stream = _ConcatenatedInputStream(BytesIO(e.buffer), contents)
|
|
1725
|
-
return self._single_thread_single_shot_upload(ctx, full_stream)
|
|
1726
1678
|
else:
|
|
1727
1679
|
raise ValueError(f"Unexpected server response: {initiate_upload_response}")
|
|
1728
1680
|
|
|
@@ -1734,10 +1686,7 @@ class FilesExt(files.FilesAPI):
|
|
|
1734
1686
|
"""
|
|
1735
1687
|
initiate_upload_response = self._initiate_multipart_upload(ctx)
|
|
1736
1688
|
|
|
1737
|
-
if initiate_upload_response.get("
|
|
1738
|
-
_LOG.warning("GCP does not support parallel resumable uploads, falling back to single-threaded upload")
|
|
1739
|
-
return self._single_thread_multipart_upload(ctx, contents)
|
|
1740
|
-
elif initiate_upload_response.get("multipart_upload"):
|
|
1689
|
+
if initiate_upload_response.get("multipart_upload"):
|
|
1741
1690
|
session_token = initiate_upload_response["multipart_upload"].get("session_token")
|
|
1742
1691
|
if not session_token:
|
|
1743
1692
|
raise ValueError(f"Unexpected server response: {initiate_upload_response}")
|
|
@@ -1803,10 +1752,6 @@ class FilesExt(files.FilesAPI):
|
|
|
1803
1752
|
# Rethrow the original exception.
|
|
1804
1753
|
raise e from None
|
|
1805
1754
|
|
|
1806
|
-
elif initiate_upload_response.get("resumable_upload"):
|
|
1807
|
-
_LOG.warning("GCP does not support parallel resumable uploads, falling back to single-threaded upload")
|
|
1808
|
-
with open(ctx.source_file_path, "rb") as f:
|
|
1809
|
-
return self._upload_single_thread_with_known_size(ctx, f)
|
|
1810
1755
|
else:
|
|
1811
1756
|
raise ValueError(f"Unexpected server response: {initiate_upload_response}")
|
|
1812
1757
|
|
|
@@ -2339,212 +2284,6 @@ class FilesExt(files.FilesAPI):
|
|
|
2339
2284
|
return True
|
|
2340
2285
|
return False
|
|
2341
2286
|
|
|
2342
|
-
def _perform_resumable_upload(
|
|
2343
|
-
self,
|
|
2344
|
-
ctx: _UploadContext,
|
|
2345
|
-
input_stream: BinaryIO,
|
|
2346
|
-
session_token: str,
|
|
2347
|
-
pre_read_buffer: bytes,
|
|
2348
|
-
) -> None:
|
|
2349
|
-
"""
|
|
2350
|
-
Performs resumable upload on GCP: https://cloud.google.com/storage/docs/performing-resumable-uploads
|
|
2351
|
-
"""
|
|
2352
|
-
# Session URI we're using expires after a week
|
|
2353
|
-
|
|
2354
|
-
# Why are we buffering the current chunk?
|
|
2355
|
-
# When using resumable upload API we're uploading data in chunks. During chunk upload
|
|
2356
|
-
# server responds with the "received offset" confirming how much data it stored so far,
|
|
2357
|
-
# so we should continue uploading from that offset. (Note this is not a failure but an
|
|
2358
|
-
# expected behaviour as per the docs.) But, input stream might be consumed beyond that
|
|
2359
|
-
# offset, since server might have read more data than it confirmed received, or some data
|
|
2360
|
-
# might have been pre-cached by e.g. OS or a proxy. So, to continue upload, we must rewind
|
|
2361
|
-
# the input stream back to the byte next to "received offset". This is not possible
|
|
2362
|
-
# for non-seekable input stream, so we must buffer the whole last chunk and seek inside
|
|
2363
|
-
# the buffer. By always uploading from the buffer we fully support non-seekable streams.
|
|
2364
|
-
|
|
2365
|
-
# Why are we doing read-ahead?
|
|
2366
|
-
# It's not possible to upload an empty chunk as "Content-Range" header format does not
|
|
2367
|
-
# support this. So if current chunk happens to finish exactly at the end of the stream,
|
|
2368
|
-
# we need to know that and mark the chunk as last (by passing real file size in the
|
|
2369
|
-
# "Content-Range" header) when uploading it. To detect if we're at the end of the stream
|
|
2370
|
-
# we're reading "ahead" an extra bytes but not uploading them immediately. If
|
|
2371
|
-
# nothing has been read ahead, it means we're at the end of the stream.
|
|
2372
|
-
# On the contrary, in multipart upload we can decide to complete upload *after*
|
|
2373
|
-
# last chunk has been sent.
|
|
2374
|
-
|
|
2375
|
-
builder = self._create_request_builder()
|
|
2376
|
-
|
|
2377
|
-
try:
|
|
2378
|
-
presigned = builder.build_resumable_upload_url(ctx.target_path, session_token)
|
|
2379
|
-
except Exception as e:
|
|
2380
|
-
raise FallbackToUploadUsingFilesApi(
|
|
2381
|
-
pre_read_buffer, f"Failed to obtain resumable upload URL: {e}, falling back to single shot upload"
|
|
2382
|
-
) from e
|
|
2383
|
-
|
|
2384
|
-
resumable_upload_url = presigned.url
|
|
2385
|
-
base_headers = presigned.headers
|
|
2386
|
-
|
|
2387
|
-
try:
|
|
2388
|
-
# We will buffer this many bytes: one chunk + read-ahead block.
|
|
2389
|
-
# Note buffer may contain more data initially (from pre_read_buffer).
|
|
2390
|
-
min_buffer_size = ctx.part_size + self._multipart_upload_read_ahead_bytes
|
|
2391
|
-
|
|
2392
|
-
buffer = pre_read_buffer
|
|
2393
|
-
|
|
2394
|
-
# How many bytes in the buffer were confirmed to be received by the server.
|
|
2395
|
-
# All the remaining bytes in the buffer must be uploaded.
|
|
2396
|
-
uploaded_bytes_count = 0
|
|
2397
|
-
|
|
2398
|
-
chunk_offset = 0
|
|
2399
|
-
|
|
2400
|
-
retry_count = 0
|
|
2401
|
-
while True:
|
|
2402
|
-
# If needed, fill the buffer to contain at least min_buffer_size bytes
|
|
2403
|
-
# (unless end of stream), discarding already uploaded bytes.
|
|
2404
|
-
bytes_to_read = max(0, min_buffer_size - (len(buffer) - uploaded_bytes_count))
|
|
2405
|
-
next_buf = input_stream.read(bytes_to_read)
|
|
2406
|
-
buffer = buffer[uploaded_bytes_count:] + next_buf
|
|
2407
|
-
|
|
2408
|
-
if len(next_buf) < bytes_to_read:
|
|
2409
|
-
# This is the last chunk in the stream.
|
|
2410
|
-
# Let's upload all the remaining bytes in one go.
|
|
2411
|
-
actual_chunk_length = len(buffer)
|
|
2412
|
-
file_size = chunk_offset + actual_chunk_length
|
|
2413
|
-
else:
|
|
2414
|
-
# More chunks expected, let's upload current chunk (excluding read-ahead block).
|
|
2415
|
-
actual_chunk_length = ctx.part_size
|
|
2416
|
-
file_size = "*"
|
|
2417
|
-
|
|
2418
|
-
headers: dict = {"Content-Type": "application/octet-stream", **base_headers}
|
|
2419
|
-
|
|
2420
|
-
chunk_last_byte_offset = chunk_offset + actual_chunk_length - 1
|
|
2421
|
-
content_range_header = f"bytes {chunk_offset}-{chunk_last_byte_offset}/{file_size}"
|
|
2422
|
-
_LOG.debug(f"Uploading chunk: {content_range_header}")
|
|
2423
|
-
headers["Content-Range"] = content_range_header
|
|
2424
|
-
|
|
2425
|
-
def retrieve_upload_status() -> Optional[requests.Response]:
|
|
2426
|
-
def perform():
|
|
2427
|
-
return self._cloud_provider_session().request(
|
|
2428
|
-
"PUT",
|
|
2429
|
-
resumable_upload_url,
|
|
2430
|
-
headers={"Content-Range": "bytes */*"},
|
|
2431
|
-
data=b"",
|
|
2432
|
-
timeout=self._config.files_ext_network_transfer_inactivity_timeout_seconds,
|
|
2433
|
-
)
|
|
2434
|
-
|
|
2435
|
-
try:
|
|
2436
|
-
return self._retry_cloud_idempotent_operation(perform)
|
|
2437
|
-
except RequestException:
|
|
2438
|
-
_LOG.warning("Failed to retrieve upload status")
|
|
2439
|
-
return None
|
|
2440
|
-
|
|
2441
|
-
try:
|
|
2442
|
-
upload_response = self._cloud_provider_session().request(
|
|
2443
|
-
"PUT",
|
|
2444
|
-
resumable_upload_url,
|
|
2445
|
-
headers=headers,
|
|
2446
|
-
data=BytesIO(buffer[:actual_chunk_length]),
|
|
2447
|
-
timeout=self._config.files_ext_network_transfer_inactivity_timeout_seconds,
|
|
2448
|
-
)
|
|
2449
|
-
|
|
2450
|
-
# https://cloud.google.com/storage/docs/performing-resumable-uploads#resume-upload
|
|
2451
|
-
# If an upload request is terminated before receiving a response, or if you receive
|
|
2452
|
-
# a 503 or 500 response, then you need to resume the interrupted upload from where it left off.
|
|
2453
|
-
|
|
2454
|
-
# Let's follow that for all potentially retryable status codes.
|
|
2455
|
-
if upload_response.status_code in self._RETRYABLE_STATUS_CODES:
|
|
2456
|
-
if retry_count < self._config.files_ext_multipart_upload_max_retries:
|
|
2457
|
-
retry_count += 1
|
|
2458
|
-
# let original upload_response be handled as an error
|
|
2459
|
-
upload_response = retrieve_upload_status() or upload_response
|
|
2460
|
-
else:
|
|
2461
|
-
# we received non-retryable response, reset retry count
|
|
2462
|
-
retry_count = 0
|
|
2463
|
-
|
|
2464
|
-
except RequestException as e:
|
|
2465
|
-
# Let's do the same for retryable network errors.
|
|
2466
|
-
if (
|
|
2467
|
-
_BaseClient._is_retryable(e)
|
|
2468
|
-
and retry_count < self._config.files_ext_multipart_upload_max_retries
|
|
2469
|
-
):
|
|
2470
|
-
retry_count += 1
|
|
2471
|
-
upload_response = retrieve_upload_status()
|
|
2472
|
-
if not upload_response:
|
|
2473
|
-
# rethrow original exception
|
|
2474
|
-
raise e from None
|
|
2475
|
-
else:
|
|
2476
|
-
# rethrow original exception
|
|
2477
|
-
raise e from None
|
|
2478
|
-
|
|
2479
|
-
if upload_response.status_code in (200, 201):
|
|
2480
|
-
if file_size == "*":
|
|
2481
|
-
raise ValueError(
|
|
2482
|
-
f"Received unexpected status {upload_response.status_code} before reaching end of stream"
|
|
2483
|
-
)
|
|
2484
|
-
|
|
2485
|
-
# upload complete
|
|
2486
|
-
break
|
|
2487
|
-
|
|
2488
|
-
elif upload_response.status_code == 308:
|
|
2489
|
-
# chunk accepted (or check-status succeeded), let's determine received offset to resume from there
|
|
2490
|
-
range_string = upload_response.headers.get("Range")
|
|
2491
|
-
confirmed_offset = self._extract_range_offset(range_string)
|
|
2492
|
-
_LOG.debug(f"Received confirmed offset: {confirmed_offset}")
|
|
2493
|
-
|
|
2494
|
-
if confirmed_offset:
|
|
2495
|
-
if confirmed_offset < chunk_offset - 1 or confirmed_offset > chunk_last_byte_offset:
|
|
2496
|
-
raise ValueError(
|
|
2497
|
-
f"Unexpected received offset: {confirmed_offset} is outside of expected range, chunk offset: {chunk_offset}, chunk last byte offset: {chunk_last_byte_offset}"
|
|
2498
|
-
)
|
|
2499
|
-
else:
|
|
2500
|
-
if chunk_offset > 0:
|
|
2501
|
-
raise ValueError(
|
|
2502
|
-
f"Unexpected received offset: {confirmed_offset} is outside of expected range, chunk offset: {chunk_offset}, chunk last byte offset: {chunk_last_byte_offset}"
|
|
2503
|
-
)
|
|
2504
|
-
|
|
2505
|
-
# We have just uploaded a part of chunk starting from offset "chunk_offset" and ending
|
|
2506
|
-
# at offset "confirmed_offset" (inclusive), so the next chunk will start at
|
|
2507
|
-
# offset "confirmed_offset + 1"
|
|
2508
|
-
if confirmed_offset:
|
|
2509
|
-
next_chunk_offset = confirmed_offset + 1
|
|
2510
|
-
else:
|
|
2511
|
-
next_chunk_offset = chunk_offset
|
|
2512
|
-
uploaded_bytes_count = next_chunk_offset - chunk_offset
|
|
2513
|
-
chunk_offset = next_chunk_offset
|
|
2514
|
-
|
|
2515
|
-
elif upload_response.status_code == 412 and not ctx.overwrite:
|
|
2516
|
-
# Assuming this is only possible reason
|
|
2517
|
-
# Full message in this case: "At least one of the pre-conditions you specified did not hold."
|
|
2518
|
-
raise AlreadyExists("The file being created already exists.")
|
|
2519
|
-
|
|
2520
|
-
else:
|
|
2521
|
-
message = f"Unsuccessful chunk upload. Response status: {upload_response.status_code}, body: {upload_response.content}"
|
|
2522
|
-
_LOG.warning(message)
|
|
2523
|
-
mapped_error = _error_mapper(upload_response, {})
|
|
2524
|
-
raise mapped_error or ValueError(message)
|
|
2525
|
-
|
|
2526
|
-
except Exception as e:
|
|
2527
|
-
_LOG.info(f"Aborting resumable upload on error: {e}")
|
|
2528
|
-
try:
|
|
2529
|
-
self._abort_resumable_upload(resumable_upload_url, base_headers)
|
|
2530
|
-
except BaseException as ex:
|
|
2531
|
-
_LOG.warning(f"Failed to abort upload: {ex}")
|
|
2532
|
-
# ignore, abort is a best-effort
|
|
2533
|
-
finally:
|
|
2534
|
-
# rethrow original exception
|
|
2535
|
-
raise e from None
|
|
2536
|
-
|
|
2537
|
-
@staticmethod
|
|
2538
|
-
def _extract_range_offset(range_string: Optional[str]) -> Optional[int]:
|
|
2539
|
-
"""Parses the response range header to extract the last byte."""
|
|
2540
|
-
if not range_string:
|
|
2541
|
-
return None # server did not yet confirm any bytes
|
|
2542
|
-
|
|
2543
|
-
if match := re.match("bytes=0-(\\d+)", range_string):
|
|
2544
|
-
return int(match.group(1))
|
|
2545
|
-
else:
|
|
2546
|
-
raise ValueError(f"Cannot parse response header: Range: {range_string}")
|
|
2547
|
-
|
|
2548
2287
|
def _get_rfc339_timestamp_with_future_offset(self, base_time: datetime.datetime, offset: timedelta) -> str:
|
|
2549
2288
|
"""Generates an offset timestamp in an RFC3339 format suitable for URL generation"""
|
|
2550
2289
|
offset_timestamp = base_time + offset
|
|
@@ -2584,19 +2323,6 @@ class FilesExt(files.FilesAPI):
|
|
|
2584
2323
|
if not abort_response.ok:
|
|
2585
2324
|
raise ValueError(abort_response)
|
|
2586
2325
|
|
|
2587
|
-
def _abort_resumable_upload(self, resumable_upload_url: str, headers: dict[str, str]) -> None:
|
|
2588
|
-
"""Aborts ongoing resumable upload session to clean up incomplete file. Best-effort, so sent once."""
|
|
2589
|
-
abort_response = self._cloud_provider_session().request(
|
|
2590
|
-
"DELETE",
|
|
2591
|
-
resumable_upload_url,
|
|
2592
|
-
headers=headers,
|
|
2593
|
-
data=b"",
|
|
2594
|
-
timeout=self._config.files_ext_network_transfer_inactivity_timeout_seconds,
|
|
2595
|
-
)
|
|
2596
|
-
|
|
2597
|
-
if abort_response.status_code not in (200, 201):
|
|
2598
|
-
raise ValueError(abort_response)
|
|
2599
|
-
|
|
2600
2326
|
def _cloud_provider_session(self) -> requests.Session:
|
|
2601
2327
|
"""Returns a session for cloud storage operations.
|
|
2602
2328
|
|
|
@@ -195,8 +195,9 @@ class AlertSpendStatus:
|
|
|
195
195
|
percent_consumed: Optional[str] = None
|
|
196
196
|
"""Percentage of the threshold consumed, as a decimal string rounded down to one decimal place (for
|
|
197
197
|
example, "68.4" means 68.4%). May exceed 100 when spend is over the threshold. Returns "0.0" if
|
|
198
|
-
there's no spend,
|
|
199
|
-
value returned; the absolute ``spend`` and ``threshold`` dollar amounts are
|
|
198
|
+
there's no spend, except that a $0 threshold always returns "100.0". For shared thresholds, this
|
|
199
|
+
is the only value returned; the absolute ``spend`` and ``threshold`` dollar amounts are
|
|
200
|
+
withheld."""
|
|
200
201
|
|
|
201
202
|
scope_type: Optional[AlertConfigurationScopeType] = None
|
|
202
203
|
"""Whether the threshold is evaluated per individual user
|