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,383 +1,383 @@
1
- import logging
2
-
3
- from .. import entities, exceptions, miscellaneous, repositories
4
- from ..services.api_client import ApiClient
5
-
6
- logger = logging.getLogger(name='dtlpy')
7
-
8
-
9
- class Apps:
10
-
11
- def __init__(self, client_api: ApiClient, project: entities.Project = None, project_id: str = None):
12
- self._client_api = client_api
13
- self._project = project
14
- self._project_id = project_id
15
- self._commands = None
16
-
17
- @property
18
- def project(self) -> entities.Project:
19
- if self._project is None:
20
- if self._project_id is None:
21
- raise exceptions.PlatformException(
22
- error='2001',
23
- message='Missing "project". need to set a Project entity or use project.apps repository')
24
- else:
25
- self._project = repositories.Projects(client_api=self._client_api).get(project_id=self._project_id)
26
- assert isinstance(self._project, entities.Project)
27
- return self._project
28
-
29
- @property
30
- def commands(self) -> repositories.Commands:
31
- if self._commands is None:
32
- self._commands = repositories.Commands(client_api=self._client_api)
33
- return self._commands
34
-
35
- @project.setter
36
- def project(self, project: entities.Project):
37
- if not isinstance(project, entities.Project):
38
- raise ValueError('Must input a valid Project entity')
39
- self._project = project
40
-
41
- def get(self,
42
- app_name: str = None,
43
- app_id: str = None,
44
- fetch: bool = None) -> entities.App:
45
- """
46
- Get an app object.
47
-
48
- note: It's required to pass either app_id of app_name
49
-
50
- :param str app_id: optional - search by id.
51
- :param str app_name: optional - search by name.
52
- :param bool fetch: optional - fetch entity from platform, default taken from cookie
53
-
54
- **Example**:
55
-
56
- .. code-block:: python
57
- app = self.apps.get(app_id='app_id')
58
- """
59
- if fetch is None:
60
- fetch = self._client_api.fetch_entities
61
-
62
- if app_id is None and app_name is None:
63
- raise exceptions.PlatformException(
64
- error='400',
65
- message='You must provide an identifier in inputs')
66
- if fetch:
67
- if app_name is not None:
68
- app = self.__get_by_name(name=app_name)
69
- else:
70
- success, response = self._client_api.gen_request(req_type='get', path="/apps/{}".format(app_id))
71
- if not success:
72
- raise exceptions.PlatformException(response)
73
- app = entities.App.from_json(client_api=self._client_api,
74
- _json=response.json(),
75
- project=self._project)
76
- else:
77
- app = entities.App.from_json(
78
- _json={
79
- 'id': app_id,
80
- 'name': app_name
81
- },
82
- client_api=self._client_api,
83
- project=self._project,
84
- is_fetched=False
85
- )
86
- assert isinstance(app, entities.App)
87
- return app
88
-
89
- def __get_by_name(self, name) -> entities.App:
90
- filters = entities.Filters(field='name',
91
- values=name,
92
- resource=entities.FiltersResource.APP,
93
- use_defaults=False)
94
- if self._project is not None:
95
- filters.add(field='projectId', values=self.project.id)
96
- apps = self.list(filters=filters)
97
- if apps.items_count == 0:
98
- raise exceptions.PlatformException(
99
- error='404',
100
- message='app not found. Name: {}'.format(name))
101
- elif apps.items_count > 1:
102
- raise exceptions.PlatformException(
103
- error='400',
104
- message='More than one app found by the name of: {} '.format(apps))
105
- return apps.items[0]
106
-
107
- def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.App]:
108
- pool = self._client_api.thread_pools(pool_name='entity.create')
109
- jobs = [None for _ in range(len(response_items))]
110
- # return triggers list
111
- for i_item, item in enumerate(response_items):
112
- jobs[i_item] = pool.submit(entities.App._protected_from_json,
113
- **{'client_api': self._client_api,
114
- '_json': item,
115
- 'project': self._project})
116
- # get all results
117
- results = [j.result() for j in jobs]
118
- # log errors
119
- _ = [logger.warning(r[1]) for r in results if r[0] is False]
120
- # return good jobs
121
- items = miscellaneous.List([r[1] for r in results if r[0] is True])
122
- return items
123
-
124
- def _list(self, filters: entities.Filters):
125
- url = '/apps/query'
126
-
127
- # request
128
- success, response = self._client_api.gen_request(req_type='post',
129
- path=url,
130
- json_req=filters.prepare())
131
- if not success:
132
- raise exceptions.PlatformException(response)
133
- return response.json()
134
-
135
- def list(self, filters: entities.Filters = None, project_id: str = None) -> entities.PagedEntities:
136
- """
137
- List the available apps in the specified project.
138
-
139
- :param entities.Filters filters: the filters to apply to the list
140
- :param str project_id: the project id to apply thew filters on.
141
- :return a paged entity representing the list of apps.
142
-
143
- ** Example **
144
- .. code-block:: python
145
- apps = dl.apps.list(project_id='id')
146
- """
147
- if filters is None:
148
- filters = entities.Filters(resource=entities.FiltersResource.APP)
149
- # assert type filters
150
- elif not isinstance(filters, entities.Filters):
151
- raise exceptions.PlatformException(error='400',
152
- message='Unknown filters type: {!r}'.format(type(filters)))
153
- if filters.resource != entities.FiltersResource.APP:
154
- raise exceptions.PlatformException(
155
- error='400',
156
- message='Filters resource must to be FiltersResource.APP. Got: {!r}'.format(filters.resource))
157
-
158
- # noinspection DuplicatedCode
159
- if project_id is None and self._project is not None:
160
- project_id = self._project.id
161
-
162
- if project_id is not None:
163
- filters.add(field='projectId', values=project_id)
164
-
165
- paged = entities.PagedEntities(items_repository=self,
166
- filters=filters,
167
- page_offset=filters.page,
168
- page_size=filters.page_size,
169
- project_id=project_id,
170
- client_api=self._client_api)
171
- paged.get_page()
172
- return paged
173
-
174
- def update(self, app: entities.App = None, app_id: str = None, wait: bool = True) -> bool:
175
- """
176
- Update the current app to the new configuration
177
-
178
- :param entities.App app: The app to update.
179
- :param str app_id: The app id to update.
180
- :param bool wait: wait for the operation to finish.
181
- :return bool whether the operation ran successfully or not
182
-
183
- **Example**
184
- .. code-block:: python
185
- succeed = dl.apps.update(app)
186
- """
187
- if app_id is not None and app is None:
188
- app = self.get(app_id=app_id)
189
- if app is None:
190
- raise exceptions.PlatformException(error='400', message='You must provide app or app_id')
191
- success, response = self._client_api.gen_request(req_type='put',
192
- path=f"/apps/{app.id}",
193
- json_req=app.to_json())
194
- if not success:
195
- raise exceptions.PlatformException(response)
196
-
197
- app = entities.App.from_json(
198
- _json=response.json(),
199
- client_api=self._client_api,
200
- project=self.project
201
- )
202
- if app.metadata:
203
- command_id = app.metadata.get('system', {}).get('commands', {}).get('update', None)
204
- if wait and app.status == entities.CompositionStatus.UPDATING and command_id is not None:
205
- command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
206
- command.wait()
207
- app = self.get(app_id=app.id)
208
-
209
- return success
210
-
211
- def install(self,
212
- dpk: entities.Dpk,
213
- app_name: str = None,
214
- organization_id: str = None,
215
- custom_installation: dict = None,
216
- scope: entities.AppScope = None,
217
- wait: bool = True,
218
- integrations: list = None
219
- ) -> entities.App:
220
- """
221
- Install the specified app in the project.
222
-
223
- Note: You must pass either the app_id or app_name
224
- :param entities.App dpk: the app entity
225
- :param str app_name: installed app name. default is the dpk name
226
- :param str organization_id: the organization which you want to apply on the filter.
227
- :param dict custom_installation: partial installation.
228
- :param str scope: the scope of the app. default is project.
229
- :param bool wait: wait for the operation to finish.
230
- :param list integrations: list of integrations to install with the app.
231
-
232
- :return the installed app.
233
- :rtype entities.App
234
-
235
- **Example**
236
- .. code-block:: python
237
- app = dl.apps.install(dpk=dpk)
238
- """
239
- if dpk is None:
240
- raise exceptions.PlatformException(error='400', message='You must provide an app')
241
-
242
- if app_name is None:
243
- app_name = dpk.display_name
244
- if isinstance(scope, entities.AppScope):
245
- scope = scope.value
246
- app = entities.App.from_json(_json={'name': app_name,
247
- 'projectId': self.project.id,
248
- 'orgId': organization_id,
249
- 'dpkName': dpk.name,
250
- "customInstallation": custom_installation,
251
- 'dpkVersion': dpk.version,
252
- 'scope': scope,
253
- 'integrations': integrations
254
- },
255
- client_api=self._client_api,
256
- project=self.project)
257
- success, response = self._client_api.gen_request(req_type='post',
258
- path="/apps",
259
- json_req=app.to_json())
260
- if not success:
261
- raise exceptions.PlatformException(response)
262
- app = entities.App.from_json(_json=response.json(),
263
- client_api=self._client_api,
264
- project=self.project)
265
-
266
- if app.metadata:
267
- command_id = app.metadata.get('system', {}).get('commands', {}).get('install', None)
268
- if wait and app.status == entities.CompositionStatus.INITIALIZING and command_id is not None:
269
- command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
270
- command.wait()
271
- app = self.get(app_id=app.id)
272
-
273
- return app
274
-
275
- def uninstall(self, app_id: str = None, app_name: str = None, wait: bool = True) -> bool:
276
- """
277
- Delete an app entity.
278
-
279
- Note: You are required to add either app_id or app_name.
280
-
281
- :param str app_id: optional - the id of the app.
282
- :param str app_name: optional - the name of the app.
283
- :param bool wait: optional - wait for the operation to finish.
284
- :return whether we succeed uninstalling the specified app.
285
- :rtype bool
286
-
287
- **Example**
288
- .. code-block:: python
289
- # succeed = dl.apps.delete(app_id='app_id')
290
- """
291
- if app_id is None and app_name is None:
292
- raise exceptions.PlatformException(
293
- error='400',
294
- message='You must provide an identifier in inputs')
295
- if app_name is not None:
296
- app = self.__get_by_name(app_name)
297
- app_id = app.id
298
-
299
- success, response = self._client_api.gen_request(req_type='delete', path='/apps/{}'.format(app_id))
300
- if not success:
301
- raise exceptions.PlatformException(response)
302
-
303
- try:
304
- app = self.get(app_id=app_id)
305
- except Exception as e:
306
- if e.status_code == '404':
307
- return success
308
- else:
309
- raise e
310
- if app.metadata:
311
- command_id = app.metadata.get('system', {}).get('commands', {}).get('uninstall', None)
312
- if wait and app.status == entities.CompositionStatus.TERMINATING and command_id is not None:
313
- command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
314
- command.wait()
315
-
316
- logger.debug(f"App deleted successfully (id: {app_id}, name: {app_name}")
317
- return success
318
-
319
- def resume(self, app: entities.App = None, app_id: str = None) -> bool:
320
- """
321
- Activate an app entity.
322
-
323
- Note: You are required to add either app or app_id.
324
-
325
- :param entities.App app: the app entity
326
- :param str app_id: optional - the id of the app.
327
- :return whether we succeed activating the specified app.
328
- :rtype bool
329
-
330
- **Example**
331
- .. code-block:: python
332
- # succeed = dl.apps.resume(app)
333
- """
334
- if app_id is not None and app is None:
335
- app = self.get(app_id=app_id)
336
-
337
- if app and app.status == entities.CompositionStatus.INSTALLED:
338
- raise exceptions.PlatformException(
339
- error='400',
340
- message='Application is already active'
341
- )
342
- if app is None:
343
- raise exceptions.PlatformException(error='400', message='You must provide app or app_id')
344
-
345
- success, response = self._client_api.gen_request(req_type='post', path='/apps/{}/activate'.format(app.id))
346
- if not success:
347
- raise exceptions.PlatformException(response)
348
-
349
- logger.debug(f"App resumed successfully (id: {app.id}, name: {app.name}")
350
- return success
351
-
352
- def pause(self, app: entities.App = None, app_id: str = None) -> bool:
353
- """
354
- Pausing an app entity.
355
-
356
- Note: You are required to add either app or app_id.
357
-
358
- :param entities.App app: the app entity
359
- :param str app_id: optional - the id of the app.
360
- :return whether we succeed pausing the specified app.
361
- :rtype bool
362
-
363
- **Example**
364
- .. code-block:: python
365
- # succeed = dl.apps.pause(app)
366
- """
367
- if app_id is not None and app is None:
368
- app = self.get(app_id=app_id)
369
-
370
- if app and app.status == entities.CompositionStatus.UNINSTALLED:
371
- raise exceptions.PlatformException(
372
- error='400',
373
- message='Application is already inactive'
374
- )
375
- if app is None:
376
- raise exceptions.PlatformException(error='400', message='You must provide app or app_id')
377
-
378
- success, response = self._client_api.gen_request(req_type='post', path='/apps/{}/deactivate'.format(app.id))
379
- if not success:
380
- raise exceptions.PlatformException(response)
381
-
382
- logger.debug(f"App paused successfully (id: {app.id}, name: {app.name}")
383
- return success
1
+ import logging
2
+
3
+ from .. import entities, exceptions, miscellaneous, repositories
4
+ from ..services.api_client import ApiClient
5
+
6
+ logger = logging.getLogger(name='dtlpy')
7
+
8
+
9
+ class Apps:
10
+
11
+ def __init__(self, client_api: ApiClient, project: entities.Project = None, project_id: str = None):
12
+ self._client_api = client_api
13
+ self._project = project
14
+ self._project_id = project_id
15
+ self._commands = None
16
+
17
+ @property
18
+ def project(self) -> entities.Project:
19
+ if self._project is None:
20
+ if self._project_id is None:
21
+ raise exceptions.PlatformException(
22
+ error='2001',
23
+ message='Missing "project". need to set a Project entity or use project.apps repository')
24
+ else:
25
+ self._project = repositories.Projects(client_api=self._client_api).get(project_id=self._project_id)
26
+ assert isinstance(self._project, entities.Project)
27
+ return self._project
28
+
29
+ @property
30
+ def commands(self) -> repositories.Commands:
31
+ if self._commands is None:
32
+ self._commands = repositories.Commands(client_api=self._client_api)
33
+ return self._commands
34
+
35
+ @project.setter
36
+ def project(self, project: entities.Project):
37
+ if not isinstance(project, entities.Project):
38
+ raise ValueError('Must input a valid Project entity')
39
+ self._project = project
40
+
41
+ def get(self,
42
+ app_name: str = None,
43
+ app_id: str = None,
44
+ fetch: bool = None) -> entities.App:
45
+ """
46
+ Get an app object.
47
+
48
+ note: It's required to pass either app_id of app_name
49
+
50
+ :param str app_id: optional - search by id.
51
+ :param str app_name: optional - search by name.
52
+ :param bool fetch: optional - fetch entity from platform, default taken from cookie
53
+
54
+ **Example**:
55
+
56
+ .. code-block:: python
57
+ app = self.apps.get(app_id='app_id')
58
+ """
59
+ if fetch is None:
60
+ fetch = self._client_api.fetch_entities
61
+
62
+ if app_id is None and app_name is None:
63
+ raise exceptions.PlatformException(
64
+ error='400',
65
+ message='You must provide an identifier in inputs')
66
+ if fetch:
67
+ if app_name is not None:
68
+ app = self.__get_by_name(name=app_name)
69
+ else:
70
+ success, response = self._client_api.gen_request(req_type='get', path="/apps/{}".format(app_id))
71
+ if not success:
72
+ raise exceptions.PlatformException(response)
73
+ app = entities.App.from_json(client_api=self._client_api,
74
+ _json=response.json(),
75
+ project=self._project)
76
+ else:
77
+ app = entities.App.from_json(
78
+ _json={
79
+ 'id': app_id,
80
+ 'name': app_name
81
+ },
82
+ client_api=self._client_api,
83
+ project=self._project,
84
+ is_fetched=False
85
+ )
86
+ assert isinstance(app, entities.App)
87
+ return app
88
+
89
+ def __get_by_name(self, name) -> entities.App:
90
+ filters = entities.Filters(field='name',
91
+ values=name,
92
+ resource=entities.FiltersResource.APP,
93
+ use_defaults=False)
94
+ if self._project is not None:
95
+ filters.add(field='projectId', values=self.project.id)
96
+ apps = self.list(filters=filters)
97
+ if apps.items_count == 0:
98
+ raise exceptions.PlatformException(
99
+ error='404',
100
+ message='app not found. Name: {}'.format(name))
101
+ elif apps.items_count > 1:
102
+ raise exceptions.PlatformException(
103
+ error='400',
104
+ message='More than one app found by the name of: {} '.format(apps))
105
+ return apps.items[0]
106
+
107
+ def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.App]:
108
+ pool = self._client_api.thread_pools(pool_name='entity.create')
109
+ jobs = [None for _ in range(len(response_items))]
110
+ # return triggers list
111
+ for i_item, item in enumerate(response_items):
112
+ jobs[i_item] = pool.submit(entities.App._protected_from_json,
113
+ **{'client_api': self._client_api,
114
+ '_json': item,
115
+ 'project': self._project})
116
+ # get all results
117
+ results = [j.result() for j in jobs]
118
+ # log errors
119
+ _ = [logger.warning(r[1]) for r in results if r[0] is False]
120
+ # return good jobs
121
+ items = miscellaneous.List([r[1] for r in results if r[0] is True])
122
+ return items
123
+
124
+ def _list(self, filters: entities.Filters):
125
+ url = '/apps/query'
126
+
127
+ # request
128
+ success, response = self._client_api.gen_request(req_type='post',
129
+ path=url,
130
+ json_req=filters.prepare())
131
+ if not success:
132
+ raise exceptions.PlatformException(response)
133
+ return response.json()
134
+
135
+ def list(self, filters: entities.Filters = None, project_id: str = None) -> entities.PagedEntities:
136
+ """
137
+ List the available apps in the specified project.
138
+
139
+ :param entities.Filters filters: the filters to apply to the list
140
+ :param str project_id: the project id to apply thew filters on.
141
+ :return a paged entity representing the list of apps.
142
+
143
+ ** Example **
144
+ .. code-block:: python
145
+ apps = dl.apps.list(project_id='id')
146
+ """
147
+ if filters is None:
148
+ filters = entities.Filters(resource=entities.FiltersResource.APP)
149
+ # assert type filters
150
+ elif not isinstance(filters, entities.Filters):
151
+ raise exceptions.PlatformException(error='400',
152
+ message='Unknown filters type: {!r}'.format(type(filters)))
153
+ if filters.resource != entities.FiltersResource.APP:
154
+ raise exceptions.PlatformException(
155
+ error='400',
156
+ message='Filters resource must to be FiltersResource.APP. Got: {!r}'.format(filters.resource))
157
+
158
+ # noinspection DuplicatedCode
159
+ if project_id is None and self._project is not None:
160
+ project_id = self._project.id
161
+
162
+ if project_id is not None:
163
+ filters.add(field='projectId', values=project_id)
164
+
165
+ paged = entities.PagedEntities(items_repository=self,
166
+ filters=filters,
167
+ page_offset=filters.page,
168
+ page_size=filters.page_size,
169
+ project_id=project_id,
170
+ client_api=self._client_api)
171
+ paged.get_page()
172
+ return paged
173
+
174
+ def update(self, app: entities.App = None, app_id: str = None, wait: bool = True) -> bool:
175
+ """
176
+ Update the current app to the new configuration
177
+
178
+ :param entities.App app: The app to update.
179
+ :param str app_id: The app id to update.
180
+ :param bool wait: wait for the operation to finish.
181
+ :return bool whether the operation ran successfully or not
182
+
183
+ **Example**
184
+ .. code-block:: python
185
+ succeed = dl.apps.update(app)
186
+ """
187
+ if app_id is not None and app is None:
188
+ app = self.get(app_id=app_id)
189
+ if app is None:
190
+ raise exceptions.PlatformException(error='400', message='You must provide app or app_id')
191
+ success, response = self._client_api.gen_request(req_type='put',
192
+ path=f"/apps/{app.id}",
193
+ json_req=app.to_json())
194
+ if not success:
195
+ raise exceptions.PlatformException(response)
196
+
197
+ app = entities.App.from_json(
198
+ _json=response.json(),
199
+ client_api=self._client_api,
200
+ project=self.project
201
+ )
202
+ if app.metadata:
203
+ command_id = app.metadata.get('system', {}).get('commands', {}).get('update', None)
204
+ if wait and app.status == entities.CompositionStatus.UPDATING and command_id is not None:
205
+ command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
206
+ command.wait()
207
+ app = self.get(app_id=app.id)
208
+
209
+ return success
210
+
211
+ def install(self,
212
+ dpk: entities.Dpk,
213
+ app_name: str = None,
214
+ organization_id: str = None,
215
+ custom_installation: dict = None,
216
+ scope: entities.AppScope = None,
217
+ wait: bool = True,
218
+ integrations: list = None
219
+ ) -> entities.App:
220
+ """
221
+ Install the specified app in the project.
222
+
223
+ Note: You must pass either the app_id or app_name
224
+ :param entities.App dpk: the app entity
225
+ :param str app_name: installed app name. default is the dpk name
226
+ :param str organization_id: the organization which you want to apply on the filter.
227
+ :param dict custom_installation: partial installation.
228
+ :param str scope: the scope of the app. default is project.
229
+ :param bool wait: wait for the operation to finish.
230
+ :param list integrations: list of integrations to install with the app.
231
+
232
+ :return the installed app.
233
+ :rtype entities.App
234
+
235
+ **Example**
236
+ .. code-block:: python
237
+ app = dl.apps.install(dpk=dpk)
238
+ """
239
+ if dpk is None:
240
+ raise exceptions.PlatformException(error='400', message='You must provide an app')
241
+
242
+ if app_name is None:
243
+ app_name = dpk.display_name
244
+ if isinstance(scope, entities.AppScope):
245
+ scope = scope.value
246
+ app = entities.App.from_json(_json={'name': app_name,
247
+ 'projectId': self.project.id,
248
+ 'orgId': organization_id,
249
+ 'dpkName': dpk.name,
250
+ "customInstallation": custom_installation,
251
+ 'dpkVersion': dpk.version,
252
+ 'scope': scope,
253
+ 'integrations': integrations
254
+ },
255
+ client_api=self._client_api,
256
+ project=self.project)
257
+ success, response = self._client_api.gen_request(req_type='post',
258
+ path="/apps",
259
+ json_req=app.to_json())
260
+ if not success:
261
+ raise exceptions.PlatformException(response)
262
+ app = entities.App.from_json(_json=response.json(),
263
+ client_api=self._client_api,
264
+ project=self.project)
265
+
266
+ if app.metadata:
267
+ command_id = app.metadata.get('system', {}).get('commands', {}).get('install', None)
268
+ if wait and app.status == entities.CompositionStatus.INITIALIZING and command_id is not None:
269
+ command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
270
+ command.wait()
271
+ app = self.get(app_id=app.id)
272
+
273
+ return app
274
+
275
+ def uninstall(self, app_id: str = None, app_name: str = None, wait: bool = True) -> bool:
276
+ """
277
+ Delete an app entity.
278
+
279
+ Note: You are required to add either app_id or app_name.
280
+
281
+ :param str app_id: optional - the id of the app.
282
+ :param str app_name: optional - the name of the app.
283
+ :param bool wait: optional - wait for the operation to finish.
284
+ :return whether we succeed uninstalling the specified app.
285
+ :rtype bool
286
+
287
+ **Example**
288
+ .. code-block:: python
289
+ # succeed = dl.apps.delete(app_id='app_id')
290
+ """
291
+ if app_id is None and app_name is None:
292
+ raise exceptions.PlatformException(
293
+ error='400',
294
+ message='You must provide an identifier in inputs')
295
+ if app_name is not None:
296
+ app = self.__get_by_name(app_name)
297
+ app_id = app.id
298
+
299
+ success, response = self._client_api.gen_request(req_type='delete', path='/apps/{}'.format(app_id))
300
+ if not success:
301
+ raise exceptions.PlatformException(response)
302
+
303
+ try:
304
+ app = self.get(app_id=app_id)
305
+ except Exception as e:
306
+ if e.status_code == '404':
307
+ return success
308
+ else:
309
+ raise e
310
+ if app.metadata:
311
+ command_id = app.metadata.get('system', {}).get('commands', {}).get('uninstall', None)
312
+ if wait and app.status == entities.CompositionStatus.TERMINATING and command_id is not None:
313
+ command = self.commands.get(command_id=command_id, url='api/v1/commands/faas/{}'.format(command_id))
314
+ command.wait()
315
+
316
+ logger.debug(f"App deleted successfully (id: {app_id}, name: {app_name}")
317
+ return success
318
+
319
+ def resume(self, app: entities.App = None, app_id: str = None) -> bool:
320
+ """
321
+ Activate an app entity.
322
+
323
+ Note: You are required to add either app or app_id.
324
+
325
+ :param entities.App app: the app entity
326
+ :param str app_id: optional - the id of the app.
327
+ :return whether we succeed activating the specified app.
328
+ :rtype bool
329
+
330
+ **Example**
331
+ .. code-block:: python
332
+ # succeed = dl.apps.resume(app)
333
+ """
334
+ if app_id is not None and app is None:
335
+ app = self.get(app_id=app_id)
336
+
337
+ if app and app.status == entities.CompositionStatus.INSTALLED:
338
+ raise exceptions.PlatformException(
339
+ error='400',
340
+ message='Application is already active'
341
+ )
342
+ if app is None:
343
+ raise exceptions.PlatformException(error='400', message='You must provide app or app_id')
344
+
345
+ success, response = self._client_api.gen_request(req_type='post', path='/apps/{}/activate'.format(app.id))
346
+ if not success:
347
+ raise exceptions.PlatformException(response)
348
+
349
+ logger.debug(f"App resumed successfully (id: {app.id}, name: {app.name}")
350
+ return success
351
+
352
+ def pause(self, app: entities.App = None, app_id: str = None) -> bool:
353
+ """
354
+ Pausing an app entity.
355
+
356
+ Note: You are required to add either app or app_id.
357
+
358
+ :param entities.App app: the app entity
359
+ :param str app_id: optional - the id of the app.
360
+ :return whether we succeed pausing the specified app.
361
+ :rtype bool
362
+
363
+ **Example**
364
+ .. code-block:: python
365
+ # succeed = dl.apps.pause(app)
366
+ """
367
+ if app_id is not None and app is None:
368
+ app = self.get(app_id=app_id)
369
+
370
+ if app and app.status == entities.CompositionStatus.UNINSTALLED:
371
+ raise exceptions.PlatformException(
372
+ error='400',
373
+ message='Application is already inactive'
374
+ )
375
+ if app is None:
376
+ raise exceptions.PlatformException(error='400', message='You must provide app or app_id')
377
+
378
+ success, response = self._client_api.gen_request(req_type='post', path='/apps/{}/deactivate'.format(app.id))
379
+ if not success:
380
+ raise exceptions.PlatformException(response)
381
+
382
+ logger.debug(f"App paused successfully (id: {app.id}, name: {app.name}")
383
+ return success