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.
Files changed (238) hide show
  1. dtlpy/__init__.py +491 -491
  2. dtlpy/__version__.py +1 -1
  3. dtlpy/assets/__init__.py +26 -26
  4. dtlpy/assets/code_server/config.yaml +2 -2
  5. dtlpy/assets/code_server/installation.sh +24 -24
  6. dtlpy/assets/code_server/launch.json +13 -13
  7. dtlpy/assets/code_server/settings.json +2 -2
  8. dtlpy/assets/main.py +53 -53
  9. dtlpy/assets/main_partial.py +18 -18
  10. dtlpy/assets/mock.json +11 -11
  11. dtlpy/assets/model_adapter.py +83 -83
  12. dtlpy/assets/package.json +61 -61
  13. dtlpy/assets/package_catalog.json +29 -29
  14. dtlpy/assets/package_gitignore +307 -307
  15. dtlpy/assets/service_runners/__init__.py +33 -33
  16. dtlpy/assets/service_runners/converter.py +96 -96
  17. dtlpy/assets/service_runners/multi_method.py +49 -49
  18. dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
  19. dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
  20. dtlpy/assets/service_runners/multi_method_item.py +52 -52
  21. dtlpy/assets/service_runners/multi_method_json.py +52 -52
  22. dtlpy/assets/service_runners/single_method.py +37 -37
  23. dtlpy/assets/service_runners/single_method_annotation.py +43 -43
  24. dtlpy/assets/service_runners/single_method_dataset.py +43 -43
  25. dtlpy/assets/service_runners/single_method_item.py +41 -41
  26. dtlpy/assets/service_runners/single_method_json.py +42 -42
  27. dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
  28. dtlpy/assets/voc_annotation_template.xml +23 -23
  29. dtlpy/caches/base_cache.py +32 -32
  30. dtlpy/caches/cache.py +473 -473
  31. dtlpy/caches/dl_cache.py +201 -201
  32. dtlpy/caches/filesystem_cache.py +89 -89
  33. dtlpy/caches/redis_cache.py +84 -84
  34. dtlpy/dlp/__init__.py +20 -20
  35. dtlpy/dlp/cli_utilities.py +367 -367
  36. dtlpy/dlp/command_executor.py +764 -764
  37. dtlpy/dlp/dlp +1 -1
  38. dtlpy/dlp/dlp.bat +1 -1
  39. dtlpy/dlp/dlp.py +128 -128
  40. dtlpy/dlp/parser.py +651 -651
  41. dtlpy/entities/__init__.py +83 -83
  42. dtlpy/entities/analytic.py +347 -347
  43. dtlpy/entities/annotation.py +1879 -1879
  44. dtlpy/entities/annotation_collection.py +699 -699
  45. dtlpy/entities/annotation_definitions/__init__.py +20 -20
  46. dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
  47. dtlpy/entities/annotation_definitions/box.py +195 -195
  48. dtlpy/entities/annotation_definitions/classification.py +67 -67
  49. dtlpy/entities/annotation_definitions/comparison.py +72 -72
  50. dtlpy/entities/annotation_definitions/cube.py +204 -204
  51. dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
  52. dtlpy/entities/annotation_definitions/description.py +32 -32
  53. dtlpy/entities/annotation_definitions/ellipse.py +124 -124
  54. dtlpy/entities/annotation_definitions/free_text.py +62 -62
  55. dtlpy/entities/annotation_definitions/gis.py +69 -69
  56. dtlpy/entities/annotation_definitions/note.py +139 -139
  57. dtlpy/entities/annotation_definitions/point.py +117 -117
  58. dtlpy/entities/annotation_definitions/polygon.py +182 -182
  59. dtlpy/entities/annotation_definitions/polyline.py +111 -111
  60. dtlpy/entities/annotation_definitions/pose.py +92 -92
  61. dtlpy/entities/annotation_definitions/ref_image.py +86 -86
  62. dtlpy/entities/annotation_definitions/segmentation.py +240 -240
  63. dtlpy/entities/annotation_definitions/subtitle.py +34 -34
  64. dtlpy/entities/annotation_definitions/text.py +85 -85
  65. dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
  66. dtlpy/entities/app.py +220 -220
  67. dtlpy/entities/app_module.py +107 -107
  68. dtlpy/entities/artifact.py +174 -174
  69. dtlpy/entities/assignment.py +399 -399
  70. dtlpy/entities/base_entity.py +214 -214
  71. dtlpy/entities/bot.py +113 -113
  72. dtlpy/entities/codebase.py +292 -292
  73. dtlpy/entities/collection.py +38 -38
  74. dtlpy/entities/command.py +169 -169
  75. dtlpy/entities/compute.py +449 -449
  76. dtlpy/entities/dataset.py +1299 -1299
  77. dtlpy/entities/directory_tree.py +44 -44
  78. dtlpy/entities/dpk.py +470 -470
  79. dtlpy/entities/driver.py +235 -235
  80. dtlpy/entities/execution.py +397 -397
  81. dtlpy/entities/feature.py +124 -124
  82. dtlpy/entities/feature_set.py +152 -145
  83. dtlpy/entities/filters.py +798 -798
  84. dtlpy/entities/gis_item.py +107 -107
  85. dtlpy/entities/integration.py +184 -184
  86. dtlpy/entities/item.py +975 -959
  87. dtlpy/entities/label.py +123 -123
  88. dtlpy/entities/links.py +85 -85
  89. dtlpy/entities/message.py +175 -175
  90. dtlpy/entities/model.py +684 -684
  91. dtlpy/entities/node.py +1005 -1005
  92. dtlpy/entities/ontology.py +810 -803
  93. dtlpy/entities/organization.py +287 -287
  94. dtlpy/entities/package.py +657 -657
  95. dtlpy/entities/package_defaults.py +5 -5
  96. dtlpy/entities/package_function.py +185 -185
  97. dtlpy/entities/package_module.py +113 -113
  98. dtlpy/entities/package_slot.py +118 -118
  99. dtlpy/entities/paged_entities.py +299 -299
  100. dtlpy/entities/pipeline.py +624 -624
  101. dtlpy/entities/pipeline_execution.py +279 -279
  102. dtlpy/entities/project.py +394 -394
  103. dtlpy/entities/prompt_item.py +505 -505
  104. dtlpy/entities/recipe.py +301 -301
  105. dtlpy/entities/reflect_dict.py +102 -102
  106. dtlpy/entities/resource_execution.py +138 -138
  107. dtlpy/entities/service.py +974 -963
  108. dtlpy/entities/service_driver.py +117 -117
  109. dtlpy/entities/setting.py +294 -294
  110. dtlpy/entities/task.py +495 -495
  111. dtlpy/entities/time_series.py +143 -143
  112. dtlpy/entities/trigger.py +426 -426
  113. dtlpy/entities/user.py +118 -118
  114. dtlpy/entities/webhook.py +124 -124
  115. dtlpy/examples/__init__.py +19 -19
  116. dtlpy/examples/add_labels.py +135 -135
  117. dtlpy/examples/add_metadata_to_item.py +21 -21
  118. dtlpy/examples/annotate_items_using_model.py +65 -65
  119. dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
  120. dtlpy/examples/annotations_convert_to_voc.py +9 -9
  121. dtlpy/examples/annotations_convert_to_yolo.py +9 -9
  122. dtlpy/examples/convert_annotation_types.py +51 -51
  123. dtlpy/examples/converter.py +143 -143
  124. dtlpy/examples/copy_annotations.py +22 -22
  125. dtlpy/examples/copy_folder.py +31 -31
  126. dtlpy/examples/create_annotations.py +51 -51
  127. dtlpy/examples/create_video_annotations.py +83 -83
  128. dtlpy/examples/delete_annotations.py +26 -26
  129. dtlpy/examples/filters.py +113 -113
  130. dtlpy/examples/move_item.py +23 -23
  131. dtlpy/examples/play_video_annotation.py +13 -13
  132. dtlpy/examples/show_item_and_mask.py +53 -53
  133. dtlpy/examples/triggers.py +49 -49
  134. dtlpy/examples/upload_batch_of_items.py +20 -20
  135. dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
  136. dtlpy/examples/upload_items_with_modalities.py +43 -43
  137. dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
  138. dtlpy/examples/upload_yolo_format_annotations.py +70 -70
  139. dtlpy/exceptions.py +125 -125
  140. dtlpy/miscellaneous/__init__.py +20 -20
  141. dtlpy/miscellaneous/dict_differ.py +95 -95
  142. dtlpy/miscellaneous/git_utils.py +217 -217
  143. dtlpy/miscellaneous/json_utils.py +14 -14
  144. dtlpy/miscellaneous/list_print.py +105 -105
  145. dtlpy/miscellaneous/zipping.py +130 -130
  146. dtlpy/ml/__init__.py +20 -20
  147. dtlpy/ml/base_feature_extractor_adapter.py +27 -27
  148. dtlpy/ml/base_model_adapter.py +1287 -1230
  149. dtlpy/ml/metrics.py +461 -461
  150. dtlpy/ml/predictions_utils.py +274 -274
  151. dtlpy/ml/summary_writer.py +57 -57
  152. dtlpy/ml/train_utils.py +60 -60
  153. dtlpy/new_instance.py +252 -252
  154. dtlpy/repositories/__init__.py +56 -56
  155. dtlpy/repositories/analytics.py +85 -85
  156. dtlpy/repositories/annotations.py +916 -916
  157. dtlpy/repositories/apps.py +383 -383
  158. dtlpy/repositories/artifacts.py +452 -452
  159. dtlpy/repositories/assignments.py +599 -599
  160. dtlpy/repositories/bots.py +213 -213
  161. dtlpy/repositories/codebases.py +559 -559
  162. dtlpy/repositories/collections.py +332 -332
  163. dtlpy/repositories/commands.py +152 -152
  164. dtlpy/repositories/compositions.py +61 -61
  165. dtlpy/repositories/computes.py +439 -439
  166. dtlpy/repositories/datasets.py +1585 -1504
  167. dtlpy/repositories/downloader.py +1157 -923
  168. dtlpy/repositories/dpks.py +433 -433
  169. dtlpy/repositories/drivers.py +482 -482
  170. dtlpy/repositories/executions.py +815 -815
  171. dtlpy/repositories/feature_sets.py +256 -226
  172. dtlpy/repositories/features.py +255 -255
  173. dtlpy/repositories/integrations.py +484 -484
  174. dtlpy/repositories/items.py +912 -912
  175. dtlpy/repositories/messages.py +94 -94
  176. dtlpy/repositories/models.py +1000 -1000
  177. dtlpy/repositories/nodes.py +80 -80
  178. dtlpy/repositories/ontologies.py +511 -511
  179. dtlpy/repositories/organizations.py +525 -525
  180. dtlpy/repositories/packages.py +1941 -1941
  181. dtlpy/repositories/pipeline_executions.py +451 -451
  182. dtlpy/repositories/pipelines.py +640 -640
  183. dtlpy/repositories/projects.py +539 -539
  184. dtlpy/repositories/recipes.py +429 -399
  185. dtlpy/repositories/resource_executions.py +137 -137
  186. dtlpy/repositories/schema.py +120 -120
  187. dtlpy/repositories/service_drivers.py +213 -213
  188. dtlpy/repositories/services.py +1704 -1704
  189. dtlpy/repositories/settings.py +339 -339
  190. dtlpy/repositories/tasks.py +1477 -1477
  191. dtlpy/repositories/times_series.py +278 -278
  192. dtlpy/repositories/triggers.py +536 -536
  193. dtlpy/repositories/upload_element.py +257 -257
  194. dtlpy/repositories/uploader.py +661 -661
  195. dtlpy/repositories/webhooks.py +249 -249
  196. dtlpy/services/__init__.py +22 -22
  197. dtlpy/services/aihttp_retry.py +131 -131
  198. dtlpy/services/api_client.py +1786 -1785
  199. dtlpy/services/api_reference.py +40 -40
  200. dtlpy/services/async_utils.py +133 -133
  201. dtlpy/services/calls_counter.py +44 -44
  202. dtlpy/services/check_sdk.py +68 -68
  203. dtlpy/services/cookie.py +115 -115
  204. dtlpy/services/create_logger.py +156 -156
  205. dtlpy/services/events.py +84 -84
  206. dtlpy/services/logins.py +235 -235
  207. dtlpy/services/reporter.py +256 -256
  208. dtlpy/services/service_defaults.py +91 -91
  209. dtlpy/utilities/__init__.py +20 -20
  210. dtlpy/utilities/annotations/__init__.py +16 -16
  211. dtlpy/utilities/annotations/annotation_converters.py +269 -269
  212. dtlpy/utilities/base_package_runner.py +285 -264
  213. dtlpy/utilities/converter.py +1650 -1650
  214. dtlpy/utilities/dataset_generators/__init__.py +1 -1
  215. dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
  216. dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
  217. dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
  218. dtlpy/utilities/local_development/__init__.py +1 -1
  219. dtlpy/utilities/local_development/local_session.py +179 -179
  220. dtlpy/utilities/reports/__init__.py +2 -2
  221. dtlpy/utilities/reports/figures.py +343 -343
  222. dtlpy/utilities/reports/report.py +71 -71
  223. dtlpy/utilities/videos/__init__.py +17 -17
  224. dtlpy/utilities/videos/video_player.py +598 -598
  225. dtlpy/utilities/videos/videos.py +470 -470
  226. {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp +1 -1
  227. dtlpy-1.117.6.data/scripts/dlp.bat +2 -0
  228. {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp.py +128 -128
  229. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/METADATA +186 -186
  230. dtlpy-1.117.6.dist-info/RECORD +239 -0
  231. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/WHEEL +1 -1
  232. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/licenses/LICENSE +200 -200
  233. tests/features/environment.py +551 -551
  234. dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
  235. dtlpy-1.115.44.data/scripts/dlp.bat +0 -2
  236. dtlpy-1.115.44.dist-info/RECORD +0 -240
  237. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/entry_points.txt +0 -0
  238. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/top_level.txt +0 -0
@@ -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()