dtlpy 1.115.44__py3-none-any.whl → 1.116.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 +145 -145
- dtlpy/entities/filters.py +798 -798
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +959 -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 +963 -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 +1257 -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 +1504 -1504
- dtlpy/repositories/downloader.py +976 -923
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -482
- dtlpy/repositories/executions.py +815 -815
- dtlpy/repositories/feature_sets.py +226 -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 +419 -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 +1785 -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.116.6.data}/scripts/dlp +1 -1
- dtlpy-1.116.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/METADATA +186 -186
- dtlpy-1.116.6.dist-info/RECORD +239 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.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.116.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/top_level.txt +0 -0
dtlpy/repositories/triggers.py
CHANGED
|
@@ -1,536 +1,536 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from .. import entities, miscellaneous, exceptions, repositories, _api_reference
|
|
4
|
-
from ..services.api_client import ApiClient
|
|
5
|
-
|
|
6
|
-
logger = logging.getLogger(name='dtlpy')
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Triggers:
|
|
10
|
-
"""
|
|
11
|
-
Triggers Repository
|
|
12
|
-
|
|
13
|
-
The Triggers class allows users to manage triggers and their properties. Triggers activate services.
|
|
14
|
-
See our documentation for more information on `triggers <https://developers.dataloop.ai/tutorials/faas/concept/chapter/>`_.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
def __init__(self,
|
|
18
|
-
client_api: ApiClient,
|
|
19
|
-
project: entities.Project = None,
|
|
20
|
-
service: entities.Service = None,
|
|
21
|
-
project_id: str = None,
|
|
22
|
-
pipeline: entities.Pipeline = None):
|
|
23
|
-
self._client_api = client_api
|
|
24
|
-
self._project = project
|
|
25
|
-
self._service = service
|
|
26
|
-
self._pipeline = pipeline
|
|
27
|
-
if project_id is None:
|
|
28
|
-
if self._project is not None:
|
|
29
|
-
project_id = self._project.id
|
|
30
|
-
elif self._service is not None:
|
|
31
|
-
project_id = self._service.project_id
|
|
32
|
-
|
|
33
|
-
self._project_id = project_id
|
|
34
|
-
|
|
35
|
-
############
|
|
36
|
-
# entities #
|
|
37
|
-
############
|
|
38
|
-
@property
|
|
39
|
-
def service(self) -> entities.Service:
|
|
40
|
-
if self._service is None:
|
|
41
|
-
raise exceptions.PlatformException(
|
|
42
|
-
error='2001',
|
|
43
|
-
message='Missing "service". need to set a Service entity or use service.triggers repository')
|
|
44
|
-
assert isinstance(self._service, entities.Service)
|
|
45
|
-
return self._service
|
|
46
|
-
|
|
47
|
-
@service.setter
|
|
48
|
-
def service(self, service: entities.Service):
|
|
49
|
-
if not isinstance(service, entities.Service):
|
|
50
|
-
raise ValueError('Must input a valid Service entity')
|
|
51
|
-
self._service = service
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
def pipeline(self) -> entities.Pipeline:
|
|
55
|
-
if self._pipeline is None:
|
|
56
|
-
raise exceptions.PlatformException(
|
|
57
|
-
error='2001',
|
|
58
|
-
message='Missing "pipeline". need to set a Pipeline entity or use pipeline.triggers repository')
|
|
59
|
-
assert isinstance(self._pipeline, entities.Pipeline)
|
|
60
|
-
return self._pipeline
|
|
61
|
-
|
|
62
|
-
@pipeline.setter
|
|
63
|
-
def pipeline(self, pipeline: entities.Pipeline):
|
|
64
|
-
if not isinstance(pipeline, entities.Pipeline):
|
|
65
|
-
raise ValueError('Must input a valid Service entity')
|
|
66
|
-
self._pipeline = pipeline
|
|
67
|
-
|
|
68
|
-
@property
|
|
69
|
-
def project(self) -> entities.Project:
|
|
70
|
-
if self._project is None:
|
|
71
|
-
if self._service is not None:
|
|
72
|
-
self._project = self._service._project
|
|
73
|
-
if self._project is None:
|
|
74
|
-
raise exceptions.PlatformException(
|
|
75
|
-
error='2001',
|
|
76
|
-
message='Missing "project". need to set a Project entity or use project.triggers repository')
|
|
77
|
-
assert isinstance(self._project, entities.Project)
|
|
78
|
-
return self._project
|
|
79
|
-
|
|
80
|
-
@project.setter
|
|
81
|
-
def project(self, project: entities.Project):
|
|
82
|
-
if not isinstance(project, entities.Project):
|
|
83
|
-
raise ValueError('Must input a valid Project entity')
|
|
84
|
-
self._project = project
|
|
85
|
-
|
|
86
|
-
def name_validation(self, name: str):
|
|
87
|
-
"""
|
|
88
|
-
This method validates the trigger name. If name is not valid, this method will return an error. Otherwise, it will not return anything.
|
|
89
|
-
|
|
90
|
-
:param str name: trigger name
|
|
91
|
-
"""
|
|
92
|
-
url = '/piper-misc/naming/triggers/{}'.format(name)
|
|
93
|
-
|
|
94
|
-
# request
|
|
95
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
96
|
-
path=url)
|
|
97
|
-
if not success:
|
|
98
|
-
raise exceptions.PlatformException(response)
|
|
99
|
-
|
|
100
|
-
@_api_reference.add(path='/triggers', method='post')
|
|
101
|
-
def create(self,
|
|
102
|
-
# for both trigger types
|
|
103
|
-
service_id: str = None,
|
|
104
|
-
trigger_type: entities.TriggerType = entities.TriggerType.EVENT,
|
|
105
|
-
name: str = None,
|
|
106
|
-
webhook_id=None,
|
|
107
|
-
function_name=entities.package_defaults.DEFAULT_PACKAGE_FUNCTION_NAME,
|
|
108
|
-
project_id=None,
|
|
109
|
-
active=True,
|
|
110
|
-
# for event trigger
|
|
111
|
-
filters=None,
|
|
112
|
-
resource: entities.TriggerResource = entities.TriggerResource.ITEM,
|
|
113
|
-
actions: entities.TriggerAction = None,
|
|
114
|
-
execution_mode: entities.TriggerExecutionMode = entities.TriggerExecutionMode.ONCE,
|
|
115
|
-
# for cron triggers
|
|
116
|
-
start_at=None,
|
|
117
|
-
end_at=None,
|
|
118
|
-
inputs=None,
|
|
119
|
-
cron=None,
|
|
120
|
-
pipeline_id=None,
|
|
121
|
-
pipeline=None,
|
|
122
|
-
pipeline_node_id=None,
|
|
123
|
-
root_node_namespace=None,
|
|
124
|
-
**kwargs) -> entities.BaseTrigger:
|
|
125
|
-
"""
|
|
126
|
-
Create a Trigger. Can create two types: a cron trigger or an event trigger.
|
|
127
|
-
Inputs are different for each type
|
|
128
|
-
|
|
129
|
-
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
130
|
-
|
|
131
|
-
Inputs for all types:
|
|
132
|
-
|
|
133
|
-
:param str service_id: Id of services to be triggered
|
|
134
|
-
:param str trigger_type: can be cron or event. use enum dl.TriggerType for the full list
|
|
135
|
-
:param str name: name of the trigger
|
|
136
|
-
:param str webhook_id: id for webhook to be called
|
|
137
|
-
:param str function_name: the function name to be called when triggered (must be defined in the package)
|
|
138
|
-
:param str project_id: project id where trigger will work
|
|
139
|
-
:param bool active: optional - True/False, default = True, if true trigger is active
|
|
140
|
-
|
|
141
|
-
Inputs for event trigger:
|
|
142
|
-
:param dtlpy.entities.filters.Filters filters: optional - Item/Annotation metadata filters, default = none
|
|
143
|
-
:param str resource: optional - Dataset/Item/Annotation/ItemStatus, default = Item
|
|
144
|
-
:param str actions: optional - Created/Updated/Deleted, default = create
|
|
145
|
-
:param str execution_mode: how many times trigger should be activated; default is "Once". enum dl.TriggerExecutionMode
|
|
146
|
-
|
|
147
|
-
Inputs for cron trigger:
|
|
148
|
-
:param start_at: iso format date string to start activating the cron trigger
|
|
149
|
-
:param end_at: iso format date string to end the cron activation
|
|
150
|
-
:param inputs: dictionary "name":"val" of inputs to the function
|
|
151
|
-
:param str cron: cron spec specifying when it should run. more information: https://en.wikipedia.org/wiki/Cron
|
|
152
|
-
:param str pipeline_id: Id of pipeline to be triggered
|
|
153
|
-
:param pipeline: pipeline entity to be triggered
|
|
154
|
-
:param str pipeline_node_id: Id of pipeline root node to be triggered
|
|
155
|
-
:param root_node_namespace: namespace of pipeline root node to be triggered
|
|
156
|
-
|
|
157
|
-
:return: Trigger entity
|
|
158
|
-
:rtype: dtlpy.entities.trigger.Trigger
|
|
159
|
-
|
|
160
|
-
**Example**:
|
|
161
|
-
|
|
162
|
-
.. code-block:: python
|
|
163
|
-
|
|
164
|
-
service.triggers.create(name='triggername',
|
|
165
|
-
execution_mode=dl.TriggerExecutionMode.ONCE,
|
|
166
|
-
resource='Item',
|
|
167
|
-
actions='Created',
|
|
168
|
-
function_name='run',
|
|
169
|
-
filters={'$and': [{'hidden': False},
|
|
170
|
-
{'type': 'file'}]}
|
|
171
|
-
)
|
|
172
|
-
"""
|
|
173
|
-
scope = kwargs.get('scope', None)
|
|
174
|
-
|
|
175
|
-
if service_id is None and webhook_id is None and pipeline_id is None and pipeline is None:
|
|
176
|
-
if self._service is not None:
|
|
177
|
-
service_id = self._service.id
|
|
178
|
-
elif self._pipeline is not None:
|
|
179
|
-
pipeline = self._pipeline
|
|
180
|
-
pipeline_id = self._pipeline.id
|
|
181
|
-
|
|
182
|
-
if pipeline is not None:
|
|
183
|
-
pipeline_id = pipeline.id
|
|
184
|
-
|
|
185
|
-
# type
|
|
186
|
-
input_num = sum(input_id is not None for input_id in [service_id, webhook_id, pipeline_id])
|
|
187
|
-
if input_num != 1:
|
|
188
|
-
raise exceptions.PlatformException('400',
|
|
189
|
-
'Must provide only one of service id, webhook id, pipeline id or pipeline')
|
|
190
|
-
|
|
191
|
-
if pipeline_id is not None:
|
|
192
|
-
if pipeline is None:
|
|
193
|
-
pipeline = repositories.Pipelines(client_api=self._client_api).get(pipeline_id=pipeline_id)
|
|
194
|
-
if pipeline_node_id is None:
|
|
195
|
-
if pipeline.start_nodes:
|
|
196
|
-
for pipe_node in pipeline.start_nodes:
|
|
197
|
-
if pipe_node['type'] == 'root':
|
|
198
|
-
pipeline_node_id = pipe_node['nodeId']
|
|
199
|
-
if pipeline_node_id is None:
|
|
200
|
-
raise exceptions.PlatformException('400', 'Must provide pipeline node id')
|
|
201
|
-
if not actions:
|
|
202
|
-
actions = [entities.TriggerAction.CREATED]
|
|
203
|
-
pipeline.nodes.get(node_id=pipeline_node_id).add_trigger(
|
|
204
|
-
trigger_type=trigger_type,
|
|
205
|
-
filters=filters,
|
|
206
|
-
resource=resource,
|
|
207
|
-
actions=actions,
|
|
208
|
-
execution_mode=execution_mode,
|
|
209
|
-
cron=cron,
|
|
210
|
-
)
|
|
211
|
-
logger.info("The trigger will not create until pipeline is install")
|
|
212
|
-
pipeline.update()
|
|
213
|
-
return True
|
|
214
|
-
else:
|
|
215
|
-
if name is None:
|
|
216
|
-
if self._service is not None:
|
|
217
|
-
name = self._service.name
|
|
218
|
-
else:
|
|
219
|
-
name = 'defaulttrigger'
|
|
220
|
-
|
|
221
|
-
if filters is None:
|
|
222
|
-
filters = dict()
|
|
223
|
-
elif isinstance(filters, entities.Filters):
|
|
224
|
-
filters = filters.prepare(query_only=True).get('filter', dict())
|
|
225
|
-
|
|
226
|
-
if webhook_id is not None:
|
|
227
|
-
operation = {
|
|
228
|
-
'type': 'webhook',
|
|
229
|
-
'webhookId': webhook_id
|
|
230
|
-
}
|
|
231
|
-
else:
|
|
232
|
-
operation = {
|
|
233
|
-
'type': 'function',
|
|
234
|
-
'serviceId': service_id,
|
|
235
|
-
'functionName': function_name
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if actions is not None:
|
|
240
|
-
if not isinstance(actions, list):
|
|
241
|
-
actions = [actions]
|
|
242
|
-
else:
|
|
243
|
-
actions = [entities.TriggerAction.CREATED]
|
|
244
|
-
|
|
245
|
-
if len(actions) == 0:
|
|
246
|
-
actions = [entities.TriggerAction.CREATED]
|
|
247
|
-
|
|
248
|
-
if trigger_type == entities.TriggerType.EVENT:
|
|
249
|
-
spec = {
|
|
250
|
-
'filter': filters,
|
|
251
|
-
'resource': resource,
|
|
252
|
-
'executionMode': execution_mode,
|
|
253
|
-
'actions': actions
|
|
254
|
-
}
|
|
255
|
-
elif trigger_type == entities.TriggerType.CRON:
|
|
256
|
-
spec = {
|
|
257
|
-
'endAt': end_at,
|
|
258
|
-
'startAt': start_at,
|
|
259
|
-
'cron': cron,
|
|
260
|
-
}
|
|
261
|
-
else:
|
|
262
|
-
raise ValueError('Unknown trigger type: "{}". Use dl.TriggerType for known types'.format(trigger_type))
|
|
263
|
-
|
|
264
|
-
spec['input'] = dict() if inputs is None else inputs
|
|
265
|
-
spec['operation'] = operation
|
|
266
|
-
|
|
267
|
-
# payload
|
|
268
|
-
if self._project_id is None and project_id is None:
|
|
269
|
-
raise exceptions.PlatformException('400', 'Please provide a project id')
|
|
270
|
-
elif project_id is None:
|
|
271
|
-
project_id = self._project_id
|
|
272
|
-
|
|
273
|
-
payload = {
|
|
274
|
-
'type': trigger_type,
|
|
275
|
-
'active': active,
|
|
276
|
-
'projectId': project_id,
|
|
277
|
-
'name': name,
|
|
278
|
-
'spec': spec
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if scope is not None:
|
|
282
|
-
logger.warning(
|
|
283
|
-
"Only superuser is allowed to define a trigger's scope. "
|
|
284
|
-
"If you are not a superuser you will not be able to perform this action")
|
|
285
|
-
payload['scope'] = scope
|
|
286
|
-
|
|
287
|
-
# request
|
|
288
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
289
|
-
path='/triggers',
|
|
290
|
-
json_req=payload)
|
|
291
|
-
|
|
292
|
-
# exception handling
|
|
293
|
-
if not success:
|
|
294
|
-
raise exceptions.PlatformException(response)
|
|
295
|
-
|
|
296
|
-
# return entity
|
|
297
|
-
return entities.BaseTrigger.from_json(_json=response.json(),
|
|
298
|
-
client_api=self._client_api,
|
|
299
|
-
project=self._project if self._project_id == project_id else None,
|
|
300
|
-
service=self._service)
|
|
301
|
-
|
|
302
|
-
@_api_reference.add(path='/triggers/{id}', method='get')
|
|
303
|
-
def get(self, trigger_id=None, trigger_name=None) -> entities.BaseTrigger:
|
|
304
|
-
"""
|
|
305
|
-
Get Trigger object
|
|
306
|
-
|
|
307
|
-
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
308
|
-
|
|
309
|
-
:param str trigger_id: trigger id
|
|
310
|
-
:param str trigger_name: trigger name
|
|
311
|
-
:return: Trigger entity
|
|
312
|
-
:rtype: dtlpy.entities.trigger.Trigger
|
|
313
|
-
|
|
314
|
-
**Example**:
|
|
315
|
-
|
|
316
|
-
.. code-block:: python
|
|
317
|
-
|
|
318
|
-
service.triggers.get(trigger_id='trigger_id')
|
|
319
|
-
"""
|
|
320
|
-
# request
|
|
321
|
-
if trigger_id is not None:
|
|
322
|
-
success, response = self._client_api.gen_request(
|
|
323
|
-
req_type="get",
|
|
324
|
-
path="/triggers/{}".format(trigger_id)
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
# exception handling
|
|
328
|
-
if not success:
|
|
329
|
-
raise exceptions.PlatformException(response)
|
|
330
|
-
|
|
331
|
-
# return entity
|
|
332
|
-
trigger = entities.BaseTrigger.from_json(client_api=self._client_api,
|
|
333
|
-
_json=response.json(),
|
|
334
|
-
project=self._project,
|
|
335
|
-
service=self._service)
|
|
336
|
-
# verify input trigger name is same as the given id
|
|
337
|
-
if trigger_name is not None and trigger.name != trigger_name:
|
|
338
|
-
logger.warning(
|
|
339
|
-
"Mismatch found in triggers.get: trigger_name is different then trigger.name:"
|
|
340
|
-
" {!r} != {!r}".format(
|
|
341
|
-
trigger_name,
|
|
342
|
-
trigger.name))
|
|
343
|
-
else:
|
|
344
|
-
if trigger_name is None:
|
|
345
|
-
raise exceptions.PlatformException('400', 'Must provide either trigger name or trigger id')
|
|
346
|
-
else:
|
|
347
|
-
filters = self.__generate_default_filter()
|
|
348
|
-
filters.add(field='name', values=trigger_name)
|
|
349
|
-
triggers = self.list(filters)
|
|
350
|
-
if triggers.items_count == 0:
|
|
351
|
-
raise exceptions.PlatformException('404', 'Trigger not found')
|
|
352
|
-
elif triggers.items_count == 1:
|
|
353
|
-
trigger = triggers.items[0]
|
|
354
|
-
else:
|
|
355
|
-
raise exceptions.PlatformException('404',
|
|
356
|
-
'More than one trigger by name {} exist'.format(trigger_name))
|
|
357
|
-
|
|
358
|
-
return trigger
|
|
359
|
-
|
|
360
|
-
@_api_reference.add(path='/triggers/{id}', method='delete')
|
|
361
|
-
def delete(self, trigger_id=None, trigger_name=None):
|
|
362
|
-
"""
|
|
363
|
-
Delete Trigger object
|
|
364
|
-
|
|
365
|
-
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
366
|
-
|
|
367
|
-
:param str trigger_id: trigger id
|
|
368
|
-
:param str trigger_name: trigger name
|
|
369
|
-
:return: True is successful error if not
|
|
370
|
-
:rtype: bool
|
|
371
|
-
|
|
372
|
-
**Example**:
|
|
373
|
-
|
|
374
|
-
.. code-block:: python
|
|
375
|
-
|
|
376
|
-
service.triggers.delete(trigger_id='trigger_id')
|
|
377
|
-
"""
|
|
378
|
-
if trigger_id is None:
|
|
379
|
-
if trigger_name is None:
|
|
380
|
-
raise exceptions.PlatformException('400', 'Must provide either trigger name or trigger id')
|
|
381
|
-
else:
|
|
382
|
-
trigger_id = self.get(trigger_name=trigger_name).id
|
|
383
|
-
# request
|
|
384
|
-
success, response = self._client_api.gen_request(
|
|
385
|
-
req_type="delete",
|
|
386
|
-
path="/triggers/{}".format(trigger_id)
|
|
387
|
-
)
|
|
388
|
-
# exception handling
|
|
389
|
-
if not success:
|
|
390
|
-
raise exceptions.PlatformException(response)
|
|
391
|
-
return True
|
|
392
|
-
|
|
393
|
-
@_api_reference.add(path='/triggers/{id}', method='patch')
|
|
394
|
-
def update(self, trigger: entities.BaseTrigger) -> entities.BaseTrigger:
|
|
395
|
-
"""
|
|
396
|
-
Update trigger
|
|
397
|
-
|
|
398
|
-
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
399
|
-
|
|
400
|
-
:param dtlpy.entities.trigger.Trigger trigger: Trigger entity
|
|
401
|
-
:return: Trigger entity
|
|
402
|
-
:rtype: dtlpy.entities.trigger.Trigger
|
|
403
|
-
|
|
404
|
-
**Example**:
|
|
405
|
-
|
|
406
|
-
.. code-block:: python
|
|
407
|
-
|
|
408
|
-
service.triggers.update(trigger='trigger_entity')
|
|
409
|
-
"""
|
|
410
|
-
# payload
|
|
411
|
-
payload = trigger.to_json()
|
|
412
|
-
|
|
413
|
-
# request
|
|
414
|
-
success, response = self._client_api.gen_request(req_type='patch',
|
|
415
|
-
path='/triggers/{}'.format(trigger.id),
|
|
416
|
-
json_req=payload)
|
|
417
|
-
|
|
418
|
-
# exception handling
|
|
419
|
-
if not success:
|
|
420
|
-
raise exceptions.PlatformException(response)
|
|
421
|
-
|
|
422
|
-
# return entity
|
|
423
|
-
return entities.BaseTrigger.from_json(_json=response.json(),
|
|
424
|
-
client_api=self._client_api,
|
|
425
|
-
project=self._project,
|
|
426
|
-
service=self._service)
|
|
427
|
-
|
|
428
|
-
def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.BaseTrigger]:
|
|
429
|
-
pool = self._client_api.thread_pools(pool_name='entity.create')
|
|
430
|
-
jobs = [None for _ in range(len(response_items))]
|
|
431
|
-
# return triggers list
|
|
432
|
-
for i_trigger, trigger in enumerate(response_items):
|
|
433
|
-
jobs[i_trigger] = pool.submit(entities.BaseTrigger._protected_from_json,
|
|
434
|
-
**{'client_api': self._client_api,
|
|
435
|
-
'_json': trigger,
|
|
436
|
-
'project': self._project,
|
|
437
|
-
'service': self._service})
|
|
438
|
-
|
|
439
|
-
# get all results
|
|
440
|
-
results = [j.result() for j in jobs]
|
|
441
|
-
# log errors
|
|
442
|
-
_ = [logger.warning(r[1]) for r in results if r[0] is False]
|
|
443
|
-
# return good jobs
|
|
444
|
-
triggers = miscellaneous.List([r[1] for r in results if r[0] is True])
|
|
445
|
-
return triggers
|
|
446
|
-
|
|
447
|
-
def _list(self, filters: entities.Filters):
|
|
448
|
-
"""
|
|
449
|
-
List project triggers
|
|
450
|
-
:return:
|
|
451
|
-
"""
|
|
452
|
-
url = '/query/faas'
|
|
453
|
-
|
|
454
|
-
success, response = self._client_api.gen_request(req_type='POST',
|
|
455
|
-
path=url,
|
|
456
|
-
json_req=filters.prepare())
|
|
457
|
-
if not success:
|
|
458
|
-
raise exceptions.PlatformException(response)
|
|
459
|
-
return response.json()
|
|
460
|
-
|
|
461
|
-
def __generate_default_filter(self):
|
|
462
|
-
filters = entities.Filters(resource=entities.FiltersResource.TRIGGER)
|
|
463
|
-
if self._project is not None:
|
|
464
|
-
filters.add(field='projectId', values=self._project.id)
|
|
465
|
-
if self._service is not None:
|
|
466
|
-
filters.add(field='spec.operation.serviceId', values=self._service.id)
|
|
467
|
-
if self._pipeline is not None:
|
|
468
|
-
filters.add(field='spec.operation.id', values=self._pipeline.id)
|
|
469
|
-
|
|
470
|
-
return filters
|
|
471
|
-
|
|
472
|
-
@_api_reference.add(path='/query/faas', method='post')
|
|
473
|
-
def list(self, filters: entities.Filters = None) -> entities.PagedEntities:
|
|
474
|
-
"""
|
|
475
|
-
List triggers of a project, package, or service.
|
|
476
|
-
|
|
477
|
-
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
478
|
-
|
|
479
|
-
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
480
|
-
:return: Paged entity
|
|
481
|
-
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
482
|
-
|
|
483
|
-
**Example**:
|
|
484
|
-
|
|
485
|
-
.. code-block:: python
|
|
486
|
-
|
|
487
|
-
service.triggers.list()
|
|
488
|
-
"""
|
|
489
|
-
if filters is None:
|
|
490
|
-
filters = self.__generate_default_filter()
|
|
491
|
-
# assert type filters
|
|
492
|
-
elif not isinstance(filters, entities.Filters):
|
|
493
|
-
raise exceptions.PlatformException(error='400',
|
|
494
|
-
message='Unknown filters type: {!r}'.format(type(filters)))
|
|
495
|
-
|
|
496
|
-
if filters.resource != entities.FiltersResource.TRIGGER:
|
|
497
|
-
raise exceptions.PlatformException(
|
|
498
|
-
error='400',
|
|
499
|
-
message='Filters resource must to be FiltersResource.TRIGGER. Got: {!r}'.format(filters.resource))
|
|
500
|
-
|
|
501
|
-
paged = entities.PagedEntities(items_repository=self,
|
|
502
|
-
filters=filters,
|
|
503
|
-
page_offset=filters.page,
|
|
504
|
-
page_size=filters.page_size,
|
|
505
|
-
client_api=self._client_api)
|
|
506
|
-
paged.get_page()
|
|
507
|
-
return paged
|
|
508
|
-
|
|
509
|
-
def resource_information(self, resource, resource_type, action='Created'):
|
|
510
|
-
"""
|
|
511
|
-
Returns which function should run on an item (based on global triggers).
|
|
512
|
-
|
|
513
|
-
**Prerequisites**: You must be a **superuser** to run this method.
|
|
514
|
-
|
|
515
|
-
:param resource: 'Item' / 'Dataset' / etc
|
|
516
|
-
:param resource_type: dictionary of the resource object
|
|
517
|
-
:param action: 'Created' / 'Updated' / etc.
|
|
518
|
-
|
|
519
|
-
**Example**:
|
|
520
|
-
|
|
521
|
-
.. code-block:: python
|
|
522
|
-
|
|
523
|
-
service.triggers.resource_information(resource='Item', resource_type=item_object, action='Created')
|
|
524
|
-
"""
|
|
525
|
-
url = '/trigger-resource-information'
|
|
526
|
-
|
|
527
|
-
payload = {'resource': resource_type,
|
|
528
|
-
'entity': resource.to_json(),
|
|
529
|
-
'action': action}
|
|
530
|
-
# request
|
|
531
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
532
|
-
path=url,
|
|
533
|
-
json_req=payload)
|
|
534
|
-
if not success:
|
|
535
|
-
raise exceptions.PlatformException(response)
|
|
536
|
-
return response.json()
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .. import entities, miscellaneous, exceptions, repositories, _api_reference
|
|
4
|
+
from ..services.api_client import ApiClient
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(name='dtlpy')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Triggers:
|
|
10
|
+
"""
|
|
11
|
+
Triggers Repository
|
|
12
|
+
|
|
13
|
+
The Triggers class allows users to manage triggers and their properties. Triggers activate services.
|
|
14
|
+
See our documentation for more information on `triggers <https://developers.dataloop.ai/tutorials/faas/concept/chapter/>`_.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self,
|
|
18
|
+
client_api: ApiClient,
|
|
19
|
+
project: entities.Project = None,
|
|
20
|
+
service: entities.Service = None,
|
|
21
|
+
project_id: str = None,
|
|
22
|
+
pipeline: entities.Pipeline = None):
|
|
23
|
+
self._client_api = client_api
|
|
24
|
+
self._project = project
|
|
25
|
+
self._service = service
|
|
26
|
+
self._pipeline = pipeline
|
|
27
|
+
if project_id is None:
|
|
28
|
+
if self._project is not None:
|
|
29
|
+
project_id = self._project.id
|
|
30
|
+
elif self._service is not None:
|
|
31
|
+
project_id = self._service.project_id
|
|
32
|
+
|
|
33
|
+
self._project_id = project_id
|
|
34
|
+
|
|
35
|
+
############
|
|
36
|
+
# entities #
|
|
37
|
+
############
|
|
38
|
+
@property
|
|
39
|
+
def service(self) -> entities.Service:
|
|
40
|
+
if self._service is None:
|
|
41
|
+
raise exceptions.PlatformException(
|
|
42
|
+
error='2001',
|
|
43
|
+
message='Missing "service". need to set a Service entity or use service.triggers repository')
|
|
44
|
+
assert isinstance(self._service, entities.Service)
|
|
45
|
+
return self._service
|
|
46
|
+
|
|
47
|
+
@service.setter
|
|
48
|
+
def service(self, service: entities.Service):
|
|
49
|
+
if not isinstance(service, entities.Service):
|
|
50
|
+
raise ValueError('Must input a valid Service entity')
|
|
51
|
+
self._service = service
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def pipeline(self) -> entities.Pipeline:
|
|
55
|
+
if self._pipeline is None:
|
|
56
|
+
raise exceptions.PlatformException(
|
|
57
|
+
error='2001',
|
|
58
|
+
message='Missing "pipeline". need to set a Pipeline entity or use pipeline.triggers repository')
|
|
59
|
+
assert isinstance(self._pipeline, entities.Pipeline)
|
|
60
|
+
return self._pipeline
|
|
61
|
+
|
|
62
|
+
@pipeline.setter
|
|
63
|
+
def pipeline(self, pipeline: entities.Pipeline):
|
|
64
|
+
if not isinstance(pipeline, entities.Pipeline):
|
|
65
|
+
raise ValueError('Must input a valid Service entity')
|
|
66
|
+
self._pipeline = pipeline
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def project(self) -> entities.Project:
|
|
70
|
+
if self._project is None:
|
|
71
|
+
if self._service is not None:
|
|
72
|
+
self._project = self._service._project
|
|
73
|
+
if self._project is None:
|
|
74
|
+
raise exceptions.PlatformException(
|
|
75
|
+
error='2001',
|
|
76
|
+
message='Missing "project". need to set a Project entity or use project.triggers repository')
|
|
77
|
+
assert isinstance(self._project, entities.Project)
|
|
78
|
+
return self._project
|
|
79
|
+
|
|
80
|
+
@project.setter
|
|
81
|
+
def project(self, project: entities.Project):
|
|
82
|
+
if not isinstance(project, entities.Project):
|
|
83
|
+
raise ValueError('Must input a valid Project entity')
|
|
84
|
+
self._project = project
|
|
85
|
+
|
|
86
|
+
def name_validation(self, name: str):
|
|
87
|
+
"""
|
|
88
|
+
This method validates the trigger name. If name is not valid, this method will return an error. Otherwise, it will not return anything.
|
|
89
|
+
|
|
90
|
+
:param str name: trigger name
|
|
91
|
+
"""
|
|
92
|
+
url = '/piper-misc/naming/triggers/{}'.format(name)
|
|
93
|
+
|
|
94
|
+
# request
|
|
95
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
96
|
+
path=url)
|
|
97
|
+
if not success:
|
|
98
|
+
raise exceptions.PlatformException(response)
|
|
99
|
+
|
|
100
|
+
@_api_reference.add(path='/triggers', method='post')
|
|
101
|
+
def create(self,
|
|
102
|
+
# for both trigger types
|
|
103
|
+
service_id: str = None,
|
|
104
|
+
trigger_type: entities.TriggerType = entities.TriggerType.EVENT,
|
|
105
|
+
name: str = None,
|
|
106
|
+
webhook_id=None,
|
|
107
|
+
function_name=entities.package_defaults.DEFAULT_PACKAGE_FUNCTION_NAME,
|
|
108
|
+
project_id=None,
|
|
109
|
+
active=True,
|
|
110
|
+
# for event trigger
|
|
111
|
+
filters=None,
|
|
112
|
+
resource: entities.TriggerResource = entities.TriggerResource.ITEM,
|
|
113
|
+
actions: entities.TriggerAction = None,
|
|
114
|
+
execution_mode: entities.TriggerExecutionMode = entities.TriggerExecutionMode.ONCE,
|
|
115
|
+
# for cron triggers
|
|
116
|
+
start_at=None,
|
|
117
|
+
end_at=None,
|
|
118
|
+
inputs=None,
|
|
119
|
+
cron=None,
|
|
120
|
+
pipeline_id=None,
|
|
121
|
+
pipeline=None,
|
|
122
|
+
pipeline_node_id=None,
|
|
123
|
+
root_node_namespace=None,
|
|
124
|
+
**kwargs) -> entities.BaseTrigger:
|
|
125
|
+
"""
|
|
126
|
+
Create a Trigger. Can create two types: a cron trigger or an event trigger.
|
|
127
|
+
Inputs are different for each type
|
|
128
|
+
|
|
129
|
+
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
130
|
+
|
|
131
|
+
Inputs for all types:
|
|
132
|
+
|
|
133
|
+
:param str service_id: Id of services to be triggered
|
|
134
|
+
:param str trigger_type: can be cron or event. use enum dl.TriggerType for the full list
|
|
135
|
+
:param str name: name of the trigger
|
|
136
|
+
:param str webhook_id: id for webhook to be called
|
|
137
|
+
:param str function_name: the function name to be called when triggered (must be defined in the package)
|
|
138
|
+
:param str project_id: project id where trigger will work
|
|
139
|
+
:param bool active: optional - True/False, default = True, if true trigger is active
|
|
140
|
+
|
|
141
|
+
Inputs for event trigger:
|
|
142
|
+
:param dtlpy.entities.filters.Filters filters: optional - Item/Annotation metadata filters, default = none
|
|
143
|
+
:param str resource: optional - Dataset/Item/Annotation/ItemStatus, default = Item
|
|
144
|
+
:param str actions: optional - Created/Updated/Deleted, default = create
|
|
145
|
+
:param str execution_mode: how many times trigger should be activated; default is "Once". enum dl.TriggerExecutionMode
|
|
146
|
+
|
|
147
|
+
Inputs for cron trigger:
|
|
148
|
+
:param start_at: iso format date string to start activating the cron trigger
|
|
149
|
+
:param end_at: iso format date string to end the cron activation
|
|
150
|
+
:param inputs: dictionary "name":"val" of inputs to the function
|
|
151
|
+
:param str cron: cron spec specifying when it should run. more information: https://en.wikipedia.org/wiki/Cron
|
|
152
|
+
:param str pipeline_id: Id of pipeline to be triggered
|
|
153
|
+
:param pipeline: pipeline entity to be triggered
|
|
154
|
+
:param str pipeline_node_id: Id of pipeline root node to be triggered
|
|
155
|
+
:param root_node_namespace: namespace of pipeline root node to be triggered
|
|
156
|
+
|
|
157
|
+
:return: Trigger entity
|
|
158
|
+
:rtype: dtlpy.entities.trigger.Trigger
|
|
159
|
+
|
|
160
|
+
**Example**:
|
|
161
|
+
|
|
162
|
+
.. code-block:: python
|
|
163
|
+
|
|
164
|
+
service.triggers.create(name='triggername',
|
|
165
|
+
execution_mode=dl.TriggerExecutionMode.ONCE,
|
|
166
|
+
resource='Item',
|
|
167
|
+
actions='Created',
|
|
168
|
+
function_name='run',
|
|
169
|
+
filters={'$and': [{'hidden': False},
|
|
170
|
+
{'type': 'file'}]}
|
|
171
|
+
)
|
|
172
|
+
"""
|
|
173
|
+
scope = kwargs.get('scope', None)
|
|
174
|
+
|
|
175
|
+
if service_id is None and webhook_id is None and pipeline_id is None and pipeline is None:
|
|
176
|
+
if self._service is not None:
|
|
177
|
+
service_id = self._service.id
|
|
178
|
+
elif self._pipeline is not None:
|
|
179
|
+
pipeline = self._pipeline
|
|
180
|
+
pipeline_id = self._pipeline.id
|
|
181
|
+
|
|
182
|
+
if pipeline is not None:
|
|
183
|
+
pipeline_id = pipeline.id
|
|
184
|
+
|
|
185
|
+
# type
|
|
186
|
+
input_num = sum(input_id is not None for input_id in [service_id, webhook_id, pipeline_id])
|
|
187
|
+
if input_num != 1:
|
|
188
|
+
raise exceptions.PlatformException('400',
|
|
189
|
+
'Must provide only one of service id, webhook id, pipeline id or pipeline')
|
|
190
|
+
|
|
191
|
+
if pipeline_id is not None:
|
|
192
|
+
if pipeline is None:
|
|
193
|
+
pipeline = repositories.Pipelines(client_api=self._client_api).get(pipeline_id=pipeline_id)
|
|
194
|
+
if pipeline_node_id is None:
|
|
195
|
+
if pipeline.start_nodes:
|
|
196
|
+
for pipe_node in pipeline.start_nodes:
|
|
197
|
+
if pipe_node['type'] == 'root':
|
|
198
|
+
pipeline_node_id = pipe_node['nodeId']
|
|
199
|
+
if pipeline_node_id is None:
|
|
200
|
+
raise exceptions.PlatformException('400', 'Must provide pipeline node id')
|
|
201
|
+
if not actions:
|
|
202
|
+
actions = [entities.TriggerAction.CREATED]
|
|
203
|
+
pipeline.nodes.get(node_id=pipeline_node_id).add_trigger(
|
|
204
|
+
trigger_type=trigger_type,
|
|
205
|
+
filters=filters,
|
|
206
|
+
resource=resource,
|
|
207
|
+
actions=actions,
|
|
208
|
+
execution_mode=execution_mode,
|
|
209
|
+
cron=cron,
|
|
210
|
+
)
|
|
211
|
+
logger.info("The trigger will not create until pipeline is install")
|
|
212
|
+
pipeline.update()
|
|
213
|
+
return True
|
|
214
|
+
else:
|
|
215
|
+
if name is None:
|
|
216
|
+
if self._service is not None:
|
|
217
|
+
name = self._service.name
|
|
218
|
+
else:
|
|
219
|
+
name = 'defaulttrigger'
|
|
220
|
+
|
|
221
|
+
if filters is None:
|
|
222
|
+
filters = dict()
|
|
223
|
+
elif isinstance(filters, entities.Filters):
|
|
224
|
+
filters = filters.prepare(query_only=True).get('filter', dict())
|
|
225
|
+
|
|
226
|
+
if webhook_id is not None:
|
|
227
|
+
operation = {
|
|
228
|
+
'type': 'webhook',
|
|
229
|
+
'webhookId': webhook_id
|
|
230
|
+
}
|
|
231
|
+
else:
|
|
232
|
+
operation = {
|
|
233
|
+
'type': 'function',
|
|
234
|
+
'serviceId': service_id,
|
|
235
|
+
'functionName': function_name
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if actions is not None:
|
|
240
|
+
if not isinstance(actions, list):
|
|
241
|
+
actions = [actions]
|
|
242
|
+
else:
|
|
243
|
+
actions = [entities.TriggerAction.CREATED]
|
|
244
|
+
|
|
245
|
+
if len(actions) == 0:
|
|
246
|
+
actions = [entities.TriggerAction.CREATED]
|
|
247
|
+
|
|
248
|
+
if trigger_type == entities.TriggerType.EVENT:
|
|
249
|
+
spec = {
|
|
250
|
+
'filter': filters,
|
|
251
|
+
'resource': resource,
|
|
252
|
+
'executionMode': execution_mode,
|
|
253
|
+
'actions': actions
|
|
254
|
+
}
|
|
255
|
+
elif trigger_type == entities.TriggerType.CRON:
|
|
256
|
+
spec = {
|
|
257
|
+
'endAt': end_at,
|
|
258
|
+
'startAt': start_at,
|
|
259
|
+
'cron': cron,
|
|
260
|
+
}
|
|
261
|
+
else:
|
|
262
|
+
raise ValueError('Unknown trigger type: "{}". Use dl.TriggerType for known types'.format(trigger_type))
|
|
263
|
+
|
|
264
|
+
spec['input'] = dict() if inputs is None else inputs
|
|
265
|
+
spec['operation'] = operation
|
|
266
|
+
|
|
267
|
+
# payload
|
|
268
|
+
if self._project_id is None and project_id is None:
|
|
269
|
+
raise exceptions.PlatformException('400', 'Please provide a project id')
|
|
270
|
+
elif project_id is None:
|
|
271
|
+
project_id = self._project_id
|
|
272
|
+
|
|
273
|
+
payload = {
|
|
274
|
+
'type': trigger_type,
|
|
275
|
+
'active': active,
|
|
276
|
+
'projectId': project_id,
|
|
277
|
+
'name': name,
|
|
278
|
+
'spec': spec
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if scope is not None:
|
|
282
|
+
logger.warning(
|
|
283
|
+
"Only superuser is allowed to define a trigger's scope. "
|
|
284
|
+
"If you are not a superuser you will not be able to perform this action")
|
|
285
|
+
payload['scope'] = scope
|
|
286
|
+
|
|
287
|
+
# request
|
|
288
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
289
|
+
path='/triggers',
|
|
290
|
+
json_req=payload)
|
|
291
|
+
|
|
292
|
+
# exception handling
|
|
293
|
+
if not success:
|
|
294
|
+
raise exceptions.PlatformException(response)
|
|
295
|
+
|
|
296
|
+
# return entity
|
|
297
|
+
return entities.BaseTrigger.from_json(_json=response.json(),
|
|
298
|
+
client_api=self._client_api,
|
|
299
|
+
project=self._project if self._project_id == project_id else None,
|
|
300
|
+
service=self._service)
|
|
301
|
+
|
|
302
|
+
@_api_reference.add(path='/triggers/{id}', method='get')
|
|
303
|
+
def get(self, trigger_id=None, trigger_name=None) -> entities.BaseTrigger:
|
|
304
|
+
"""
|
|
305
|
+
Get Trigger object
|
|
306
|
+
|
|
307
|
+
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
308
|
+
|
|
309
|
+
:param str trigger_id: trigger id
|
|
310
|
+
:param str trigger_name: trigger name
|
|
311
|
+
:return: Trigger entity
|
|
312
|
+
:rtype: dtlpy.entities.trigger.Trigger
|
|
313
|
+
|
|
314
|
+
**Example**:
|
|
315
|
+
|
|
316
|
+
.. code-block:: python
|
|
317
|
+
|
|
318
|
+
service.triggers.get(trigger_id='trigger_id')
|
|
319
|
+
"""
|
|
320
|
+
# request
|
|
321
|
+
if trigger_id is not None:
|
|
322
|
+
success, response = self._client_api.gen_request(
|
|
323
|
+
req_type="get",
|
|
324
|
+
path="/triggers/{}".format(trigger_id)
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# exception handling
|
|
328
|
+
if not success:
|
|
329
|
+
raise exceptions.PlatformException(response)
|
|
330
|
+
|
|
331
|
+
# return entity
|
|
332
|
+
trigger = entities.BaseTrigger.from_json(client_api=self._client_api,
|
|
333
|
+
_json=response.json(),
|
|
334
|
+
project=self._project,
|
|
335
|
+
service=self._service)
|
|
336
|
+
# verify input trigger name is same as the given id
|
|
337
|
+
if trigger_name is not None and trigger.name != trigger_name:
|
|
338
|
+
logger.warning(
|
|
339
|
+
"Mismatch found in triggers.get: trigger_name is different then trigger.name:"
|
|
340
|
+
" {!r} != {!r}".format(
|
|
341
|
+
trigger_name,
|
|
342
|
+
trigger.name))
|
|
343
|
+
else:
|
|
344
|
+
if trigger_name is None:
|
|
345
|
+
raise exceptions.PlatformException('400', 'Must provide either trigger name or trigger id')
|
|
346
|
+
else:
|
|
347
|
+
filters = self.__generate_default_filter()
|
|
348
|
+
filters.add(field='name', values=trigger_name)
|
|
349
|
+
triggers = self.list(filters)
|
|
350
|
+
if triggers.items_count == 0:
|
|
351
|
+
raise exceptions.PlatformException('404', 'Trigger not found')
|
|
352
|
+
elif triggers.items_count == 1:
|
|
353
|
+
trigger = triggers.items[0]
|
|
354
|
+
else:
|
|
355
|
+
raise exceptions.PlatformException('404',
|
|
356
|
+
'More than one trigger by name {} exist'.format(trigger_name))
|
|
357
|
+
|
|
358
|
+
return trigger
|
|
359
|
+
|
|
360
|
+
@_api_reference.add(path='/triggers/{id}', method='delete')
|
|
361
|
+
def delete(self, trigger_id=None, trigger_name=None):
|
|
362
|
+
"""
|
|
363
|
+
Delete Trigger object
|
|
364
|
+
|
|
365
|
+
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
366
|
+
|
|
367
|
+
:param str trigger_id: trigger id
|
|
368
|
+
:param str trigger_name: trigger name
|
|
369
|
+
:return: True is successful error if not
|
|
370
|
+
:rtype: bool
|
|
371
|
+
|
|
372
|
+
**Example**:
|
|
373
|
+
|
|
374
|
+
.. code-block:: python
|
|
375
|
+
|
|
376
|
+
service.triggers.delete(trigger_id='trigger_id')
|
|
377
|
+
"""
|
|
378
|
+
if trigger_id is None:
|
|
379
|
+
if trigger_name is None:
|
|
380
|
+
raise exceptions.PlatformException('400', 'Must provide either trigger name or trigger id')
|
|
381
|
+
else:
|
|
382
|
+
trigger_id = self.get(trigger_name=trigger_name).id
|
|
383
|
+
# request
|
|
384
|
+
success, response = self._client_api.gen_request(
|
|
385
|
+
req_type="delete",
|
|
386
|
+
path="/triggers/{}".format(trigger_id)
|
|
387
|
+
)
|
|
388
|
+
# exception handling
|
|
389
|
+
if not success:
|
|
390
|
+
raise exceptions.PlatformException(response)
|
|
391
|
+
return True
|
|
392
|
+
|
|
393
|
+
@_api_reference.add(path='/triggers/{id}', method='patch')
|
|
394
|
+
def update(self, trigger: entities.BaseTrigger) -> entities.BaseTrigger:
|
|
395
|
+
"""
|
|
396
|
+
Update trigger
|
|
397
|
+
|
|
398
|
+
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
399
|
+
|
|
400
|
+
:param dtlpy.entities.trigger.Trigger trigger: Trigger entity
|
|
401
|
+
:return: Trigger entity
|
|
402
|
+
:rtype: dtlpy.entities.trigger.Trigger
|
|
403
|
+
|
|
404
|
+
**Example**:
|
|
405
|
+
|
|
406
|
+
.. code-block:: python
|
|
407
|
+
|
|
408
|
+
service.triggers.update(trigger='trigger_entity')
|
|
409
|
+
"""
|
|
410
|
+
# payload
|
|
411
|
+
payload = trigger.to_json()
|
|
412
|
+
|
|
413
|
+
# request
|
|
414
|
+
success, response = self._client_api.gen_request(req_type='patch',
|
|
415
|
+
path='/triggers/{}'.format(trigger.id),
|
|
416
|
+
json_req=payload)
|
|
417
|
+
|
|
418
|
+
# exception handling
|
|
419
|
+
if not success:
|
|
420
|
+
raise exceptions.PlatformException(response)
|
|
421
|
+
|
|
422
|
+
# return entity
|
|
423
|
+
return entities.BaseTrigger.from_json(_json=response.json(),
|
|
424
|
+
client_api=self._client_api,
|
|
425
|
+
project=self._project,
|
|
426
|
+
service=self._service)
|
|
427
|
+
|
|
428
|
+
def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.BaseTrigger]:
|
|
429
|
+
pool = self._client_api.thread_pools(pool_name='entity.create')
|
|
430
|
+
jobs = [None for _ in range(len(response_items))]
|
|
431
|
+
# return triggers list
|
|
432
|
+
for i_trigger, trigger in enumerate(response_items):
|
|
433
|
+
jobs[i_trigger] = pool.submit(entities.BaseTrigger._protected_from_json,
|
|
434
|
+
**{'client_api': self._client_api,
|
|
435
|
+
'_json': trigger,
|
|
436
|
+
'project': self._project,
|
|
437
|
+
'service': self._service})
|
|
438
|
+
|
|
439
|
+
# get all results
|
|
440
|
+
results = [j.result() for j in jobs]
|
|
441
|
+
# log errors
|
|
442
|
+
_ = [logger.warning(r[1]) for r in results if r[0] is False]
|
|
443
|
+
# return good jobs
|
|
444
|
+
triggers = miscellaneous.List([r[1] for r in results if r[0] is True])
|
|
445
|
+
return triggers
|
|
446
|
+
|
|
447
|
+
def _list(self, filters: entities.Filters):
|
|
448
|
+
"""
|
|
449
|
+
List project triggers
|
|
450
|
+
:return:
|
|
451
|
+
"""
|
|
452
|
+
url = '/query/faas'
|
|
453
|
+
|
|
454
|
+
success, response = self._client_api.gen_request(req_type='POST',
|
|
455
|
+
path=url,
|
|
456
|
+
json_req=filters.prepare())
|
|
457
|
+
if not success:
|
|
458
|
+
raise exceptions.PlatformException(response)
|
|
459
|
+
return response.json()
|
|
460
|
+
|
|
461
|
+
def __generate_default_filter(self):
|
|
462
|
+
filters = entities.Filters(resource=entities.FiltersResource.TRIGGER)
|
|
463
|
+
if self._project is not None:
|
|
464
|
+
filters.add(field='projectId', values=self._project.id)
|
|
465
|
+
if self._service is not None:
|
|
466
|
+
filters.add(field='spec.operation.serviceId', values=self._service.id)
|
|
467
|
+
if self._pipeline is not None:
|
|
468
|
+
filters.add(field='spec.operation.id', values=self._pipeline.id)
|
|
469
|
+
|
|
470
|
+
return filters
|
|
471
|
+
|
|
472
|
+
@_api_reference.add(path='/query/faas', method='post')
|
|
473
|
+
def list(self, filters: entities.Filters = None) -> entities.PagedEntities:
|
|
474
|
+
"""
|
|
475
|
+
List triggers of a project, package, or service.
|
|
476
|
+
|
|
477
|
+
**Prerequisites**: You must be in the role of an *owner* or *developer*. You must have a service.
|
|
478
|
+
|
|
479
|
+
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
480
|
+
:return: Paged entity
|
|
481
|
+
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
482
|
+
|
|
483
|
+
**Example**:
|
|
484
|
+
|
|
485
|
+
.. code-block:: python
|
|
486
|
+
|
|
487
|
+
service.triggers.list()
|
|
488
|
+
"""
|
|
489
|
+
if filters is None:
|
|
490
|
+
filters = self.__generate_default_filter()
|
|
491
|
+
# assert type filters
|
|
492
|
+
elif not isinstance(filters, entities.Filters):
|
|
493
|
+
raise exceptions.PlatformException(error='400',
|
|
494
|
+
message='Unknown filters type: {!r}'.format(type(filters)))
|
|
495
|
+
|
|
496
|
+
if filters.resource != entities.FiltersResource.TRIGGER:
|
|
497
|
+
raise exceptions.PlatformException(
|
|
498
|
+
error='400',
|
|
499
|
+
message='Filters resource must to be FiltersResource.TRIGGER. Got: {!r}'.format(filters.resource))
|
|
500
|
+
|
|
501
|
+
paged = entities.PagedEntities(items_repository=self,
|
|
502
|
+
filters=filters,
|
|
503
|
+
page_offset=filters.page,
|
|
504
|
+
page_size=filters.page_size,
|
|
505
|
+
client_api=self._client_api)
|
|
506
|
+
paged.get_page()
|
|
507
|
+
return paged
|
|
508
|
+
|
|
509
|
+
def resource_information(self, resource, resource_type, action='Created'):
|
|
510
|
+
"""
|
|
511
|
+
Returns which function should run on an item (based on global triggers).
|
|
512
|
+
|
|
513
|
+
**Prerequisites**: You must be a **superuser** to run this method.
|
|
514
|
+
|
|
515
|
+
:param resource: 'Item' / 'Dataset' / etc
|
|
516
|
+
:param resource_type: dictionary of the resource object
|
|
517
|
+
:param action: 'Created' / 'Updated' / etc.
|
|
518
|
+
|
|
519
|
+
**Example**:
|
|
520
|
+
|
|
521
|
+
.. code-block:: python
|
|
522
|
+
|
|
523
|
+
service.triggers.resource_information(resource='Item', resource_type=item_object, action='Created')
|
|
524
|
+
"""
|
|
525
|
+
url = '/trigger-resource-information'
|
|
526
|
+
|
|
527
|
+
payload = {'resource': resource_type,
|
|
528
|
+
'entity': resource.to_json(),
|
|
529
|
+
'action': action}
|
|
530
|
+
# request
|
|
531
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
532
|
+
path=url,
|
|
533
|
+
json_req=payload)
|
|
534
|
+
if not success:
|
|
535
|
+
raise exceptions.PlatformException(response)
|
|
536
|
+
return response.json()
|