dtlpy 1.115.44__py3-none-any.whl → 1.117.6__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.
- dtlpy/__init__.py +491 -491
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__init__.py +26 -26
- dtlpy/assets/code_server/config.yaml +2 -2
- dtlpy/assets/code_server/installation.sh +24 -24
- dtlpy/assets/code_server/launch.json +13 -13
- dtlpy/assets/code_server/settings.json +2 -2
- dtlpy/assets/main.py +53 -53
- dtlpy/assets/main_partial.py +18 -18
- dtlpy/assets/mock.json +11 -11
- dtlpy/assets/model_adapter.py +83 -83
- dtlpy/assets/package.json +61 -61
- dtlpy/assets/package_catalog.json +29 -29
- dtlpy/assets/package_gitignore +307 -307
- dtlpy/assets/service_runners/__init__.py +33 -33
- dtlpy/assets/service_runners/converter.py +96 -96
- dtlpy/assets/service_runners/multi_method.py +49 -49
- dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
- dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
- dtlpy/assets/service_runners/multi_method_item.py +52 -52
- dtlpy/assets/service_runners/multi_method_json.py +52 -52
- dtlpy/assets/service_runners/single_method.py +37 -37
- dtlpy/assets/service_runners/single_method_annotation.py +43 -43
- dtlpy/assets/service_runners/single_method_dataset.py +43 -43
- dtlpy/assets/service_runners/single_method_item.py +41 -41
- dtlpy/assets/service_runners/single_method_json.py +42 -42
- dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
- dtlpy/assets/voc_annotation_template.xml +23 -23
- dtlpy/caches/base_cache.py +32 -32
- dtlpy/caches/cache.py +473 -473
- dtlpy/caches/dl_cache.py +201 -201
- dtlpy/caches/filesystem_cache.py +89 -89
- dtlpy/caches/redis_cache.py +84 -84
- dtlpy/dlp/__init__.py +20 -20
- dtlpy/dlp/cli_utilities.py +367 -367
- dtlpy/dlp/command_executor.py +764 -764
- dtlpy/dlp/dlp +1 -1
- dtlpy/dlp/dlp.bat +1 -1
- dtlpy/dlp/dlp.py +128 -128
- dtlpy/dlp/parser.py +651 -651
- dtlpy/entities/__init__.py +83 -83
- dtlpy/entities/analytic.py +347 -347
- dtlpy/entities/annotation.py +1879 -1879
- dtlpy/entities/annotation_collection.py +699 -699
- dtlpy/entities/annotation_definitions/__init__.py +20 -20
- dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
- dtlpy/entities/annotation_definitions/box.py +195 -195
- dtlpy/entities/annotation_definitions/classification.py +67 -67
- dtlpy/entities/annotation_definitions/comparison.py +72 -72
- dtlpy/entities/annotation_definitions/cube.py +204 -204
- dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
- dtlpy/entities/annotation_definitions/description.py +32 -32
- dtlpy/entities/annotation_definitions/ellipse.py +124 -124
- dtlpy/entities/annotation_definitions/free_text.py +62 -62
- dtlpy/entities/annotation_definitions/gis.py +69 -69
- dtlpy/entities/annotation_definitions/note.py +139 -139
- dtlpy/entities/annotation_definitions/point.py +117 -117
- dtlpy/entities/annotation_definitions/polygon.py +182 -182
- dtlpy/entities/annotation_definitions/polyline.py +111 -111
- dtlpy/entities/annotation_definitions/pose.py +92 -92
- dtlpy/entities/annotation_definitions/ref_image.py +86 -86
- dtlpy/entities/annotation_definitions/segmentation.py +240 -240
- dtlpy/entities/annotation_definitions/subtitle.py +34 -34
- dtlpy/entities/annotation_definitions/text.py +85 -85
- dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
- dtlpy/entities/app.py +220 -220
- dtlpy/entities/app_module.py +107 -107
- dtlpy/entities/artifact.py +174 -174
- dtlpy/entities/assignment.py +399 -399
- dtlpy/entities/base_entity.py +214 -214
- dtlpy/entities/bot.py +113 -113
- dtlpy/entities/codebase.py +292 -292
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +449 -449
- dtlpy/entities/dataset.py +1299 -1299
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +235 -235
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +152 -145
- dtlpy/entities/filters.py +798 -798
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +975 -959
- dtlpy/entities/label.py +123 -123
- dtlpy/entities/links.py +85 -85
- dtlpy/entities/message.py +175 -175
- dtlpy/entities/model.py +684 -684
- dtlpy/entities/node.py +1005 -1005
- dtlpy/entities/ontology.py +810 -803
- dtlpy/entities/organization.py +287 -287
- dtlpy/entities/package.py +657 -657
- dtlpy/entities/package_defaults.py +5 -5
- dtlpy/entities/package_function.py +185 -185
- dtlpy/entities/package_module.py +113 -113
- dtlpy/entities/package_slot.py +118 -118
- dtlpy/entities/paged_entities.py +299 -299
- dtlpy/entities/pipeline.py +624 -624
- dtlpy/entities/pipeline_execution.py +279 -279
- dtlpy/entities/project.py +394 -394
- dtlpy/entities/prompt_item.py +505 -505
- dtlpy/entities/recipe.py +301 -301
- dtlpy/entities/reflect_dict.py +102 -102
- dtlpy/entities/resource_execution.py +138 -138
- dtlpy/entities/service.py +974 -963
- dtlpy/entities/service_driver.py +117 -117
- dtlpy/entities/setting.py +294 -294
- dtlpy/entities/task.py +495 -495
- dtlpy/entities/time_series.py +143 -143
- dtlpy/entities/trigger.py +426 -426
- dtlpy/entities/user.py +118 -118
- dtlpy/entities/webhook.py +124 -124
- dtlpy/examples/__init__.py +19 -19
- dtlpy/examples/add_labels.py +135 -135
- dtlpy/examples/add_metadata_to_item.py +21 -21
- dtlpy/examples/annotate_items_using_model.py +65 -65
- dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
- dtlpy/examples/annotations_convert_to_voc.py +9 -9
- dtlpy/examples/annotations_convert_to_yolo.py +9 -9
- dtlpy/examples/convert_annotation_types.py +51 -51
- dtlpy/examples/converter.py +143 -143
- dtlpy/examples/copy_annotations.py +22 -22
- dtlpy/examples/copy_folder.py +31 -31
- dtlpy/examples/create_annotations.py +51 -51
- dtlpy/examples/create_video_annotations.py +83 -83
- dtlpy/examples/delete_annotations.py +26 -26
- dtlpy/examples/filters.py +113 -113
- dtlpy/examples/move_item.py +23 -23
- dtlpy/examples/play_video_annotation.py +13 -13
- dtlpy/examples/show_item_and_mask.py +53 -53
- dtlpy/examples/triggers.py +49 -49
- dtlpy/examples/upload_batch_of_items.py +20 -20
- dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
- dtlpy/examples/upload_items_with_modalities.py +43 -43
- dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
- dtlpy/examples/upload_yolo_format_annotations.py +70 -70
- dtlpy/exceptions.py +125 -125
- dtlpy/miscellaneous/__init__.py +20 -20
- dtlpy/miscellaneous/dict_differ.py +95 -95
- dtlpy/miscellaneous/git_utils.py +217 -217
- dtlpy/miscellaneous/json_utils.py +14 -14
- dtlpy/miscellaneous/list_print.py +105 -105
- dtlpy/miscellaneous/zipping.py +130 -130
- dtlpy/ml/__init__.py +20 -20
- dtlpy/ml/base_feature_extractor_adapter.py +27 -27
- dtlpy/ml/base_model_adapter.py +1287 -1230
- dtlpy/ml/metrics.py +461 -461
- dtlpy/ml/predictions_utils.py +274 -274
- dtlpy/ml/summary_writer.py +57 -57
- dtlpy/ml/train_utils.py +60 -60
- dtlpy/new_instance.py +252 -252
- dtlpy/repositories/__init__.py +56 -56
- dtlpy/repositories/analytics.py +85 -85
- dtlpy/repositories/annotations.py +916 -916
- dtlpy/repositories/apps.py +383 -383
- dtlpy/repositories/artifacts.py +452 -452
- dtlpy/repositories/assignments.py +599 -599
- dtlpy/repositories/bots.py +213 -213
- dtlpy/repositories/codebases.py +559 -559
- dtlpy/repositories/collections.py +332 -332
- dtlpy/repositories/commands.py +152 -152
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +439 -439
- dtlpy/repositories/datasets.py +1585 -1504
- dtlpy/repositories/downloader.py +1157 -923
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -482
- dtlpy/repositories/executions.py +815 -815
- dtlpy/repositories/feature_sets.py +256 -226
- dtlpy/repositories/features.py +255 -255
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +912 -912
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +1000 -1000
- dtlpy/repositories/nodes.py +80 -80
- dtlpy/repositories/ontologies.py +511 -511
- dtlpy/repositories/organizations.py +525 -525
- dtlpy/repositories/packages.py +1941 -1941
- dtlpy/repositories/pipeline_executions.py +451 -451
- dtlpy/repositories/pipelines.py +640 -640
- dtlpy/repositories/projects.py +539 -539
- dtlpy/repositories/recipes.py +429 -399
- dtlpy/repositories/resource_executions.py +137 -137
- dtlpy/repositories/schema.py +120 -120
- dtlpy/repositories/service_drivers.py +213 -213
- dtlpy/repositories/services.py +1704 -1704
- dtlpy/repositories/settings.py +339 -339
- dtlpy/repositories/tasks.py +1477 -1477
- dtlpy/repositories/times_series.py +278 -278
- dtlpy/repositories/triggers.py +536 -536
- dtlpy/repositories/upload_element.py +257 -257
- dtlpy/repositories/uploader.py +661 -661
- dtlpy/repositories/webhooks.py +249 -249
- dtlpy/services/__init__.py +22 -22
- dtlpy/services/aihttp_retry.py +131 -131
- dtlpy/services/api_client.py +1786 -1785
- dtlpy/services/api_reference.py +40 -40
- dtlpy/services/async_utils.py +133 -133
- dtlpy/services/calls_counter.py +44 -44
- dtlpy/services/check_sdk.py +68 -68
- dtlpy/services/cookie.py +115 -115
- dtlpy/services/create_logger.py +156 -156
- dtlpy/services/events.py +84 -84
- dtlpy/services/logins.py +235 -235
- dtlpy/services/reporter.py +256 -256
- dtlpy/services/service_defaults.py +91 -91
- dtlpy/utilities/__init__.py +20 -20
- dtlpy/utilities/annotations/__init__.py +16 -16
- dtlpy/utilities/annotations/annotation_converters.py +269 -269
- dtlpy/utilities/base_package_runner.py +285 -264
- dtlpy/utilities/converter.py +1650 -1650
- dtlpy/utilities/dataset_generators/__init__.py +1 -1
- dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
- dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
- dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
- dtlpy/utilities/local_development/__init__.py +1 -1
- dtlpy/utilities/local_development/local_session.py +179 -179
- dtlpy/utilities/reports/__init__.py +2 -2
- dtlpy/utilities/reports/figures.py +343 -343
- dtlpy/utilities/reports/report.py +71 -71
- dtlpy/utilities/videos/__init__.py +17 -17
- dtlpy/utilities/videos/video_player.py +598 -598
- dtlpy/utilities/videos/videos.py +470 -470
- {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp +1 -1
- dtlpy-1.117.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/METADATA +186 -186
- dtlpy-1.117.6.dist-info/RECORD +239 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/licenses/LICENSE +200 -200
- tests/features/environment.py +551 -551
- dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
- dtlpy-1.115.44.data/scripts/dlp.bat +0 -2
- dtlpy-1.115.44.dist-info/RECORD +0 -240
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/top_level.txt +0 -0
|
@@ -1,451 +1,451 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import time
|
|
3
|
-
import numpy as np
|
|
4
|
-
|
|
5
|
-
from .. import entities, repositories, exceptions, miscellaneous, services, _api_reference
|
|
6
|
-
from ..services.api_client import ApiClient
|
|
7
|
-
|
|
8
|
-
logger = logging.getLogger(name='dtlpy')
|
|
9
|
-
MAX_SLEEP_TIME = 30
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class PipelineExecutions:
|
|
13
|
-
"""
|
|
14
|
-
PipelineExecutions Repository
|
|
15
|
-
|
|
16
|
-
The PipelineExecutions class allows users to manage pipeline executions. See our documentation for more information on `pipelines <https://dataloop.ai/docs/pipelines-overview>`_.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
def __init__(
|
|
20
|
-
self,
|
|
21
|
-
client_api: ApiClient,
|
|
22
|
-
project: entities.Project = None,
|
|
23
|
-
pipeline: entities.Pipeline = None
|
|
24
|
-
):
|
|
25
|
-
self._client_api = client_api
|
|
26
|
-
self._project = project
|
|
27
|
-
self._pipeline = pipeline
|
|
28
|
-
|
|
29
|
-
############
|
|
30
|
-
# entities #
|
|
31
|
-
############
|
|
32
|
-
@property
|
|
33
|
-
def project(self) -> entities.Project:
|
|
34
|
-
if self._project is None:
|
|
35
|
-
try:
|
|
36
|
-
self._project = repositories.Projects(client_api=self._client_api).get()
|
|
37
|
-
except exceptions.NotFound:
|
|
38
|
-
raise exceptions.PlatformException(
|
|
39
|
-
error='2001',
|
|
40
|
-
message='Missing "project". need to set a Project entity or use project.pipelines repository')
|
|
41
|
-
return self._project
|
|
42
|
-
|
|
43
|
-
@project.setter
|
|
44
|
-
def project(self, project: entities.Project):
|
|
45
|
-
if not isinstance(project, entities.Project):
|
|
46
|
-
raise ValueError('Must input a valid Project entity')
|
|
47
|
-
self._project = project
|
|
48
|
-
|
|
49
|
-
@property
|
|
50
|
-
def pipeline(self) -> entities.Pipeline:
|
|
51
|
-
assert isinstance(self._pipeline, entities.Pipeline)
|
|
52
|
-
return self._pipeline
|
|
53
|
-
|
|
54
|
-
@pipeline.setter
|
|
55
|
-
def pipeline(self, pipeline: entities.Pipeline):
|
|
56
|
-
if not isinstance(pipeline, entities.Pipeline):
|
|
57
|
-
raise ValueError('Must input a valid pipeline entity')
|
|
58
|
-
self._pipeline = pipeline
|
|
59
|
-
|
|
60
|
-
###########
|
|
61
|
-
# methods #
|
|
62
|
-
###########
|
|
63
|
-
# @_api_reference.add(path='/pipelines/{pipelineId}/executions/{executionId}', method='get')
|
|
64
|
-
def get(self,
|
|
65
|
-
pipeline_execution_id: str,
|
|
66
|
-
pipeline_id: str = None
|
|
67
|
-
) -> entities.PipelineExecution:
|
|
68
|
-
"""
|
|
69
|
-
Get Pipeline Execution object
|
|
70
|
-
|
|
71
|
-
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
72
|
-
|
|
73
|
-
:param str pipeline_execution_id: pipeline execution id
|
|
74
|
-
:param str pipeline_id: pipeline id
|
|
75
|
-
:return: PipelineExecution object
|
|
76
|
-
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
77
|
-
|
|
78
|
-
**Example**:
|
|
79
|
-
|
|
80
|
-
.. code-block:: python
|
|
81
|
-
|
|
82
|
-
pipeline_executions = pipeline.pipeline_executions.get(pipeline_id='pipeline_id')
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
if pipeline_id is None and self._pipeline is None:
|
|
86
|
-
raise exceptions.PlatformException('400', 'Must provide param pipeline_id')
|
|
87
|
-
elif pipeline_id is None:
|
|
88
|
-
pipeline_id = self._pipeline.id
|
|
89
|
-
|
|
90
|
-
success, response = self._client_api.gen_request(
|
|
91
|
-
req_type="get",
|
|
92
|
-
path="/pipelines/{pipeline_id}/executions/{pipeline_execution_id}".format(
|
|
93
|
-
pipeline_id=pipeline_id,
|
|
94
|
-
pipeline_execution_id=pipeline_execution_id
|
|
95
|
-
)
|
|
96
|
-
)
|
|
97
|
-
if not success:
|
|
98
|
-
raise exceptions.PlatformException(response)
|
|
99
|
-
|
|
100
|
-
pipeline_execution = entities.PipelineExecution.from_json(
|
|
101
|
-
client_api=self._client_api,
|
|
102
|
-
_json=response.json(),
|
|
103
|
-
pipeline=self._pipeline
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
return pipeline_execution
|
|
107
|
-
|
|
108
|
-
def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.PipelineExecution]:
|
|
109
|
-
pool = self._client_api.thread_pools(pool_name='entity.create')
|
|
110
|
-
jobs = [None for _ in range(len(response_items))]
|
|
111
|
-
|
|
112
|
-
for i_pipeline_execution, pipeline_execution in enumerate(response_items):
|
|
113
|
-
jobs[i_pipeline_execution] = pool.submit(
|
|
114
|
-
entities.PipelineExecution._protected_from_json,
|
|
115
|
-
**{
|
|
116
|
-
'client_api': self._client_api,
|
|
117
|
-
'_json': pipeline_execution,
|
|
118
|
-
'pipeline': self._pipeline
|
|
119
|
-
}
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
# get all results
|
|
123
|
-
# noinspection PyUnresolvedReferences
|
|
124
|
-
results = [j.result() for j in jobs]
|
|
125
|
-
# log errors
|
|
126
|
-
_ = [logger.warning(r[1]) for r in results if r[0] is False]
|
|
127
|
-
# return good jobs
|
|
128
|
-
pipeline_executions = miscellaneous.List([r[1] for r in results if r[0] is True])
|
|
129
|
-
return pipeline_executions
|
|
130
|
-
|
|
131
|
-
def _list(self, filters: entities.Filters):
|
|
132
|
-
url = '/pipelines/query'
|
|
133
|
-
|
|
134
|
-
# request
|
|
135
|
-
success, response = self._client_api.gen_request(
|
|
136
|
-
req_type='post',
|
|
137
|
-
path=url,
|
|
138
|
-
json_req=filters.prepare()
|
|
139
|
-
)
|
|
140
|
-
if not success:
|
|
141
|
-
raise exceptions.PlatformException(response)
|
|
142
|
-
return response.json()
|
|
143
|
-
|
|
144
|
-
@_api_reference.add(path='/pipelines/query', method='post')
|
|
145
|
-
def list(self, filters: entities.Filters = None) -> entities.PagedEntities:
|
|
146
|
-
"""
|
|
147
|
-
List project pipeline executions.
|
|
148
|
-
|
|
149
|
-
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
150
|
-
|
|
151
|
-
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
152
|
-
:return: Paged entity
|
|
153
|
-
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
154
|
-
|
|
155
|
-
**Example**:
|
|
156
|
-
|
|
157
|
-
.. code-block:: python
|
|
158
|
-
|
|
159
|
-
pipeline_executions = pipeline.pipeline_executions.list()
|
|
160
|
-
"""
|
|
161
|
-
if filters is None:
|
|
162
|
-
filters = entities.Filters(resource=entities.FiltersResource.PIPELINE_EXECUTION)
|
|
163
|
-
# assert type filters
|
|
164
|
-
elif not isinstance(filters, entities.Filters):
|
|
165
|
-
raise exceptions.PlatformException(error='400',
|
|
166
|
-
message='Unknown filters type: {!r}'.format(type(filters)))
|
|
167
|
-
if filters.resource != entities.FiltersResource.PIPELINE_EXECUTION:
|
|
168
|
-
raise exceptions.PlatformException(
|
|
169
|
-
error='400',
|
|
170
|
-
message='Filters resource must to be FiltersResource.PIPELINE_EXECUTION. Got: {!r}'.format(
|
|
171
|
-
filters.resource))
|
|
172
|
-
|
|
173
|
-
project_id = None
|
|
174
|
-
if self._project is not None:
|
|
175
|
-
project_id = self._project.id
|
|
176
|
-
|
|
177
|
-
# TODO - uncomment this after DAT-24496 is done and cycles have projectId
|
|
178
|
-
# if self._project is not None:
|
|
179
|
-
# filters.add(field='projectId', values=self.project.id)
|
|
180
|
-
|
|
181
|
-
if self._pipeline is not None:
|
|
182
|
-
filters.add(field='pipelineId', values=self._pipeline.id)
|
|
183
|
-
|
|
184
|
-
paged = entities.PagedEntities(
|
|
185
|
-
items_repository=self,
|
|
186
|
-
filters=filters,
|
|
187
|
-
page_offset=filters.page,
|
|
188
|
-
page_size=filters.page_size,
|
|
189
|
-
project_id=project_id,
|
|
190
|
-
client_api=self._client_api
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
paged.get_page()
|
|
194
|
-
return paged
|
|
195
|
-
|
|
196
|
-
@_api_reference.add(path="/pipelines/{pipelineId}/execute", method="post")
|
|
197
|
-
def create(
|
|
198
|
-
self,
|
|
199
|
-
pipeline_id: str = None,
|
|
200
|
-
execution_input=None,
|
|
201
|
-
node_id: str = None,
|
|
202
|
-
test_mode: bool = None
|
|
203
|
-
):
|
|
204
|
-
"""
|
|
205
|
-
Execute a pipeline.
|
|
206
|
-
|
|
207
|
-
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
208
|
-
|
|
209
|
-
:param pipeline_id: pipeline id
|
|
210
|
-
:param execution_input: list of the dl.FunctionIO or dict of pipeline input - example {'item': 'item_id'}
|
|
211
|
-
:param node_id: node id to start from
|
|
212
|
-
:param bool test_mode: if True, the pipeline will be executed in test mode
|
|
213
|
-
:return: entities.PipelineExecution object
|
|
214
|
-
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
215
|
-
|
|
216
|
-
**Example**:
|
|
217
|
-
|
|
218
|
-
.. code-block:: python
|
|
219
|
-
|
|
220
|
-
pipeline_execution = pipeline.pipeline_executions.create(pipeline_id='pipeline_id', execution_input={'item': 'item_id'})
|
|
221
|
-
"""
|
|
222
|
-
if pipeline_id is None:
|
|
223
|
-
if self._pipeline is None:
|
|
224
|
-
raise exceptions.PlatformException('400', 'Please provide pipeline id')
|
|
225
|
-
pipeline_id = self._pipeline.id
|
|
226
|
-
|
|
227
|
-
pipeline_options = dict()
|
|
228
|
-
if test_mode is not None:
|
|
229
|
-
pipeline_options["testMode"] = test_mode
|
|
230
|
-
if execution_input is None:
|
|
231
|
-
# support pipeline executions without any input
|
|
232
|
-
pass
|
|
233
|
-
elif isinstance(execution_input, dict):
|
|
234
|
-
pipeline_options["input"] = execution_input
|
|
235
|
-
else:
|
|
236
|
-
if not isinstance(execution_input, list):
|
|
237
|
-
execution_input = [execution_input]
|
|
238
|
-
if len(execution_input) > 0 and isinstance(execution_input[0], entities.FunctionIO):
|
|
239
|
-
pipeline_options["input"] = dict()
|
|
240
|
-
for single_input in execution_input:
|
|
241
|
-
pipeline_options["input"].update(single_input.to_json(resource="execution"))
|
|
242
|
-
else:
|
|
243
|
-
raise exceptions.PlatformException('400', 'Unknown input type')
|
|
244
|
-
|
|
245
|
-
if node_id is not None:
|
|
246
|
-
pipeline_options["nodeId"] = node_id
|
|
247
|
-
|
|
248
|
-
success, response = self._client_api.gen_request(
|
|
249
|
-
path="/pipelines/{}/execute".format(pipeline_id),
|
|
250
|
-
req_type="POST",
|
|
251
|
-
json_req={"pipeline": pipeline_options},
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
if not success:
|
|
255
|
-
raise exceptions.PlatformException(response)
|
|
256
|
-
|
|
257
|
-
execution = entities.PipelineExecution.from_json(_json=response.json(),
|
|
258
|
-
client_api=self._client_api,
|
|
259
|
-
pipeline=self._pipeline)
|
|
260
|
-
return execution
|
|
261
|
-
|
|
262
|
-
@_api_reference.add(path='/pipelines/{pipelineId}/execute', method='post')
|
|
263
|
-
def create_batch(
|
|
264
|
-
self,
|
|
265
|
-
pipeline_id: str,
|
|
266
|
-
filters,
|
|
267
|
-
execution_inputs=None,
|
|
268
|
-
wait=True,
|
|
269
|
-
node_id: str = None
|
|
270
|
-
):
|
|
271
|
-
"""
|
|
272
|
-
Create batch executions of a pipeline.
|
|
273
|
-
|
|
274
|
-
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
275
|
-
|
|
276
|
-
:param pipeline_id: pipeline id
|
|
277
|
-
:param filters: Filters entity for a filtering before execute
|
|
278
|
-
:param execution_inputs: list of the dl.FunctionIO or dict of pipeline input - example {'item': 'item_id'}, that represent the extra inputs of the function
|
|
279
|
-
:param bool wait: wait until create task finish
|
|
280
|
-
:return: entities.PipelineExecution object
|
|
281
|
-
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
282
|
-
|
|
283
|
-
**Example**:
|
|
284
|
-
|
|
285
|
-
.. code-block:: python
|
|
286
|
-
|
|
287
|
-
command = pipeline.pipeline_executions.create_batch(
|
|
288
|
-
execution_inputs=dl.FunctionIO(type=dl.PackageInputType.STRING, value='test', name='string'),
|
|
289
|
-
filters=dl.Filters(field='dir', values='/test'))
|
|
290
|
-
"""
|
|
291
|
-
if pipeline_id is None:
|
|
292
|
-
if self._pipeline is None:
|
|
293
|
-
raise exceptions.PlatformException('400', 'Please provide pipeline id')
|
|
294
|
-
pipeline_id = self._pipeline.id
|
|
295
|
-
|
|
296
|
-
if filters is None:
|
|
297
|
-
raise exceptions.PlatformException('400', 'Please provide filter')
|
|
298
|
-
extra_input = dict()
|
|
299
|
-
|
|
300
|
-
if execution_inputs is None:
|
|
301
|
-
execution_inputs = {}
|
|
302
|
-
|
|
303
|
-
if isinstance(execution_inputs, dict):
|
|
304
|
-
extra_input = execution_inputs
|
|
305
|
-
else:
|
|
306
|
-
if not isinstance(execution_inputs, list):
|
|
307
|
-
execution_inputs = [execution_inputs]
|
|
308
|
-
if len(execution_inputs) > 0 and isinstance(execution_inputs[0], entities.FunctionIO):
|
|
309
|
-
for single_input in execution_inputs:
|
|
310
|
-
extra_input.update(single_input.to_json(resource='execution'))
|
|
311
|
-
else:
|
|
312
|
-
raise exceptions.PlatformException('400', 'Unknown input type')
|
|
313
|
-
payload = dict()
|
|
314
|
-
payload['batch'] = dict()
|
|
315
|
-
payload['batch']['query'] = filters.prepare()
|
|
316
|
-
payload['batch']['args'] = extra_input
|
|
317
|
-
|
|
318
|
-
if node_id is not None:
|
|
319
|
-
payload['nodeId'] = node_id
|
|
320
|
-
|
|
321
|
-
success, response = self._client_api.gen_request(
|
|
322
|
-
path='/pipelines/{}/execute'.format(pipeline_id),
|
|
323
|
-
req_type='POST',
|
|
324
|
-
json_req=payload
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
if not success:
|
|
328
|
-
raise exceptions.PlatformException(response)
|
|
329
|
-
|
|
330
|
-
response_json = response.json()
|
|
331
|
-
command = entities.Command.from_json(_json=response_json,
|
|
332
|
-
client_api=self._client_api)
|
|
333
|
-
if wait:
|
|
334
|
-
command = command.wait(timeout=0)
|
|
335
|
-
return command
|
|
336
|
-
|
|
337
|
-
@_api_reference.add(path='/pipelines/{pipelineId}/executions/rerun', method='post')
|
|
338
|
-
def rerun(self,
|
|
339
|
-
pipeline_id: str = None,
|
|
340
|
-
method: str = None,
|
|
341
|
-
start_nodes_ids: list = None,
|
|
342
|
-
filters: entities.Filters = None,
|
|
343
|
-
wait: bool = True
|
|
344
|
-
) -> bool:
|
|
345
|
-
"""
|
|
346
|
-
Get Pipeline Execution object
|
|
347
|
-
|
|
348
|
-
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
349
|
-
|
|
350
|
-
:param str pipeline_id: pipeline id
|
|
351
|
-
:param str method: method to run
|
|
352
|
-
:param list start_nodes_ids: list of start nodes ids
|
|
353
|
-
:param filters: Filters entity for a filtering before execute
|
|
354
|
-
:param bool wait: wait until rerun finish
|
|
355
|
-
:return: True if success
|
|
356
|
-
:rtype: bool
|
|
357
|
-
|
|
358
|
-
**Example**:
|
|
359
|
-
|
|
360
|
-
.. code-block:: python
|
|
361
|
-
|
|
362
|
-
pipeline.pipeline_executions.rerun(pipeline_id='pipeline_id', method=dl.CycleRerunMethod.START_FROM_BEGINNING)
|
|
363
|
-
"""
|
|
364
|
-
|
|
365
|
-
if pipeline_id is None and self._pipeline is None:
|
|
366
|
-
raise exceptions.PlatformException('400', 'Must provide param pipeline_id')
|
|
367
|
-
elif pipeline_id is None:
|
|
368
|
-
pipeline_id = self._pipeline.id
|
|
369
|
-
|
|
370
|
-
if filters is None:
|
|
371
|
-
filters = entities.Filters(resource=entities.FiltersResource.PIPELINE_EXECUTION)
|
|
372
|
-
|
|
373
|
-
success, response = self._client_api.gen_request(
|
|
374
|
-
req_type="post",
|
|
375
|
-
path="/pipelines/{pipeline_id}/executions/rerun".format(
|
|
376
|
-
pipeline_id=pipeline_id,
|
|
377
|
-
),
|
|
378
|
-
json_req={
|
|
379
|
-
'pipeline': {
|
|
380
|
-
"method": method,
|
|
381
|
-
"startNodeIds": start_nodes_ids,
|
|
382
|
-
},
|
|
383
|
-
"batch": {
|
|
384
|
-
"query": filters.prepare()
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
)
|
|
388
|
-
|
|
389
|
-
if not success:
|
|
390
|
-
raise exceptions.PlatformException(response)
|
|
391
|
-
|
|
392
|
-
command = entities.Command.from_json(_json=response.json(),
|
|
393
|
-
client_api=self._client_api)
|
|
394
|
-
if not wait:
|
|
395
|
-
return command
|
|
396
|
-
command = command.wait(timeout=0)
|
|
397
|
-
|
|
398
|
-
if 'cycleOptions' not in command.spec:
|
|
399
|
-
raise exceptions.PlatformException(error='400',
|
|
400
|
-
message="cycleOptions key is missing in command response: {!r}"
|
|
401
|
-
.format(response))
|
|
402
|
-
return True
|
|
403
|
-
|
|
404
|
-
def wait(self,
|
|
405
|
-
pipeline_execution_id: str = None,
|
|
406
|
-
pipeline_execution: entities.PipelineExecution = None,
|
|
407
|
-
timeout: int = None,
|
|
408
|
-
backoff_factor=1):
|
|
409
|
-
"""
|
|
410
|
-
Get Service execution object.
|
|
411
|
-
|
|
412
|
-
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
413
|
-
|
|
414
|
-
:param str pipeline_execution_id: pipeline execution id
|
|
415
|
-
:param str pipeline_execution: dl.PipelineExecution, optional. must input one of pipeline execution or pipeline_execution_id
|
|
416
|
-
:param int timeout: seconds to wait until TimeoutError is raised. if <=0 - wait until done - by default wait take the service timeout
|
|
417
|
-
:param float backoff_factor: A backoff factor to apply between attempts after the second try
|
|
418
|
-
:return: Service execution object
|
|
419
|
-
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
420
|
-
|
|
421
|
-
**Example**:
|
|
422
|
-
|
|
423
|
-
.. code-block:: python
|
|
424
|
-
|
|
425
|
-
pipeline.pipeline_executions.wait(pipeline_execution_id='pipeline_execution_id')
|
|
426
|
-
"""
|
|
427
|
-
if pipeline_execution is None:
|
|
428
|
-
if pipeline_execution_id is None:
|
|
429
|
-
raise ValueError('Must input at least one: [pipeline_execution, pipeline_execution_id]')
|
|
430
|
-
else:
|
|
431
|
-
pipeline_execution_id = pipeline_execution.id
|
|
432
|
-
elapsed = 0
|
|
433
|
-
start = time.time()
|
|
434
|
-
if timeout is None or timeout <= 0:
|
|
435
|
-
timeout = np.inf
|
|
436
|
-
|
|
437
|
-
num_tries = 1
|
|
438
|
-
while elapsed < timeout:
|
|
439
|
-
pipeline_execution = self.get(pipeline_execution_id=pipeline_execution_id)
|
|
440
|
-
if not pipeline_execution.in_progress():
|
|
441
|
-
break
|
|
442
|
-
elapsed = time.time() - start
|
|
443
|
-
if elapsed >= timeout:
|
|
444
|
-
raise TimeoutError(
|
|
445
|
-
f"Pipeline execution wait() function timed out. id: {pipeline_execution.id!r}, status: {pipeline_execution.status}.")
|
|
446
|
-
sleep_time = np.min([timeout - elapsed, backoff_factor * (2 ** num_tries), MAX_SLEEP_TIME])
|
|
447
|
-
num_tries += 1
|
|
448
|
-
logger.debug(
|
|
449
|
-
f"Pipeline execution {pipeline_execution.id!r} has been running for {elapsed:.2f}[s]. Sleeping for {sleep_time:.2f}[s]")
|
|
450
|
-
time.sleep(sleep_time)
|
|
451
|
-
return pipeline_execution
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from .. import entities, repositories, exceptions, miscellaneous, services, _api_reference
|
|
6
|
+
from ..services.api_client import ApiClient
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(name='dtlpy')
|
|
9
|
+
MAX_SLEEP_TIME = 30
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PipelineExecutions:
|
|
13
|
+
"""
|
|
14
|
+
PipelineExecutions Repository
|
|
15
|
+
|
|
16
|
+
The PipelineExecutions class allows users to manage pipeline executions. See our documentation for more information on `pipelines <https://dataloop.ai/docs/pipelines-overview>`_.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
client_api: ApiClient,
|
|
22
|
+
project: entities.Project = None,
|
|
23
|
+
pipeline: entities.Pipeline = None
|
|
24
|
+
):
|
|
25
|
+
self._client_api = client_api
|
|
26
|
+
self._project = project
|
|
27
|
+
self._pipeline = pipeline
|
|
28
|
+
|
|
29
|
+
############
|
|
30
|
+
# entities #
|
|
31
|
+
############
|
|
32
|
+
@property
|
|
33
|
+
def project(self) -> entities.Project:
|
|
34
|
+
if self._project is None:
|
|
35
|
+
try:
|
|
36
|
+
self._project = repositories.Projects(client_api=self._client_api).get()
|
|
37
|
+
except exceptions.NotFound:
|
|
38
|
+
raise exceptions.PlatformException(
|
|
39
|
+
error='2001',
|
|
40
|
+
message='Missing "project". need to set a Project entity or use project.pipelines repository')
|
|
41
|
+
return self._project
|
|
42
|
+
|
|
43
|
+
@project.setter
|
|
44
|
+
def project(self, project: entities.Project):
|
|
45
|
+
if not isinstance(project, entities.Project):
|
|
46
|
+
raise ValueError('Must input a valid Project entity')
|
|
47
|
+
self._project = project
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def pipeline(self) -> entities.Pipeline:
|
|
51
|
+
assert isinstance(self._pipeline, entities.Pipeline)
|
|
52
|
+
return self._pipeline
|
|
53
|
+
|
|
54
|
+
@pipeline.setter
|
|
55
|
+
def pipeline(self, pipeline: entities.Pipeline):
|
|
56
|
+
if not isinstance(pipeline, entities.Pipeline):
|
|
57
|
+
raise ValueError('Must input a valid pipeline entity')
|
|
58
|
+
self._pipeline = pipeline
|
|
59
|
+
|
|
60
|
+
###########
|
|
61
|
+
# methods #
|
|
62
|
+
###########
|
|
63
|
+
# @_api_reference.add(path='/pipelines/{pipelineId}/executions/{executionId}', method='get')
|
|
64
|
+
def get(self,
|
|
65
|
+
pipeline_execution_id: str,
|
|
66
|
+
pipeline_id: str = None
|
|
67
|
+
) -> entities.PipelineExecution:
|
|
68
|
+
"""
|
|
69
|
+
Get Pipeline Execution object
|
|
70
|
+
|
|
71
|
+
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
72
|
+
|
|
73
|
+
:param str pipeline_execution_id: pipeline execution id
|
|
74
|
+
:param str pipeline_id: pipeline id
|
|
75
|
+
:return: PipelineExecution object
|
|
76
|
+
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
77
|
+
|
|
78
|
+
**Example**:
|
|
79
|
+
|
|
80
|
+
.. code-block:: python
|
|
81
|
+
|
|
82
|
+
pipeline_executions = pipeline.pipeline_executions.get(pipeline_id='pipeline_id')
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
if pipeline_id is None and self._pipeline is None:
|
|
86
|
+
raise exceptions.PlatformException('400', 'Must provide param pipeline_id')
|
|
87
|
+
elif pipeline_id is None:
|
|
88
|
+
pipeline_id = self._pipeline.id
|
|
89
|
+
|
|
90
|
+
success, response = self._client_api.gen_request(
|
|
91
|
+
req_type="get",
|
|
92
|
+
path="/pipelines/{pipeline_id}/executions/{pipeline_execution_id}".format(
|
|
93
|
+
pipeline_id=pipeline_id,
|
|
94
|
+
pipeline_execution_id=pipeline_execution_id
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
if not success:
|
|
98
|
+
raise exceptions.PlatformException(response)
|
|
99
|
+
|
|
100
|
+
pipeline_execution = entities.PipelineExecution.from_json(
|
|
101
|
+
client_api=self._client_api,
|
|
102
|
+
_json=response.json(),
|
|
103
|
+
pipeline=self._pipeline
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return pipeline_execution
|
|
107
|
+
|
|
108
|
+
def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.PipelineExecution]:
|
|
109
|
+
pool = self._client_api.thread_pools(pool_name='entity.create')
|
|
110
|
+
jobs = [None for _ in range(len(response_items))]
|
|
111
|
+
|
|
112
|
+
for i_pipeline_execution, pipeline_execution in enumerate(response_items):
|
|
113
|
+
jobs[i_pipeline_execution] = pool.submit(
|
|
114
|
+
entities.PipelineExecution._protected_from_json,
|
|
115
|
+
**{
|
|
116
|
+
'client_api': self._client_api,
|
|
117
|
+
'_json': pipeline_execution,
|
|
118
|
+
'pipeline': self._pipeline
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# get all results
|
|
123
|
+
# noinspection PyUnresolvedReferences
|
|
124
|
+
results = [j.result() for j in jobs]
|
|
125
|
+
# log errors
|
|
126
|
+
_ = [logger.warning(r[1]) for r in results if r[0] is False]
|
|
127
|
+
# return good jobs
|
|
128
|
+
pipeline_executions = miscellaneous.List([r[1] for r in results if r[0] is True])
|
|
129
|
+
return pipeline_executions
|
|
130
|
+
|
|
131
|
+
def _list(self, filters: entities.Filters):
|
|
132
|
+
url = '/pipelines/query'
|
|
133
|
+
|
|
134
|
+
# request
|
|
135
|
+
success, response = self._client_api.gen_request(
|
|
136
|
+
req_type='post',
|
|
137
|
+
path=url,
|
|
138
|
+
json_req=filters.prepare()
|
|
139
|
+
)
|
|
140
|
+
if not success:
|
|
141
|
+
raise exceptions.PlatformException(response)
|
|
142
|
+
return response.json()
|
|
143
|
+
|
|
144
|
+
@_api_reference.add(path='/pipelines/query', method='post')
|
|
145
|
+
def list(self, filters: entities.Filters = None) -> entities.PagedEntities:
|
|
146
|
+
"""
|
|
147
|
+
List project pipeline executions.
|
|
148
|
+
|
|
149
|
+
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
150
|
+
|
|
151
|
+
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
152
|
+
:return: Paged entity
|
|
153
|
+
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
154
|
+
|
|
155
|
+
**Example**:
|
|
156
|
+
|
|
157
|
+
.. code-block:: python
|
|
158
|
+
|
|
159
|
+
pipeline_executions = pipeline.pipeline_executions.list()
|
|
160
|
+
"""
|
|
161
|
+
if filters is None:
|
|
162
|
+
filters = entities.Filters(resource=entities.FiltersResource.PIPELINE_EXECUTION)
|
|
163
|
+
# assert type filters
|
|
164
|
+
elif not isinstance(filters, entities.Filters):
|
|
165
|
+
raise exceptions.PlatformException(error='400',
|
|
166
|
+
message='Unknown filters type: {!r}'.format(type(filters)))
|
|
167
|
+
if filters.resource != entities.FiltersResource.PIPELINE_EXECUTION:
|
|
168
|
+
raise exceptions.PlatformException(
|
|
169
|
+
error='400',
|
|
170
|
+
message='Filters resource must to be FiltersResource.PIPELINE_EXECUTION. Got: {!r}'.format(
|
|
171
|
+
filters.resource))
|
|
172
|
+
|
|
173
|
+
project_id = None
|
|
174
|
+
if self._project is not None:
|
|
175
|
+
project_id = self._project.id
|
|
176
|
+
|
|
177
|
+
# TODO - uncomment this after DAT-24496 is done and cycles have projectId
|
|
178
|
+
# if self._project is not None:
|
|
179
|
+
# filters.add(field='projectId', values=self.project.id)
|
|
180
|
+
|
|
181
|
+
if self._pipeline is not None:
|
|
182
|
+
filters.add(field='pipelineId', values=self._pipeline.id)
|
|
183
|
+
|
|
184
|
+
paged = entities.PagedEntities(
|
|
185
|
+
items_repository=self,
|
|
186
|
+
filters=filters,
|
|
187
|
+
page_offset=filters.page,
|
|
188
|
+
page_size=filters.page_size,
|
|
189
|
+
project_id=project_id,
|
|
190
|
+
client_api=self._client_api
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
paged.get_page()
|
|
194
|
+
return paged
|
|
195
|
+
|
|
196
|
+
@_api_reference.add(path="/pipelines/{pipelineId}/execute", method="post")
|
|
197
|
+
def create(
|
|
198
|
+
self,
|
|
199
|
+
pipeline_id: str = None,
|
|
200
|
+
execution_input=None,
|
|
201
|
+
node_id: str = None,
|
|
202
|
+
test_mode: bool = None
|
|
203
|
+
):
|
|
204
|
+
"""
|
|
205
|
+
Execute a pipeline.
|
|
206
|
+
|
|
207
|
+
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
208
|
+
|
|
209
|
+
:param pipeline_id: pipeline id
|
|
210
|
+
:param execution_input: list of the dl.FunctionIO or dict of pipeline input - example {'item': 'item_id'}
|
|
211
|
+
:param node_id: node id to start from
|
|
212
|
+
:param bool test_mode: if True, the pipeline will be executed in test mode
|
|
213
|
+
:return: entities.PipelineExecution object
|
|
214
|
+
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
215
|
+
|
|
216
|
+
**Example**:
|
|
217
|
+
|
|
218
|
+
.. code-block:: python
|
|
219
|
+
|
|
220
|
+
pipeline_execution = pipeline.pipeline_executions.create(pipeline_id='pipeline_id', execution_input={'item': 'item_id'})
|
|
221
|
+
"""
|
|
222
|
+
if pipeline_id is None:
|
|
223
|
+
if self._pipeline is None:
|
|
224
|
+
raise exceptions.PlatformException('400', 'Please provide pipeline id')
|
|
225
|
+
pipeline_id = self._pipeline.id
|
|
226
|
+
|
|
227
|
+
pipeline_options = dict()
|
|
228
|
+
if test_mode is not None:
|
|
229
|
+
pipeline_options["testMode"] = test_mode
|
|
230
|
+
if execution_input is None:
|
|
231
|
+
# support pipeline executions without any input
|
|
232
|
+
pass
|
|
233
|
+
elif isinstance(execution_input, dict):
|
|
234
|
+
pipeline_options["input"] = execution_input
|
|
235
|
+
else:
|
|
236
|
+
if not isinstance(execution_input, list):
|
|
237
|
+
execution_input = [execution_input]
|
|
238
|
+
if len(execution_input) > 0 and isinstance(execution_input[0], entities.FunctionIO):
|
|
239
|
+
pipeline_options["input"] = dict()
|
|
240
|
+
for single_input in execution_input:
|
|
241
|
+
pipeline_options["input"].update(single_input.to_json(resource="execution"))
|
|
242
|
+
else:
|
|
243
|
+
raise exceptions.PlatformException('400', 'Unknown input type')
|
|
244
|
+
|
|
245
|
+
if node_id is not None:
|
|
246
|
+
pipeline_options["nodeId"] = node_id
|
|
247
|
+
|
|
248
|
+
success, response = self._client_api.gen_request(
|
|
249
|
+
path="/pipelines/{}/execute".format(pipeline_id),
|
|
250
|
+
req_type="POST",
|
|
251
|
+
json_req={"pipeline": pipeline_options},
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
if not success:
|
|
255
|
+
raise exceptions.PlatformException(response)
|
|
256
|
+
|
|
257
|
+
execution = entities.PipelineExecution.from_json(_json=response.json(),
|
|
258
|
+
client_api=self._client_api,
|
|
259
|
+
pipeline=self._pipeline)
|
|
260
|
+
return execution
|
|
261
|
+
|
|
262
|
+
@_api_reference.add(path='/pipelines/{pipelineId}/execute', method='post')
|
|
263
|
+
def create_batch(
|
|
264
|
+
self,
|
|
265
|
+
pipeline_id: str,
|
|
266
|
+
filters,
|
|
267
|
+
execution_inputs=None,
|
|
268
|
+
wait=True,
|
|
269
|
+
node_id: str = None
|
|
270
|
+
):
|
|
271
|
+
"""
|
|
272
|
+
Create batch executions of a pipeline.
|
|
273
|
+
|
|
274
|
+
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
275
|
+
|
|
276
|
+
:param pipeline_id: pipeline id
|
|
277
|
+
:param filters: Filters entity for a filtering before execute
|
|
278
|
+
:param execution_inputs: list of the dl.FunctionIO or dict of pipeline input - example {'item': 'item_id'}, that represent the extra inputs of the function
|
|
279
|
+
:param bool wait: wait until create task finish
|
|
280
|
+
:return: entities.PipelineExecution object
|
|
281
|
+
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
282
|
+
|
|
283
|
+
**Example**:
|
|
284
|
+
|
|
285
|
+
.. code-block:: python
|
|
286
|
+
|
|
287
|
+
command = pipeline.pipeline_executions.create_batch(
|
|
288
|
+
execution_inputs=dl.FunctionIO(type=dl.PackageInputType.STRING, value='test', name='string'),
|
|
289
|
+
filters=dl.Filters(field='dir', values='/test'))
|
|
290
|
+
"""
|
|
291
|
+
if pipeline_id is None:
|
|
292
|
+
if self._pipeline is None:
|
|
293
|
+
raise exceptions.PlatformException('400', 'Please provide pipeline id')
|
|
294
|
+
pipeline_id = self._pipeline.id
|
|
295
|
+
|
|
296
|
+
if filters is None:
|
|
297
|
+
raise exceptions.PlatformException('400', 'Please provide filter')
|
|
298
|
+
extra_input = dict()
|
|
299
|
+
|
|
300
|
+
if execution_inputs is None:
|
|
301
|
+
execution_inputs = {}
|
|
302
|
+
|
|
303
|
+
if isinstance(execution_inputs, dict):
|
|
304
|
+
extra_input = execution_inputs
|
|
305
|
+
else:
|
|
306
|
+
if not isinstance(execution_inputs, list):
|
|
307
|
+
execution_inputs = [execution_inputs]
|
|
308
|
+
if len(execution_inputs) > 0 and isinstance(execution_inputs[0], entities.FunctionIO):
|
|
309
|
+
for single_input in execution_inputs:
|
|
310
|
+
extra_input.update(single_input.to_json(resource='execution'))
|
|
311
|
+
else:
|
|
312
|
+
raise exceptions.PlatformException('400', 'Unknown input type')
|
|
313
|
+
payload = dict()
|
|
314
|
+
payload['batch'] = dict()
|
|
315
|
+
payload['batch']['query'] = filters.prepare()
|
|
316
|
+
payload['batch']['args'] = extra_input
|
|
317
|
+
|
|
318
|
+
if node_id is not None:
|
|
319
|
+
payload['nodeId'] = node_id
|
|
320
|
+
|
|
321
|
+
success, response = self._client_api.gen_request(
|
|
322
|
+
path='/pipelines/{}/execute'.format(pipeline_id),
|
|
323
|
+
req_type='POST',
|
|
324
|
+
json_req=payload
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
if not success:
|
|
328
|
+
raise exceptions.PlatformException(response)
|
|
329
|
+
|
|
330
|
+
response_json = response.json()
|
|
331
|
+
command = entities.Command.from_json(_json=response_json,
|
|
332
|
+
client_api=self._client_api)
|
|
333
|
+
if wait:
|
|
334
|
+
command = command.wait(timeout=0)
|
|
335
|
+
return command
|
|
336
|
+
|
|
337
|
+
@_api_reference.add(path='/pipelines/{pipelineId}/executions/rerun', method='post')
|
|
338
|
+
def rerun(self,
|
|
339
|
+
pipeline_id: str = None,
|
|
340
|
+
method: str = None,
|
|
341
|
+
start_nodes_ids: list = None,
|
|
342
|
+
filters: entities.Filters = None,
|
|
343
|
+
wait: bool = True
|
|
344
|
+
) -> bool:
|
|
345
|
+
"""
|
|
346
|
+
Get Pipeline Execution object
|
|
347
|
+
|
|
348
|
+
**prerequisites**: You must be an *owner* or *developer* to use this method.
|
|
349
|
+
|
|
350
|
+
:param str pipeline_id: pipeline id
|
|
351
|
+
:param str method: method to run
|
|
352
|
+
:param list start_nodes_ids: list of start nodes ids
|
|
353
|
+
:param filters: Filters entity for a filtering before execute
|
|
354
|
+
:param bool wait: wait until rerun finish
|
|
355
|
+
:return: True if success
|
|
356
|
+
:rtype: bool
|
|
357
|
+
|
|
358
|
+
**Example**:
|
|
359
|
+
|
|
360
|
+
.. code-block:: python
|
|
361
|
+
|
|
362
|
+
pipeline.pipeline_executions.rerun(pipeline_id='pipeline_id', method=dl.CycleRerunMethod.START_FROM_BEGINNING)
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
if pipeline_id is None and self._pipeline is None:
|
|
366
|
+
raise exceptions.PlatformException('400', 'Must provide param pipeline_id')
|
|
367
|
+
elif pipeline_id is None:
|
|
368
|
+
pipeline_id = self._pipeline.id
|
|
369
|
+
|
|
370
|
+
if filters is None:
|
|
371
|
+
filters = entities.Filters(resource=entities.FiltersResource.PIPELINE_EXECUTION)
|
|
372
|
+
|
|
373
|
+
success, response = self._client_api.gen_request(
|
|
374
|
+
req_type="post",
|
|
375
|
+
path="/pipelines/{pipeline_id}/executions/rerun".format(
|
|
376
|
+
pipeline_id=pipeline_id,
|
|
377
|
+
),
|
|
378
|
+
json_req={
|
|
379
|
+
'pipeline': {
|
|
380
|
+
"method": method,
|
|
381
|
+
"startNodeIds": start_nodes_ids,
|
|
382
|
+
},
|
|
383
|
+
"batch": {
|
|
384
|
+
"query": filters.prepare()
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
if not success:
|
|
390
|
+
raise exceptions.PlatformException(response)
|
|
391
|
+
|
|
392
|
+
command = entities.Command.from_json(_json=response.json(),
|
|
393
|
+
client_api=self._client_api)
|
|
394
|
+
if not wait:
|
|
395
|
+
return command
|
|
396
|
+
command = command.wait(timeout=0)
|
|
397
|
+
|
|
398
|
+
if 'cycleOptions' not in command.spec:
|
|
399
|
+
raise exceptions.PlatformException(error='400',
|
|
400
|
+
message="cycleOptions key is missing in command response: {!r}"
|
|
401
|
+
.format(response))
|
|
402
|
+
return True
|
|
403
|
+
|
|
404
|
+
def wait(self,
|
|
405
|
+
pipeline_execution_id: str = None,
|
|
406
|
+
pipeline_execution: entities.PipelineExecution = None,
|
|
407
|
+
timeout: int = None,
|
|
408
|
+
backoff_factor=1):
|
|
409
|
+
"""
|
|
410
|
+
Get Service execution object.
|
|
411
|
+
|
|
412
|
+
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
413
|
+
|
|
414
|
+
:param str pipeline_execution_id: pipeline execution id
|
|
415
|
+
:param str pipeline_execution: dl.PipelineExecution, optional. must input one of pipeline execution or pipeline_execution_id
|
|
416
|
+
:param int timeout: seconds to wait until TimeoutError is raised. if <=0 - wait until done - by default wait take the service timeout
|
|
417
|
+
:param float backoff_factor: A backoff factor to apply between attempts after the second try
|
|
418
|
+
:return: Service execution object
|
|
419
|
+
:rtype: dtlpy.entities.pipeline_execution.PipelineExecution
|
|
420
|
+
|
|
421
|
+
**Example**:
|
|
422
|
+
|
|
423
|
+
.. code-block:: python
|
|
424
|
+
|
|
425
|
+
pipeline.pipeline_executions.wait(pipeline_execution_id='pipeline_execution_id')
|
|
426
|
+
"""
|
|
427
|
+
if pipeline_execution is None:
|
|
428
|
+
if pipeline_execution_id is None:
|
|
429
|
+
raise ValueError('Must input at least one: [pipeline_execution, pipeline_execution_id]')
|
|
430
|
+
else:
|
|
431
|
+
pipeline_execution_id = pipeline_execution.id
|
|
432
|
+
elapsed = 0
|
|
433
|
+
start = time.time()
|
|
434
|
+
if timeout is None or timeout <= 0:
|
|
435
|
+
timeout = np.inf
|
|
436
|
+
|
|
437
|
+
num_tries = 1
|
|
438
|
+
while elapsed < timeout:
|
|
439
|
+
pipeline_execution = self.get(pipeline_execution_id=pipeline_execution_id)
|
|
440
|
+
if not pipeline_execution.in_progress():
|
|
441
|
+
break
|
|
442
|
+
elapsed = time.time() - start
|
|
443
|
+
if elapsed >= timeout:
|
|
444
|
+
raise TimeoutError(
|
|
445
|
+
f"Pipeline execution wait() function timed out. id: {pipeline_execution.id!r}, status: {pipeline_execution.status}.")
|
|
446
|
+
sleep_time = np.min([timeout - elapsed, backoff_factor * (2 ** num_tries), MAX_SLEEP_TIME])
|
|
447
|
+
num_tries += 1
|
|
448
|
+
logger.debug(
|
|
449
|
+
f"Pipeline execution {pipeline_execution.id!r} has been running for {elapsed:.2f}[s]. Sleeping for {sleep_time:.2f}[s]")
|
|
450
|
+
time.sleep(sleep_time)
|
|
451
|
+
return pipeline_execution
|