databricks-sdk 0.18.0__py3-none-any.whl → 0.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of databricks-sdk might be problematic. Click here for more details.
- databricks/sdk/__init__.py +30 -1
- databricks/sdk/azure.py +14 -0
- databricks/sdk/clock.py +49 -0
- databricks/sdk/config.py +7 -0
- databricks/sdk/core.py +2 -1
- databricks/sdk/credentials_provider.py +14 -3
- databricks/sdk/environments.py +1 -1
- databricks/sdk/errors/__init__.py +1 -1
- databricks/sdk/errors/mapper.py +5 -5
- databricks/sdk/mixins/workspace.py +3 -3
- databricks/sdk/retries.py +9 -5
- databricks/sdk/service/catalog.py +173 -78
- databricks/sdk/service/compute.py +86 -25
- databricks/sdk/service/files.py +136 -22
- databricks/sdk/service/iam.py +42 -36
- databricks/sdk/service/jobs.py +192 -14
- databricks/sdk/service/ml.py +27 -36
- databricks/sdk/service/oauth2.py +3 -4
- databricks/sdk/service/pipelines.py +50 -29
- databricks/sdk/service/settings.py +338 -57
- databricks/sdk/service/sharing.py +3 -4
- databricks/sdk/service/sql.py +24 -17
- databricks/sdk/service/vectorsearch.py +13 -17
- databricks/sdk/service/workspace.py +18 -7
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.18.0.dist-info → databricks_sdk-0.19.0.dist-info}/METADATA +1 -1
- databricks_sdk-0.19.0.dist-info/RECORD +53 -0
- databricks_sdk-0.18.0.dist-info/RECORD +0 -52
- /databricks/sdk/errors/{mapping.py → platform.py} +0 -0
- {databricks_sdk-0.18.0.dist-info → databricks_sdk-0.19.0.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.18.0.dist-info → databricks_sdk-0.19.0.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.18.0.dist-info → databricks_sdk-0.19.0.dist-info}/WHEEL +0 -0
- {databricks_sdk-0.18.0.dist-info → databricks_sdk-0.19.0.dist-info}/top_level.txt +0 -0
databricks/sdk/service/jobs.py
CHANGED
|
@@ -676,13 +676,22 @@ class DbtTask:
|
|
|
676
676
|
specified. If no warehouse_id is specified and this folder is unset, the root directory is used."""
|
|
677
677
|
|
|
678
678
|
project_directory: Optional[str] = None
|
|
679
|
-
"""
|
|
680
|
-
repository is used."""
|
|
679
|
+
"""Path to the project directory. Optional for Git sourced tasks, in which case if no value is
|
|
680
|
+
provided, the root of the Git repository is used."""
|
|
681
681
|
|
|
682
682
|
schema: Optional[str] = None
|
|
683
683
|
"""Optional schema to write to. This parameter is only used when a warehouse_id is also provided.
|
|
684
684
|
If not provided, the `default` schema is used."""
|
|
685
685
|
|
|
686
|
+
source: Optional[Source] = None
|
|
687
|
+
"""Optional location type of the project directory. When set to `WORKSPACE`, the project will be
|
|
688
|
+
retrieved from the local <Databricks> workspace. When set to `GIT`, the project will be
|
|
689
|
+
retrieved from a Git repository defined in `git_source`. If the value is empty, the task will
|
|
690
|
+
use `GIT` if `git_source` is defined and `WORKSPACE` otherwise.
|
|
691
|
+
|
|
692
|
+
* `WORKSPACE`: Project is located in <Databricks> workspace. * `GIT`: Project is located in
|
|
693
|
+
cloud Git provider."""
|
|
694
|
+
|
|
686
695
|
warehouse_id: Optional[str] = None
|
|
687
696
|
"""ID of the SQL warehouse to connect to. If provided, we automatically generate and provide the
|
|
688
697
|
profile and connection details to dbt. It can be overridden on a per-command basis by using the
|
|
@@ -696,6 +705,7 @@ class DbtTask:
|
|
|
696
705
|
if self.profiles_directory is not None: body['profiles_directory'] = self.profiles_directory
|
|
697
706
|
if self.project_directory is not None: body['project_directory'] = self.project_directory
|
|
698
707
|
if self.schema is not None: body['schema'] = self.schema
|
|
708
|
+
if self.source is not None: body['source'] = self.source.value
|
|
699
709
|
if self.warehouse_id is not None: body['warehouse_id'] = self.warehouse_id
|
|
700
710
|
return body
|
|
701
711
|
|
|
@@ -707,6 +717,7 @@ class DbtTask:
|
|
|
707
717
|
profiles_directory=d.get('profiles_directory', None),
|
|
708
718
|
project_directory=d.get('project_directory', None),
|
|
709
719
|
schema=d.get('schema', None),
|
|
720
|
+
source=_enum(d, 'source', Source),
|
|
710
721
|
warehouse_id=d.get('warehouse_id', None))
|
|
711
722
|
|
|
712
723
|
|
|
@@ -771,8 +782,8 @@ class FileArrivalTriggerConfiguration:
|
|
|
771
782
|
time the trigger fired. The minimum allowed value is 60 seconds"""
|
|
772
783
|
|
|
773
784
|
url: Optional[str] = None
|
|
774
|
-
"""
|
|
775
|
-
external location."""
|
|
785
|
+
"""The storage location to monitor for file arrivals. The value must point to the root or a subpath
|
|
786
|
+
of an external location URL or the root or subpath of a Unity Catalog volume."""
|
|
776
787
|
|
|
777
788
|
wait_after_last_change_seconds: Optional[int] = None
|
|
778
789
|
"""If set, the trigger starts a run only after no file activity has occurred for the specified
|
|
@@ -797,6 +808,117 @@ class FileArrivalTriggerConfiguration:
|
|
|
797
808
|
wait_after_last_change_seconds=d.get('wait_after_last_change_seconds', None))
|
|
798
809
|
|
|
799
810
|
|
|
811
|
+
@dataclass
|
|
812
|
+
class ForEachStats:
|
|
813
|
+
error_message_stats: Optional[ForEachTaskErrorMessageStats] = None
|
|
814
|
+
"""Sample of 3 most common error messages occurred during the iteration."""
|
|
815
|
+
|
|
816
|
+
task_run_stats: Optional[ForEachTaskTaskRunStats] = None
|
|
817
|
+
"""Describes stats of the iteration. Only latest retries are considered."""
|
|
818
|
+
|
|
819
|
+
def as_dict(self) -> dict:
|
|
820
|
+
"""Serializes the ForEachStats into a dictionary suitable for use as a JSON request body."""
|
|
821
|
+
body = {}
|
|
822
|
+
if self.error_message_stats: body['error_message_stats'] = self.error_message_stats.as_dict()
|
|
823
|
+
if self.task_run_stats: body['task_run_stats'] = self.task_run_stats.as_dict()
|
|
824
|
+
return body
|
|
825
|
+
|
|
826
|
+
@classmethod
|
|
827
|
+
def from_dict(cls, d: Dict[str, any]) -> ForEachStats:
|
|
828
|
+
"""Deserializes the ForEachStats from a dictionary."""
|
|
829
|
+
return cls(error_message_stats=_from_dict(d, 'error_message_stats', ForEachTaskErrorMessageStats),
|
|
830
|
+
task_run_stats=_from_dict(d, 'task_run_stats', ForEachTaskTaskRunStats))
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
@dataclass
|
|
834
|
+
class ForEachTask:
|
|
835
|
+
inputs: str
|
|
836
|
+
"""Array for task to iterate on. This can be a JSON string or a reference to an array parameter."""
|
|
837
|
+
|
|
838
|
+
task: Task
|
|
839
|
+
|
|
840
|
+
concurrency: Optional[int] = None
|
|
841
|
+
"""Controls the number of active iterations task runs. Default is 100 (maximal value)."""
|
|
842
|
+
|
|
843
|
+
def as_dict(self) -> dict:
|
|
844
|
+
"""Serializes the ForEachTask into a dictionary suitable for use as a JSON request body."""
|
|
845
|
+
body = {}
|
|
846
|
+
if self.concurrency is not None: body['concurrency'] = self.concurrency
|
|
847
|
+
if self.inputs is not None: body['inputs'] = self.inputs
|
|
848
|
+
if self.task: body['task'] = self.task.as_dict()
|
|
849
|
+
return body
|
|
850
|
+
|
|
851
|
+
@classmethod
|
|
852
|
+
def from_dict(cls, d: Dict[str, any]) -> ForEachTask:
|
|
853
|
+
"""Deserializes the ForEachTask from a dictionary."""
|
|
854
|
+
return cls(concurrency=d.get('concurrency', None),
|
|
855
|
+
inputs=d.get('inputs', None),
|
|
856
|
+
task=_from_dict(d, 'task', Task))
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
@dataclass
|
|
860
|
+
class ForEachTaskErrorMessageStats:
|
|
861
|
+
count: Optional[str] = None
|
|
862
|
+
"""Describes the count of such error message encountered during the iterations."""
|
|
863
|
+
|
|
864
|
+
error_message: Optional[str] = None
|
|
865
|
+
"""Describes the error message occured during the iterations."""
|
|
866
|
+
|
|
867
|
+
def as_dict(self) -> dict:
|
|
868
|
+
"""Serializes the ForEachTaskErrorMessageStats into a dictionary suitable for use as a JSON request body."""
|
|
869
|
+
body = {}
|
|
870
|
+
if self.count is not None: body['count'] = self.count
|
|
871
|
+
if self.error_message is not None: body['error_message'] = self.error_message
|
|
872
|
+
return body
|
|
873
|
+
|
|
874
|
+
@classmethod
|
|
875
|
+
def from_dict(cls, d: Dict[str, any]) -> ForEachTaskErrorMessageStats:
|
|
876
|
+
"""Deserializes the ForEachTaskErrorMessageStats from a dictionary."""
|
|
877
|
+
return cls(count=d.get('count', None), error_message=d.get('error_message', None))
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
@dataclass
|
|
881
|
+
class ForEachTaskTaskRunStats:
|
|
882
|
+
active_iterations: Optional[int] = None
|
|
883
|
+
"""Describes the iteration runs having an active lifecycle state or an active run sub state."""
|
|
884
|
+
|
|
885
|
+
completed_iterations: Optional[int] = None
|
|
886
|
+
"""Describes the number of failed and succeeded iteration runs."""
|
|
887
|
+
|
|
888
|
+
failed_iterations: Optional[int] = None
|
|
889
|
+
"""Describes the number of failed iteration runs."""
|
|
890
|
+
|
|
891
|
+
scheduled_iterations: Optional[int] = None
|
|
892
|
+
"""Describes the number of iteration runs that have been scheduled."""
|
|
893
|
+
|
|
894
|
+
succeeded_iterations: Optional[int] = None
|
|
895
|
+
"""Describes the number of succeeded iteration runs."""
|
|
896
|
+
|
|
897
|
+
total_iterations: Optional[int] = None
|
|
898
|
+
"""Describes the length of the list of items to iterate over."""
|
|
899
|
+
|
|
900
|
+
def as_dict(self) -> dict:
|
|
901
|
+
"""Serializes the ForEachTaskTaskRunStats into a dictionary suitable for use as a JSON request body."""
|
|
902
|
+
body = {}
|
|
903
|
+
if self.active_iterations is not None: body['active_iterations'] = self.active_iterations
|
|
904
|
+
if self.completed_iterations is not None: body['completed_iterations'] = self.completed_iterations
|
|
905
|
+
if self.failed_iterations is not None: body['failed_iterations'] = self.failed_iterations
|
|
906
|
+
if self.scheduled_iterations is not None: body['scheduled_iterations'] = self.scheduled_iterations
|
|
907
|
+
if self.succeeded_iterations is not None: body['succeeded_iterations'] = self.succeeded_iterations
|
|
908
|
+
if self.total_iterations is not None: body['total_iterations'] = self.total_iterations
|
|
909
|
+
return body
|
|
910
|
+
|
|
911
|
+
@classmethod
|
|
912
|
+
def from_dict(cls, d: Dict[str, any]) -> ForEachTaskTaskRunStats:
|
|
913
|
+
"""Deserializes the ForEachTaskTaskRunStats from a dictionary."""
|
|
914
|
+
return cls(active_iterations=d.get('active_iterations', None),
|
|
915
|
+
completed_iterations=d.get('completed_iterations', None),
|
|
916
|
+
failed_iterations=d.get('failed_iterations', None),
|
|
917
|
+
scheduled_iterations=d.get('scheduled_iterations', None),
|
|
918
|
+
succeeded_iterations=d.get('succeeded_iterations', None),
|
|
919
|
+
total_iterations=d.get('total_iterations', None))
|
|
920
|
+
|
|
921
|
+
|
|
800
922
|
class Format(Enum):
|
|
801
923
|
|
|
802
924
|
MULTI_TASK = 'MULTI_TASK'
|
|
@@ -2531,6 +2653,36 @@ class RunConditionTaskOp(Enum):
|
|
|
2531
2653
|
NOT_EQUAL = 'NOT_EQUAL'
|
|
2532
2654
|
|
|
2533
2655
|
|
|
2656
|
+
@dataclass
|
|
2657
|
+
class RunForEachTask:
|
|
2658
|
+
concurrency: Optional[int] = None
|
|
2659
|
+
"""Controls the number of active iterations task runs. Default is 100 (maximal value)."""
|
|
2660
|
+
|
|
2661
|
+
inputs: Optional[str] = None
|
|
2662
|
+
"""Array for task to iterate on. This can be a JSON string or a reference to an array parameter."""
|
|
2663
|
+
|
|
2664
|
+
stats: Optional[ForEachStats] = None
|
|
2665
|
+
|
|
2666
|
+
task: Optional[Task] = None
|
|
2667
|
+
|
|
2668
|
+
def as_dict(self) -> dict:
|
|
2669
|
+
"""Serializes the RunForEachTask into a dictionary suitable for use as a JSON request body."""
|
|
2670
|
+
body = {}
|
|
2671
|
+
if self.concurrency is not None: body['concurrency'] = self.concurrency
|
|
2672
|
+
if self.inputs is not None: body['inputs'] = self.inputs
|
|
2673
|
+
if self.stats: body['stats'] = self.stats.as_dict()
|
|
2674
|
+
if self.task: body['task'] = self.task.as_dict()
|
|
2675
|
+
return body
|
|
2676
|
+
|
|
2677
|
+
@classmethod
|
|
2678
|
+
def from_dict(cls, d: Dict[str, any]) -> RunForEachTask:
|
|
2679
|
+
"""Deserializes the RunForEachTask from a dictionary."""
|
|
2680
|
+
return cls(concurrency=d.get('concurrency', None),
|
|
2681
|
+
inputs=d.get('inputs', None),
|
|
2682
|
+
stats=_from_dict(d, 'stats', ForEachStats),
|
|
2683
|
+
task=_from_dict(d, 'task', Task))
|
|
2684
|
+
|
|
2685
|
+
|
|
2534
2686
|
class RunIf(Enum):
|
|
2535
2687
|
"""An optional value indicating the condition that determines whether the task should be run once
|
|
2536
2688
|
its dependencies have been completed. When omitted, defaults to `ALL_SUCCESS`.
|
|
@@ -3056,6 +3208,9 @@ class RunTask:
|
|
|
3056
3208
|
When running jobs on an existing cluster, you may need to manually restart the cluster if it
|
|
3057
3209
|
stops responding. We suggest running jobs on new clusters for greater reliability."""
|
|
3058
3210
|
|
|
3211
|
+
for_each_task: Optional[RunForEachTask] = None
|
|
3212
|
+
"""If for_each_task, indicates that this task must execute the nested task within it."""
|
|
3213
|
+
|
|
3059
3214
|
git_source: Optional[GitSource] = None
|
|
3060
3215
|
"""An optional specification for a remote Git repository containing the source code used by tasks.
|
|
3061
3216
|
Version-controlled source code is supported by notebook, dbt, Python script, and SQL File tasks.
|
|
@@ -3159,6 +3314,7 @@ class RunTask:
|
|
|
3159
3314
|
if self.end_time is not None: body['end_time'] = self.end_time
|
|
3160
3315
|
if self.execution_duration is not None: body['execution_duration'] = self.execution_duration
|
|
3161
3316
|
if self.existing_cluster_id is not None: body['existing_cluster_id'] = self.existing_cluster_id
|
|
3317
|
+
if self.for_each_task: body['for_each_task'] = self.for_each_task.as_dict()
|
|
3162
3318
|
if self.git_source: body['git_source'] = self.git_source.as_dict()
|
|
3163
3319
|
if self.libraries: body['libraries'] = [v.as_dict() for v in self.libraries]
|
|
3164
3320
|
if self.new_cluster: body['new_cluster'] = self.new_cluster.as_dict()
|
|
@@ -3193,6 +3349,7 @@ class RunTask:
|
|
|
3193
3349
|
end_time=d.get('end_time', None),
|
|
3194
3350
|
execution_duration=d.get('execution_duration', None),
|
|
3195
3351
|
existing_cluster_id=d.get('existing_cluster_id', None),
|
|
3352
|
+
for_each_task=_from_dict(d, 'for_each_task', RunForEachTask),
|
|
3196
3353
|
git_source=_from_dict(d, 'git_source', GitSource),
|
|
3197
3354
|
libraries=_repeated_dict(d, 'libraries', compute.Library),
|
|
3198
3355
|
new_cluster=_from_dict(d, 'new_cluster', compute.ClusterSpec),
|
|
@@ -3662,18 +3819,29 @@ class SqlTaskDashboard:
|
|
|
3662
3819
|
@dataclass
|
|
3663
3820
|
class SqlTaskFile:
|
|
3664
3821
|
path: str
|
|
3665
|
-
"""
|
|
3822
|
+
"""Path of the SQL file. Must be relative if the source is a remote Git repository and absolute for
|
|
3823
|
+
workspace paths."""
|
|
3824
|
+
|
|
3825
|
+
source: Optional[Source] = None
|
|
3826
|
+
"""Optional location type of the SQL file. When set to `WORKSPACE`, the SQL file will be retrieved
|
|
3827
|
+
from the local <Databricks> workspace. When set to `GIT`, the SQL file will be retrieved from a
|
|
3828
|
+
Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if
|
|
3829
|
+
`git_source` is defined and `WORKSPACE` otherwise.
|
|
3830
|
+
|
|
3831
|
+
* `WORKSPACE`: SQL file is located in <Databricks> workspace. * `GIT`: SQL file is located in
|
|
3832
|
+
cloud Git provider."""
|
|
3666
3833
|
|
|
3667
3834
|
def as_dict(self) -> dict:
|
|
3668
3835
|
"""Serializes the SqlTaskFile into a dictionary suitable for use as a JSON request body."""
|
|
3669
3836
|
body = {}
|
|
3670
3837
|
if self.path is not None: body['path'] = self.path
|
|
3838
|
+
if self.source is not None: body['source'] = self.source.value
|
|
3671
3839
|
return body
|
|
3672
3840
|
|
|
3673
3841
|
@classmethod
|
|
3674
3842
|
def from_dict(cls, d: Dict[str, any]) -> SqlTaskFile:
|
|
3675
3843
|
"""Deserializes the SqlTaskFile from a dictionary."""
|
|
3676
|
-
return cls(path=d.get('path', None))
|
|
3844
|
+
return cls(path=d.get('path', None), source=_enum(d, 'source', Source))
|
|
3677
3845
|
|
|
3678
3846
|
|
|
3679
3847
|
@dataclass
|
|
@@ -3847,6 +4015,10 @@ class SubmitTask:
|
|
|
3847
4015
|
to manually restart the cluster if it stops responding. We suggest running jobs on new clusters
|
|
3848
4016
|
for greater reliability."""
|
|
3849
4017
|
|
|
4018
|
+
for_each_task: Optional[ForEachTask] = None
|
|
4019
|
+
"""If for_each_task, indicates that this must execute the nested task within it for the inputs
|
|
4020
|
+
provided."""
|
|
4021
|
+
|
|
3850
4022
|
health: Optional[JobsHealthRules] = None
|
|
3851
4023
|
"""An optional set of health rules that can be defined for this job."""
|
|
3852
4024
|
|
|
@@ -3920,6 +4092,7 @@ class SubmitTask:
|
|
|
3920
4092
|
if self.depends_on: body['depends_on'] = [v.as_dict() for v in self.depends_on]
|
|
3921
4093
|
if self.email_notifications: body['email_notifications'] = self.email_notifications.as_dict()
|
|
3922
4094
|
if self.existing_cluster_id is not None: body['existing_cluster_id'] = self.existing_cluster_id
|
|
4095
|
+
if self.for_each_task: body['for_each_task'] = self.for_each_task.as_dict()
|
|
3923
4096
|
if self.health: body['health'] = self.health.as_dict()
|
|
3924
4097
|
if self.libraries: body['libraries'] = [v.as_dict() for v in self.libraries]
|
|
3925
4098
|
if self.new_cluster: body['new_cluster'] = self.new_cluster.as_dict()
|
|
@@ -3945,6 +4118,7 @@ class SubmitTask:
|
|
|
3945
4118
|
depends_on=_repeated_dict(d, 'depends_on', TaskDependency),
|
|
3946
4119
|
email_notifications=_from_dict(d, 'email_notifications', JobEmailNotifications),
|
|
3947
4120
|
existing_cluster_id=d.get('existing_cluster_id', None),
|
|
4121
|
+
for_each_task=_from_dict(d, 'for_each_task', ForEachTask),
|
|
3948
4122
|
health=_from_dict(d, 'health', JobsHealthRules),
|
|
3949
4123
|
libraries=_repeated_dict(d, 'libraries', compute.Library),
|
|
3950
4124
|
new_cluster=_from_dict(d, 'new_cluster', compute.ClusterSpec),
|
|
@@ -4002,6 +4176,10 @@ class Task:
|
|
|
4002
4176
|
to manually restart the cluster if it stops responding. We suggest running jobs on new clusters
|
|
4003
4177
|
for greater reliability."""
|
|
4004
4178
|
|
|
4179
|
+
for_each_task: Optional[ForEachTask] = None
|
|
4180
|
+
"""If for_each_task, indicates that this must execute the nested task within it for the inputs
|
|
4181
|
+
provided."""
|
|
4182
|
+
|
|
4005
4183
|
health: Optional[JobsHealthRules] = None
|
|
4006
4184
|
"""An optional set of health rules that can be defined for this job."""
|
|
4007
4185
|
|
|
@@ -4098,6 +4276,7 @@ class Task:
|
|
|
4098
4276
|
if self.description is not None: body['description'] = self.description
|
|
4099
4277
|
if self.email_notifications: body['email_notifications'] = self.email_notifications.as_dict()
|
|
4100
4278
|
if self.existing_cluster_id is not None: body['existing_cluster_id'] = self.existing_cluster_id
|
|
4279
|
+
if self.for_each_task: body['for_each_task'] = self.for_each_task.as_dict()
|
|
4101
4280
|
if self.health: body['health'] = self.health.as_dict()
|
|
4102
4281
|
if self.job_cluster_key is not None: body['job_cluster_key'] = self.job_cluster_key
|
|
4103
4282
|
if self.libraries: body['libraries'] = [v.as_dict() for v in self.libraries]
|
|
@@ -4131,6 +4310,7 @@ class Task:
|
|
|
4131
4310
|
description=d.get('description', None),
|
|
4132
4311
|
email_notifications=_from_dict(d, 'email_notifications', TaskEmailNotifications),
|
|
4133
4312
|
existing_cluster_id=d.get('existing_cluster_id', None),
|
|
4313
|
+
for_each_task=_from_dict(d, 'for_each_task', ForEachTask),
|
|
4134
4314
|
health=_from_dict(d, 'health', JobsHealthRules),
|
|
4135
4315
|
job_cluster_key=d.get('job_cluster_key', None),
|
|
4136
4316
|
libraries=_repeated_dict(d, 'libraries', compute.Library),
|
|
@@ -4945,10 +5125,9 @@ class JobsAPI:
|
|
|
4945
5125
|
|
|
4946
5126
|
while True:
|
|
4947
5127
|
json = self._api.do('GET', '/api/2.1/jobs/list', query=query, headers=headers)
|
|
4948
|
-
if 'jobs'
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
yield BaseJob.from_dict(v)
|
|
5128
|
+
if 'jobs' in json:
|
|
5129
|
+
for v in json['jobs']:
|
|
5130
|
+
yield BaseJob.from_dict(v)
|
|
4952
5131
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
4953
5132
|
return
|
|
4954
5133
|
query['page_token'] = json['next_page_token']
|
|
@@ -5017,10 +5196,9 @@ class JobsAPI:
|
|
|
5017
5196
|
|
|
5018
5197
|
while True:
|
|
5019
5198
|
json = self._api.do('GET', '/api/2.1/jobs/runs/list', query=query, headers=headers)
|
|
5020
|
-
if 'runs'
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
yield BaseRun.from_dict(v)
|
|
5199
|
+
if 'runs' in json:
|
|
5200
|
+
for v in json['runs']:
|
|
5201
|
+
yield BaseRun.from_dict(v)
|
|
5024
5202
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
5025
5203
|
return
|
|
5026
5204
|
query['page_token'] = json['next_page_token']
|
databricks/sdk/service/ml.py
CHANGED
|
@@ -3710,10 +3710,9 @@ class ExperimentsAPI:
|
|
|
3710
3710
|
|
|
3711
3711
|
while True:
|
|
3712
3712
|
json = self._api.do('GET', '/api/2.0/mlflow/metrics/get-history', query=query, headers=headers)
|
|
3713
|
-
if 'metrics'
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
yield Metric.from_dict(v)
|
|
3713
|
+
if 'metrics' in json:
|
|
3714
|
+
for v in json['metrics']:
|
|
3715
|
+
yield Metric.from_dict(v)
|
|
3717
3716
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
3718
3717
|
return
|
|
3719
3718
|
query['page_token'] = json['next_page_token']
|
|
@@ -3807,10 +3806,9 @@ class ExperimentsAPI:
|
|
|
3807
3806
|
|
|
3808
3807
|
while True:
|
|
3809
3808
|
json = self._api.do('GET', '/api/2.0/mlflow/artifacts/list', query=query, headers=headers)
|
|
3810
|
-
if 'files'
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
yield FileInfo.from_dict(v)
|
|
3809
|
+
if 'files' in json:
|
|
3810
|
+
for v in json['files']:
|
|
3811
|
+
yield FileInfo.from_dict(v)
|
|
3814
3812
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
3815
3813
|
return
|
|
3816
3814
|
query['page_token'] = json['next_page_token']
|
|
@@ -3844,10 +3842,9 @@ class ExperimentsAPI:
|
|
|
3844
3842
|
|
|
3845
3843
|
while True:
|
|
3846
3844
|
json = self._api.do('GET', '/api/2.0/mlflow/experiments/list', query=query, headers=headers)
|
|
3847
|
-
if 'experiments'
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
yield Experiment.from_dict(v)
|
|
3845
|
+
if 'experiments' in json:
|
|
3846
|
+
for v in json['experiments']:
|
|
3847
|
+
yield Experiment.from_dict(v)
|
|
3851
3848
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
3852
3849
|
return
|
|
3853
3850
|
query['page_token'] = json['next_page_token']
|
|
@@ -4125,10 +4122,9 @@ class ExperimentsAPI:
|
|
|
4125
4122
|
|
|
4126
4123
|
while True:
|
|
4127
4124
|
json = self._api.do('POST', '/api/2.0/mlflow/experiments/search', body=body, headers=headers)
|
|
4128
|
-
if 'experiments'
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
yield Experiment.from_dict(v)
|
|
4125
|
+
if 'experiments' in json:
|
|
4126
|
+
for v in json['experiments']:
|
|
4127
|
+
yield Experiment.from_dict(v)
|
|
4132
4128
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
4133
4129
|
return
|
|
4134
4130
|
body['page_token'] = json['next_page_token']
|
|
@@ -4186,10 +4182,9 @@ class ExperimentsAPI:
|
|
|
4186
4182
|
|
|
4187
4183
|
while True:
|
|
4188
4184
|
json = self._api.do('POST', '/api/2.0/mlflow/runs/search', body=body, headers=headers)
|
|
4189
|
-
if 'runs'
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
yield Run.from_dict(v)
|
|
4185
|
+
if 'runs' in json:
|
|
4186
|
+
for v in json['runs']:
|
|
4187
|
+
yield Run.from_dict(v)
|
|
4193
4188
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
4194
4189
|
return
|
|
4195
4190
|
body['page_token'] = json['next_page_token']
|
|
@@ -4903,10 +4898,9 @@ class ModelRegistryAPI:
|
|
|
4903
4898
|
|
|
4904
4899
|
while True:
|
|
4905
4900
|
json = self._api.do('GET', '/api/2.0/mlflow/registered-models/list', query=query, headers=headers)
|
|
4906
|
-
if 'registered_models'
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
yield Model.from_dict(v)
|
|
4901
|
+
if 'registered_models' in json:
|
|
4902
|
+
for v in json['registered_models']:
|
|
4903
|
+
yield Model.from_dict(v)
|
|
4910
4904
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
4911
4905
|
return
|
|
4912
4906
|
query['page_token'] = json['next_page_token']
|
|
@@ -4963,10 +4957,9 @@ class ModelRegistryAPI:
|
|
|
4963
4957
|
|
|
4964
4958
|
while True:
|
|
4965
4959
|
json = self._api.do('GET', '/api/2.0/mlflow/registry-webhooks/list', query=query, headers=headers)
|
|
4966
|
-
if 'webhooks'
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
yield RegistryWebhook.from_dict(v)
|
|
4960
|
+
if 'webhooks' in json:
|
|
4961
|
+
for v in json['webhooks']:
|
|
4962
|
+
yield RegistryWebhook.from_dict(v)
|
|
4970
4963
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
4971
4964
|
return
|
|
4972
4965
|
query['page_token'] = json['next_page_token']
|
|
@@ -5062,10 +5055,9 @@ class ModelRegistryAPI:
|
|
|
5062
5055
|
|
|
5063
5056
|
while True:
|
|
5064
5057
|
json = self._api.do('GET', '/api/2.0/mlflow/model-versions/search', query=query, headers=headers)
|
|
5065
|
-
if 'model_versions'
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
yield ModelVersion.from_dict(v)
|
|
5058
|
+
if 'model_versions' in json:
|
|
5059
|
+
for v in json['model_versions']:
|
|
5060
|
+
yield ModelVersion.from_dict(v)
|
|
5069
5061
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
5070
5062
|
return
|
|
5071
5063
|
query['page_token'] = json['next_page_token']
|
|
@@ -5108,10 +5100,9 @@ class ModelRegistryAPI:
|
|
|
5108
5100
|
'/api/2.0/mlflow/registered-models/search',
|
|
5109
5101
|
query=query,
|
|
5110
5102
|
headers=headers)
|
|
5111
|
-
if 'registered_models'
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
yield Model.from_dict(v)
|
|
5103
|
+
if 'registered_models' in json:
|
|
5104
|
+
for v in json['registered_models']:
|
|
5105
|
+
yield Model.from_dict(v)
|
|
5115
5106
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
5116
5107
|
return
|
|
5117
5108
|
query['page_token'] = json['next_page_token']
|
databricks/sdk/service/oauth2.py
CHANGED
|
@@ -629,10 +629,9 @@ class OAuthPublishedAppsAPI:
|
|
|
629
629
|
f'/api/2.0/accounts/{self._api.account_id}/oauth2/published-apps/',
|
|
630
630
|
query=query,
|
|
631
631
|
headers=headers)
|
|
632
|
-
if 'apps'
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
yield PublishedAppOutput.from_dict(v)
|
|
632
|
+
if 'apps' in json:
|
|
633
|
+
for v in json['apps']:
|
|
634
|
+
yield PublishedAppOutput.from_dict(v)
|
|
636
635
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
637
636
|
return
|
|
638
637
|
query['page_token'] = json['next_page_token']
|
|
@@ -791,7 +791,7 @@ class PipelineCluster:
|
|
|
791
791
|
apply_policy_default_values: Optional[bool] = None
|
|
792
792
|
"""Note: This field won't be persisted. Only API users will check this field."""
|
|
793
793
|
|
|
794
|
-
autoscale: Optional[
|
|
794
|
+
autoscale: Optional[PipelineClusterAutoscale] = None
|
|
795
795
|
"""Parameters needed in order to automatically scale clusters up and down based on load. Note:
|
|
796
796
|
autoscaling works best with DB runtime versions 3.0 or later."""
|
|
797
797
|
|
|
@@ -914,7 +914,7 @@ class PipelineCluster:
|
|
|
914
914
|
def from_dict(cls, d: Dict[str, any]) -> PipelineCluster:
|
|
915
915
|
"""Deserializes the PipelineCluster from a dictionary."""
|
|
916
916
|
return cls(apply_policy_default_values=d.get('apply_policy_default_values', None),
|
|
917
|
-
autoscale=_from_dict(d, 'autoscale',
|
|
917
|
+
autoscale=_from_dict(d, 'autoscale', PipelineClusterAutoscale),
|
|
918
918
|
aws_attributes=_from_dict(d, 'aws_attributes', compute.AwsAttributes),
|
|
919
919
|
azure_attributes=_from_dict(d, 'azure_attributes', compute.AzureAttributes),
|
|
920
920
|
cluster_log_conf=_from_dict(d, 'cluster_log_conf', compute.ClusterLogConf),
|
|
@@ -933,6 +933,48 @@ class PipelineCluster:
|
|
|
933
933
|
ssh_public_keys=d.get('ssh_public_keys', None))
|
|
934
934
|
|
|
935
935
|
|
|
936
|
+
@dataclass
|
|
937
|
+
class PipelineClusterAutoscale:
|
|
938
|
+
min_workers: int
|
|
939
|
+
"""The minimum number of workers the cluster can scale down to when underutilized. It is also the
|
|
940
|
+
initial number of workers the cluster will have after creation."""
|
|
941
|
+
|
|
942
|
+
max_workers: int
|
|
943
|
+
"""The maximum number of workers to which the cluster can scale up when overloaded. `max_workers`
|
|
944
|
+
must be strictly greater than `min_workers`."""
|
|
945
|
+
|
|
946
|
+
mode: Optional[PipelineClusterAutoscaleMode] = None
|
|
947
|
+
"""Databricks Enhanced Autoscaling optimizes cluster utilization by automatically allocating
|
|
948
|
+
cluster resources based on workload volume, with minimal impact to the data processing latency
|
|
949
|
+
of your pipelines. Enhanced Autoscaling is available for `updates` clusters only. The legacy
|
|
950
|
+
autoscaling feature is used for `maintenance` clusters."""
|
|
951
|
+
|
|
952
|
+
def as_dict(self) -> dict:
|
|
953
|
+
"""Serializes the PipelineClusterAutoscale into a dictionary suitable for use as a JSON request body."""
|
|
954
|
+
body = {}
|
|
955
|
+
if self.max_workers is not None: body['max_workers'] = self.max_workers
|
|
956
|
+
if self.min_workers is not None: body['min_workers'] = self.min_workers
|
|
957
|
+
if self.mode is not None: body['mode'] = self.mode.value
|
|
958
|
+
return body
|
|
959
|
+
|
|
960
|
+
@classmethod
|
|
961
|
+
def from_dict(cls, d: Dict[str, any]) -> PipelineClusterAutoscale:
|
|
962
|
+
"""Deserializes the PipelineClusterAutoscale from a dictionary."""
|
|
963
|
+
return cls(max_workers=d.get('max_workers', None),
|
|
964
|
+
min_workers=d.get('min_workers', None),
|
|
965
|
+
mode=_enum(d, 'mode', PipelineClusterAutoscaleMode))
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
class PipelineClusterAutoscaleMode(Enum):
|
|
969
|
+
"""Databricks Enhanced Autoscaling optimizes cluster utilization by automatically allocating
|
|
970
|
+
cluster resources based on workload volume, with minimal impact to the data processing latency
|
|
971
|
+
of your pipelines. Enhanced Autoscaling is available for `updates` clusters only. The legacy
|
|
972
|
+
autoscaling feature is used for `maintenance` clusters."""
|
|
973
|
+
|
|
974
|
+
ENHANCED = 'ENHANCED'
|
|
975
|
+
LEGACY = 'LEGACY'
|
|
976
|
+
|
|
977
|
+
|
|
936
978
|
@dataclass
|
|
937
979
|
class PipelineEvent:
|
|
938
980
|
error: Optional[ErrorDetail] = None
|
|
@@ -1891,10 +1933,9 @@ class PipelinesAPI:
|
|
|
1891
1933
|
f'/api/2.0/pipelines/{pipeline_id}/events',
|
|
1892
1934
|
query=query,
|
|
1893
1935
|
headers=headers)
|
|
1894
|
-
if 'events'
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
yield PipelineEvent.from_dict(v)
|
|
1936
|
+
if 'events' in json:
|
|
1937
|
+
for v in json['events']:
|
|
1938
|
+
yield PipelineEvent.from_dict(v)
|
|
1898
1939
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
1899
1940
|
return
|
|
1900
1941
|
query['page_token'] = json['next_page_token']
|
|
@@ -1940,10 +1981,9 @@ class PipelinesAPI:
|
|
|
1940
1981
|
|
|
1941
1982
|
while True:
|
|
1942
1983
|
json = self._api.do('GET', '/api/2.0/pipelines', query=query, headers=headers)
|
|
1943
|
-
if 'statuses'
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
yield PipelineStateInfo.from_dict(v)
|
|
1984
|
+
if 'statuses' in json:
|
|
1985
|
+
for v in json['statuses']:
|
|
1986
|
+
yield PipelineStateInfo.from_dict(v)
|
|
1947
1987
|
if 'next_page_token' not in json or not json['next_page_token']:
|
|
1948
1988
|
return
|
|
1949
1989
|
query['page_token'] = json['next_page_token']
|
|
@@ -1978,25 +2018,6 @@ class PipelinesAPI:
|
|
|
1978
2018
|
res = self._api.do('GET', f'/api/2.0/pipelines/{pipeline_id}/updates', query=query, headers=headers)
|
|
1979
2019
|
return ListUpdatesResponse.from_dict(res)
|
|
1980
2020
|
|
|
1981
|
-
def reset(self, pipeline_id: str) -> Wait[GetPipelineResponse]:
|
|
1982
|
-
"""Reset a pipeline.
|
|
1983
|
-
|
|
1984
|
-
Resets a pipeline.
|
|
1985
|
-
|
|
1986
|
-
:param pipeline_id: str
|
|
1987
|
-
|
|
1988
|
-
:returns:
|
|
1989
|
-
Long-running operation waiter for :class:`GetPipelineResponse`.
|
|
1990
|
-
See :method:wait_get_pipeline_running for more details.
|
|
1991
|
-
"""
|
|
1992
|
-
|
|
1993
|
-
headers = {'Accept': 'application/json', }
|
|
1994
|
-
self._api.do('POST', f'/api/2.0/pipelines/{pipeline_id}/reset', headers=headers)
|
|
1995
|
-
return Wait(self.wait_get_pipeline_running, pipeline_id=pipeline_id)
|
|
1996
|
-
|
|
1997
|
-
def reset_and_wait(self, pipeline_id: str, timeout=timedelta(minutes=20)) -> GetPipelineResponse:
|
|
1998
|
-
return self.reset(pipeline_id=pipeline_id).result(timeout=timeout)
|
|
1999
|
-
|
|
2000
2021
|
def set_permissions(
|
|
2001
2022
|
self,
|
|
2002
2023
|
pipeline_id: str,
|