dtlpy 1.113.10__py3-none-any.whl → 1.114.13__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 (243) hide show
  1. dtlpy/__init__.py +488 -488
  2. dtlpy/__version__.py +1 -1
  3. dtlpy/assets/__init__.py +26 -26
  4. dtlpy/assets/__pycache__/__init__.cpython-38.pyc +0 -0
  5. dtlpy/assets/code_server/config.yaml +2 -2
  6. dtlpy/assets/code_server/installation.sh +24 -24
  7. dtlpy/assets/code_server/launch.json +13 -13
  8. dtlpy/assets/code_server/settings.json +2 -2
  9. dtlpy/assets/main.py +53 -53
  10. dtlpy/assets/main_partial.py +18 -18
  11. dtlpy/assets/mock.json +11 -11
  12. dtlpy/assets/model_adapter.py +83 -83
  13. dtlpy/assets/package.json +61 -61
  14. dtlpy/assets/package_catalog.json +29 -29
  15. dtlpy/assets/package_gitignore +307 -307
  16. dtlpy/assets/service_runners/__init__.py +33 -33
  17. dtlpy/assets/service_runners/converter.py +96 -96
  18. dtlpy/assets/service_runners/multi_method.py +49 -49
  19. dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
  20. dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
  21. dtlpy/assets/service_runners/multi_method_item.py +52 -52
  22. dtlpy/assets/service_runners/multi_method_json.py +52 -52
  23. dtlpy/assets/service_runners/single_method.py +37 -37
  24. dtlpy/assets/service_runners/single_method_annotation.py +43 -43
  25. dtlpy/assets/service_runners/single_method_dataset.py +43 -43
  26. dtlpy/assets/service_runners/single_method_item.py +41 -41
  27. dtlpy/assets/service_runners/single_method_json.py +42 -42
  28. dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
  29. dtlpy/assets/voc_annotation_template.xml +23 -23
  30. dtlpy/caches/base_cache.py +32 -32
  31. dtlpy/caches/cache.py +473 -473
  32. dtlpy/caches/dl_cache.py +201 -201
  33. dtlpy/caches/filesystem_cache.py +89 -89
  34. dtlpy/caches/redis_cache.py +84 -84
  35. dtlpy/dlp/__init__.py +20 -20
  36. dtlpy/dlp/cli_utilities.py +367 -367
  37. dtlpy/dlp/command_executor.py +764 -764
  38. dtlpy/dlp/dlp +1 -1
  39. dtlpy/dlp/dlp.bat +1 -1
  40. dtlpy/dlp/dlp.py +128 -128
  41. dtlpy/dlp/parser.py +651 -651
  42. dtlpy/entities/__init__.py +83 -83
  43. dtlpy/entities/analytic.py +311 -311
  44. dtlpy/entities/annotation.py +1879 -1879
  45. dtlpy/entities/annotation_collection.py +699 -699
  46. dtlpy/entities/annotation_definitions/__init__.py +20 -20
  47. dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
  48. dtlpy/entities/annotation_definitions/box.py +195 -195
  49. dtlpy/entities/annotation_definitions/classification.py +67 -67
  50. dtlpy/entities/annotation_definitions/comparison.py +72 -72
  51. dtlpy/entities/annotation_definitions/cube.py +204 -204
  52. dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
  53. dtlpy/entities/annotation_definitions/description.py +32 -32
  54. dtlpy/entities/annotation_definitions/ellipse.py +124 -124
  55. dtlpy/entities/annotation_definitions/free_text.py +62 -62
  56. dtlpy/entities/annotation_definitions/gis.py +69 -69
  57. dtlpy/entities/annotation_definitions/note.py +139 -139
  58. dtlpy/entities/annotation_definitions/point.py +117 -117
  59. dtlpy/entities/annotation_definitions/polygon.py +182 -182
  60. dtlpy/entities/annotation_definitions/polyline.py +111 -111
  61. dtlpy/entities/annotation_definitions/pose.py +92 -92
  62. dtlpy/entities/annotation_definitions/ref_image.py +86 -86
  63. dtlpy/entities/annotation_definitions/segmentation.py +240 -240
  64. dtlpy/entities/annotation_definitions/subtitle.py +34 -34
  65. dtlpy/entities/annotation_definitions/text.py +85 -85
  66. dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
  67. dtlpy/entities/app.py +220 -220
  68. dtlpy/entities/app_module.py +107 -107
  69. dtlpy/entities/artifact.py +174 -174
  70. dtlpy/entities/assignment.py +399 -399
  71. dtlpy/entities/base_entity.py +214 -214
  72. dtlpy/entities/bot.py +113 -113
  73. dtlpy/entities/codebase.py +296 -296
  74. dtlpy/entities/collection.py +38 -38
  75. dtlpy/entities/command.py +169 -169
  76. dtlpy/entities/compute.py +442 -442
  77. dtlpy/entities/dataset.py +1285 -1285
  78. dtlpy/entities/directory_tree.py +44 -44
  79. dtlpy/entities/dpk.py +470 -470
  80. dtlpy/entities/driver.py +222 -222
  81. dtlpy/entities/execution.py +397 -397
  82. dtlpy/entities/feature.py +124 -124
  83. dtlpy/entities/feature_set.py +145 -145
  84. dtlpy/entities/filters.py +641 -641
  85. dtlpy/entities/gis_item.py +107 -107
  86. dtlpy/entities/integration.py +184 -184
  87. dtlpy/entities/item.py +953 -953
  88. dtlpy/entities/label.py +123 -123
  89. dtlpy/entities/links.py +85 -85
  90. dtlpy/entities/message.py +175 -175
  91. dtlpy/entities/model.py +694 -691
  92. dtlpy/entities/node.py +1005 -1005
  93. dtlpy/entities/ontology.py +803 -803
  94. dtlpy/entities/organization.py +287 -287
  95. dtlpy/entities/package.py +657 -657
  96. dtlpy/entities/package_defaults.py +5 -5
  97. dtlpy/entities/package_function.py +185 -185
  98. dtlpy/entities/package_module.py +113 -113
  99. dtlpy/entities/package_slot.py +118 -118
  100. dtlpy/entities/paged_entities.py +290 -267
  101. dtlpy/entities/pipeline.py +593 -593
  102. dtlpy/entities/pipeline_execution.py +279 -279
  103. dtlpy/entities/project.py +394 -394
  104. dtlpy/entities/prompt_item.py +499 -499
  105. dtlpy/entities/recipe.py +301 -301
  106. dtlpy/entities/reflect_dict.py +102 -102
  107. dtlpy/entities/resource_execution.py +138 -138
  108. dtlpy/entities/service.py +958 -958
  109. dtlpy/entities/service_driver.py +117 -117
  110. dtlpy/entities/setting.py +294 -294
  111. dtlpy/entities/task.py +491 -491
  112. dtlpy/entities/time_series.py +143 -143
  113. dtlpy/entities/trigger.py +426 -426
  114. dtlpy/entities/user.py +118 -118
  115. dtlpy/entities/webhook.py +124 -124
  116. dtlpy/examples/__init__.py +19 -19
  117. dtlpy/examples/add_labels.py +135 -135
  118. dtlpy/examples/add_metadata_to_item.py +21 -21
  119. dtlpy/examples/annotate_items_using_model.py +65 -65
  120. dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
  121. dtlpy/examples/annotations_convert_to_voc.py +9 -9
  122. dtlpy/examples/annotations_convert_to_yolo.py +9 -9
  123. dtlpy/examples/convert_annotation_types.py +51 -51
  124. dtlpy/examples/converter.py +143 -143
  125. dtlpy/examples/copy_annotations.py +22 -22
  126. dtlpy/examples/copy_folder.py +31 -31
  127. dtlpy/examples/create_annotations.py +51 -51
  128. dtlpy/examples/create_video_annotations.py +83 -83
  129. dtlpy/examples/delete_annotations.py +26 -26
  130. dtlpy/examples/filters.py +113 -113
  131. dtlpy/examples/move_item.py +23 -23
  132. dtlpy/examples/play_video_annotation.py +13 -13
  133. dtlpy/examples/show_item_and_mask.py +53 -53
  134. dtlpy/examples/triggers.py +49 -49
  135. dtlpy/examples/upload_batch_of_items.py +20 -20
  136. dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
  137. dtlpy/examples/upload_items_with_modalities.py +43 -43
  138. dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
  139. dtlpy/examples/upload_yolo_format_annotations.py +70 -70
  140. dtlpy/exceptions.py +125 -125
  141. dtlpy/miscellaneous/__init__.py +20 -20
  142. dtlpy/miscellaneous/dict_differ.py +95 -95
  143. dtlpy/miscellaneous/git_utils.py +217 -217
  144. dtlpy/miscellaneous/json_utils.py +14 -14
  145. dtlpy/miscellaneous/list_print.py +105 -105
  146. dtlpy/miscellaneous/zipping.py +130 -130
  147. dtlpy/ml/__init__.py +20 -20
  148. dtlpy/ml/base_feature_extractor_adapter.py +27 -27
  149. dtlpy/ml/base_model_adapter.py +945 -940
  150. dtlpy/ml/metrics.py +461 -461
  151. dtlpy/ml/predictions_utils.py +274 -274
  152. dtlpy/ml/summary_writer.py +57 -57
  153. dtlpy/ml/train_utils.py +60 -60
  154. dtlpy/new_instance.py +252 -252
  155. dtlpy/repositories/__init__.py +56 -56
  156. dtlpy/repositories/analytics.py +85 -85
  157. dtlpy/repositories/annotations.py +916 -916
  158. dtlpy/repositories/apps.py +383 -383
  159. dtlpy/repositories/artifacts.py +452 -452
  160. dtlpy/repositories/assignments.py +599 -599
  161. dtlpy/repositories/bots.py +213 -213
  162. dtlpy/repositories/codebases.py +559 -559
  163. dtlpy/repositories/collections.py +332 -348
  164. dtlpy/repositories/commands.py +158 -158
  165. dtlpy/repositories/compositions.py +61 -61
  166. dtlpy/repositories/computes.py +434 -406
  167. dtlpy/repositories/datasets.py +1291 -1291
  168. dtlpy/repositories/downloader.py +895 -895
  169. dtlpy/repositories/dpks.py +433 -433
  170. dtlpy/repositories/drivers.py +266 -266
  171. dtlpy/repositories/executions.py +817 -817
  172. dtlpy/repositories/feature_sets.py +226 -226
  173. dtlpy/repositories/features.py +238 -238
  174. dtlpy/repositories/integrations.py +484 -484
  175. dtlpy/repositories/items.py +909 -915
  176. dtlpy/repositories/messages.py +94 -94
  177. dtlpy/repositories/models.py +877 -867
  178. dtlpy/repositories/nodes.py +80 -80
  179. dtlpy/repositories/ontologies.py +511 -511
  180. dtlpy/repositories/organizations.py +525 -525
  181. dtlpy/repositories/packages.py +1941 -1941
  182. dtlpy/repositories/pipeline_executions.py +448 -448
  183. dtlpy/repositories/pipelines.py +642 -642
  184. dtlpy/repositories/projects.py +539 -539
  185. dtlpy/repositories/recipes.py +399 -399
  186. dtlpy/repositories/resource_executions.py +137 -137
  187. dtlpy/repositories/schema.py +120 -120
  188. dtlpy/repositories/service_drivers.py +213 -213
  189. dtlpy/repositories/services.py +1704 -1704
  190. dtlpy/repositories/settings.py +339 -339
  191. dtlpy/repositories/tasks.py +1124 -1124
  192. dtlpy/repositories/times_series.py +278 -278
  193. dtlpy/repositories/triggers.py +536 -536
  194. dtlpy/repositories/upload_element.py +257 -257
  195. dtlpy/repositories/uploader.py +651 -651
  196. dtlpy/repositories/webhooks.py +249 -249
  197. dtlpy/services/__init__.py +22 -22
  198. dtlpy/services/aihttp_retry.py +131 -131
  199. dtlpy/services/api_client.py +1782 -1782
  200. dtlpy/services/api_reference.py +40 -40
  201. dtlpy/services/async_utils.py +133 -133
  202. dtlpy/services/calls_counter.py +44 -44
  203. dtlpy/services/check_sdk.py +68 -68
  204. dtlpy/services/cookie.py +115 -115
  205. dtlpy/services/create_logger.py +156 -156
  206. dtlpy/services/events.py +84 -84
  207. dtlpy/services/logins.py +235 -235
  208. dtlpy/services/reporter.py +256 -256
  209. dtlpy/services/service_defaults.py +91 -91
  210. dtlpy/utilities/__init__.py +20 -20
  211. dtlpy/utilities/annotations/__init__.py +16 -16
  212. dtlpy/utilities/annotations/annotation_converters.py +269 -269
  213. dtlpy/utilities/base_package_runner.py +264 -264
  214. dtlpy/utilities/converter.py +1650 -1650
  215. dtlpy/utilities/dataset_generators/__init__.py +1 -1
  216. dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
  217. dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
  218. dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
  219. dtlpy/utilities/local_development/__init__.py +1 -1
  220. dtlpy/utilities/local_development/local_session.py +179 -179
  221. dtlpy/utilities/reports/__init__.py +2 -2
  222. dtlpy/utilities/reports/figures.py +343 -343
  223. dtlpy/utilities/reports/report.py +71 -71
  224. dtlpy/utilities/videos/__init__.py +17 -17
  225. dtlpy/utilities/videos/video_player.py +598 -598
  226. dtlpy/utilities/videos/videos.py +470 -470
  227. {dtlpy-1.113.10.data → dtlpy-1.114.13.data}/scripts/dlp +1 -1
  228. dtlpy-1.114.13.data/scripts/dlp.bat +2 -0
  229. {dtlpy-1.113.10.data → dtlpy-1.114.13.data}/scripts/dlp.py +128 -128
  230. {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/LICENSE +200 -200
  231. {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/METADATA +172 -172
  232. dtlpy-1.114.13.dist-info/RECORD +240 -0
  233. {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/WHEEL +1 -1
  234. tests/features/environment.py +551 -550
  235. dtlpy-1.113.10.data/scripts/dlp.bat +0 -2
  236. dtlpy-1.113.10.dist-info/RECORD +0 -244
  237. tests/assets/__init__.py +0 -0
  238. tests/assets/models_flow/__init__.py +0 -0
  239. tests/assets/models_flow/failedmain.py +0 -52
  240. tests/assets/models_flow/main.py +0 -62
  241. tests/assets/models_flow/main_model.py +0 -54
  242. {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/entry_points.txt +0 -0
  243. {dtlpy-1.113.10.dist-info → dtlpy-1.114.13.dist-info}/top_level.txt +0 -0
dtlpy/entities/package.py CHANGED
@@ -1,657 +1,657 @@
1
- from collections import namedtuple
2
- from typing import Union
3
- from enum import Enum
4
- import traceback
5
- import logging
6
- import inspect
7
- import typing
8
- import json
9
- import os
10
-
11
- from .package_module import PackageModule
12
- from .package_slot import PackageSlot
13
- from .. import repositories, entities, exceptions
14
- from ..services.api_client import ApiClient
15
-
16
- logger = logging.getLogger(name='dtlpy')
17
-
18
-
19
- class RequirementOperator(str, Enum):
20
- EQUAL = '==',
21
- GREATER_THAN = '>',
22
- LESS_THAN = '<',
23
- EQUAL_OR_LESS_THAN = '<=',
24
- EQUAL_OR_GREATER_THAN = '>='
25
-
26
- @staticmethod
27
- def keys():
28
- return [key.value for key in list(RequirementOperator)]
29
-
30
-
31
- class PackageRequirement:
32
-
33
- def __init__(self, name: str, version: str = None, operator: str = None):
34
- self.name = name
35
- self.version = version
36
-
37
- valid_operators = RequirementOperator.keys()
38
- if operator is not None and operator not in valid_operators:
39
- raise Exception('Illegal operator: {}. Please select from: {}'.format(operator, valid_operators))
40
-
41
- self.operator = operator
42
-
43
- def to_json(self):
44
- _json = {'name': self.name}
45
- if self.version is not None:
46
- _json['version'] = self.version
47
- if self.operator is not None:
48
- _json['operator'] = self.operator
49
- return _json
50
-
51
- @classmethod
52
- def from_json(cls, _json: dict):
53
- return cls(**_json)
54
-
55
-
56
- class Package(entities.DlEntity):
57
- """
58
- Package object
59
- """
60
- # platform
61
- id: str = entities.DlProperty(location=['id'], _type=str)
62
- url: str = entities.DlProperty(location=['url'], _type=str)
63
- name: str = entities.DlProperty(location=['name'], _type=str)
64
- version: str = entities.DlProperty(location=['version'], _type=str)
65
- created_at: str = entities.DlProperty(location=['createdAt'], _type=str)
66
- updated_at: str = entities.DlProperty(location=['updatedAt'], _type=str)
67
- project_id: str = entities.DlProperty(location=['projectId'], _type=str)
68
- creator: str = entities.DlProperty(location=['creator'], _type=str)
69
- type: str = entities.DlProperty(location=['type'], _type=str)
70
- metadata: dict = entities.DlProperty(location=['metadata'], _type=dict)
71
- ui_hooks: list = entities.DlProperty(location=['uiHooks'], _type=str)
72
- service_config: dict = entities.DlProperty(location=['serviceConfig'], _type=str)
73
- is_global: bool = entities.DlProperty(location=['global'], _type=str)
74
-
75
- codebase: typing.Any = entities.DlProperty(location=['codebase'], _kls='Codebase')
76
- modules: typing.List[PackageModule] = entities.DlProperty(location=['modules'], _kls='PackageModule')
77
- slots: typing.Union[typing.List[PackageSlot], None] = entities.DlProperty(location=['slots'],
78
- _kls='PackageSlot')
79
- requirements: typing.Union[typing.List[PackageRequirement], None] = entities.DlProperty(location=['requirements'],
80
- _kls='PackageRequirement')
81
-
82
- # sdk
83
- _client_api: ApiClient
84
- _revisions = None
85
- __repositories = None
86
- _project = None
87
-
88
- def __repr__(self):
89
- # TODO need to move to DlEntity
90
- return "Package(id={id}, name={name}, creator={creator}, project_id={project_id}, type={type}, version={version})".format(
91
- id=self.id,
92
- name=self.name,
93
- version=self.version,
94
- type=self.type,
95
- project_id=self.project_id,
96
- creator=self.creator)
97
-
98
- @property
99
- def createdAt(self):
100
- return self.created_at
101
-
102
- @property
103
- def updatedAt(self):
104
- return self.updated_at
105
-
106
- @property
107
- def revisions(self):
108
- if self._revisions is None:
109
- self._revisions = self.packages.revisions(package=self)
110
- return self._revisions
111
-
112
- @property
113
- def platform_url(self):
114
- return self._client_api._get_resource_url("projects/{}/packages/{}/main".format(self.project.id, self.id))
115
-
116
- @property
117
- def codebase_id(self):
118
- if self.codebase is not None and self.codebase.type == entities.PackageCodebaseType.ITEM:
119
- return self.codebase.item_id
120
- return None
121
-
122
- @codebase_id.setter
123
- def codebase_id(self, item_id: str):
124
- self.codebase = entities.ItemCodebase(item_id=item_id)
125
-
126
- @staticmethod
127
- def _protected_from_json(_json, client_api, project=None, is_fetched=True):
128
- """
129
- Same as from_json but with try-except to catch if error
130
-
131
- :param _json: platform json
132
- :param client_api: ApiClient entity
133
- :return:
134
- """
135
- try:
136
- package = Package.from_json(_json=_json,
137
- client_api=client_api,
138
- project=project,
139
- is_fetched=is_fetched)
140
- status = True
141
- except Exception:
142
- package = traceback.format_exc()
143
- status = False
144
- return status, package
145
-
146
- @classmethod
147
- def from_json(cls, _json, client_api, project=None, is_fetched=True):
148
- """
149
- Turn platform representation of package into a package entity
150
-
151
- :param dict _json: platform representation of package
152
- :param dl.ApiClient client_api: ApiClient entity
153
- :param dtlpy.entities.project.Project project: project entity
154
- :param is_fetched: is Entity fetched from Platform
155
- :return: Package entity
156
- :rtype: dtlpy.entities.package.Package
157
- """
158
- if project is not None:
159
- if project.id != _json.get('projectId', None):
160
- logger.warning('Package has been fetched from a project that is not belong to it')
161
- project = None
162
- # Entity
163
- inst = cls(_dict=_json)
164
- # Platform
165
- inst._project = project
166
- inst._client_api = client_api
167
- inst.is_fetched = is_fetched
168
-
169
- return inst
170
-
171
- def to_json(self):
172
- """
173
- Turn Package entity into a platform representation of Package
174
-
175
- :return: platform json of package
176
- :rtype: dict
177
- """
178
- _json = self._dict.copy()
179
- return _json
180
-
181
- ############
182
- # entities #
183
- ############
184
- @property
185
- def project(self):
186
- if self._project is None:
187
- self._project = self.projects.get(project_id=self.project_id, fetch=None)
188
- assert isinstance(self._project, entities.Project)
189
- return self._project
190
-
191
- @project.setter
192
- def project(self, project):
193
- assert isinstance(self._project, entities.Project), "Unknwon 'project' type: {}".format(type(project))
194
- self._project = project
195
-
196
- ################
197
- # repositories #
198
- ################
199
- @property
200
- def _repositories(self):
201
- if self.__repositories is None:
202
- reps = namedtuple('repositories',
203
- field_names=['executions', 'services', 'projects', 'packages', 'artifacts', 'codebases',
204
- 'models'])
205
-
206
- self.__repositories = reps(
207
- executions=repositories.Executions(client_api=self._client_api,
208
- project=self._project),
209
- services=repositories.Services(client_api=self._client_api,
210
- package=self,
211
- project=self._project,
212
- project_id=self.project_id),
213
- projects=repositories.Projects(client_api=self._client_api),
214
- packages=repositories.Packages(client_api=self._client_api,
215
- project=self._project),
216
- artifacts=repositories.Artifacts(client_api=self._client_api,
217
- project=self._project,
218
- project_id=self.project_id,
219
- package=self),
220
- codebases=repositories.Codebases(client_api=self._client_api, project=self._project,
221
- project_id=self.project_id),
222
- models=repositories.Models(client_api=self._client_api,
223
- project=self._project,
224
- package=self,
225
- project_id=self.project_id)
226
- )
227
- return self.__repositories
228
-
229
- @property
230
- def executions(self):
231
- assert isinstance(self._repositories.executions, repositories.Executions)
232
- return self._repositories.executions
233
-
234
- @property
235
- def services(self):
236
- assert isinstance(self._repositories.services, repositories.Services)
237
- return self._repositories.services
238
-
239
- @property
240
- def projects(self):
241
- assert isinstance(self._repositories.projects, repositories.Projects)
242
- return self._repositories.projects
243
-
244
- @property
245
- def packages(self):
246
- assert isinstance(self._repositories.packages, repositories.Packages)
247
- return self._repositories.packages
248
-
249
- @property
250
- def codebases(self):
251
- assert isinstance(self._repositories.codebases, repositories.Codebases)
252
- return self._repositories.codebases
253
-
254
- @property
255
- def artifacts(self):
256
- assert isinstance(self._repositories.artifacts, repositories.Artifacts)
257
- return self._repositories.artifacts
258
-
259
- @property
260
- def models(self):
261
- assert isinstance(self._repositories.models, repositories.Models)
262
- return self._repositories.models
263
-
264
- ##############
265
- # properties #
266
- ##############
267
- @property
268
- def git_status(self):
269
- status = 'Git status unavailable'
270
- try:
271
- if self.codebase.type == entities.PackageCodebaseType.ITEM:
272
- if 'git' in self.codebase.item.metadata:
273
- status = self.codebase.item.metadata['git'].get('status', status)
274
- except Exception:
275
- logging.debug('Error getting codebase')
276
- return status
277
-
278
- @property
279
- def git_log(self):
280
- log = 'Git log unavailable'
281
- try:
282
- if self.codebase.type == entities.PackageCodebaseType.ITEM:
283
- if 'git' in self.codebase.item.metadata:
284
- log = self.codebase.item.metadata['git'].get('log', log)
285
- except Exception:
286
- logging.debug('Error getting codebase')
287
- return log
288
-
289
- ###########
290
- # methods #
291
- ###########
292
- def update(self):
293
- """
294
- Update Package changes to platform
295
-
296
- :return: Package entity
297
- """
298
- return self.packages.update(package=self)
299
-
300
- def deploy(self,
301
- service_name=None,
302
- revision=None,
303
- init_input=None,
304
- runtime=None,
305
- sdk_version=None,
306
- agent_versions=None,
307
- verify=True,
308
- bot=None,
309
- pod_type=None,
310
- module_name=None,
311
- run_execution_as_process=None,
312
- execution_timeout=None,
313
- drain_time=None,
314
- on_reset=None,
315
- max_attempts=None,
316
- force=False,
317
- secrets: list = None,
318
- **kwargs):
319
- """
320
- Deploy package
321
-
322
- :param str service_name: service name
323
- :param str revision: package revision - default=latest
324
- :param init_input: config to run at startup
325
- :param dict runtime: runtime resources
326
- :param str sdk_version: - optional - string - sdk version
327
- :param dict agent_versions: - dictionary - - optional -versions of sdk, agent runner and agent proxy
328
- :param str bot: bot email
329
- :param str pod_type: pod type dl.InstanceCatalog
330
- :param bool verify: verify the inputs
331
- :param str module_name: module name
332
- :param bool run_execution_as_process: run execution as process
333
- :param int execution_timeout: execution timeout
334
- :param int drain_time: drain time
335
- :param str on_reset: on reset
336
- :param int max_attempts: Maximum execution retries in-case of a service reset
337
- :param bool force: optional - terminate old replicas immediately
338
- :param list secrets: list of the integrations ids
339
- :return: Service object
340
- :rtype: dtlpy.entities.service.Service
341
-
342
- **Example**:
343
-
344
- .. code-block:: python
345
- service: dl.Service = package.deploy(service_name=package_name,
346
- execution_timeout=3 * 60 * 60,
347
- module_name=module.name,
348
- runtime=dl.KubernetesRuntime(
349
- concurrency=10,
350
- pod_type=dl.InstanceCatalog.REGULAR_S,
351
- autoscaler=dl.KubernetesRabbitmqAutoscaler(
352
- min_replicas=1,
353
- max_replicas=20,
354
- queue_length=20
355
- )
356
- )
357
- )
358
-
359
- """
360
- return self.project.packages.deploy(package=self,
361
- service_name=service_name,
362
- project_id=self.project_id,
363
- revision=revision,
364
- init_input=init_input,
365
- runtime=runtime,
366
- sdk_version=sdk_version,
367
- agent_versions=agent_versions,
368
- pod_type=pod_type,
369
- bot=bot,
370
- verify=verify,
371
- module_name=module_name,
372
- run_execution_as_process=run_execution_as_process,
373
- execution_timeout=execution_timeout,
374
- drain_time=drain_time,
375
- on_reset=on_reset,
376
- max_attempts=max_attempts,
377
- force=force,
378
- jwt_forward=kwargs.get('jwt_forward', None),
379
- is_global=kwargs.get('is_global', None),
380
- secrets=secrets)
381
-
382
- def checkout(self):
383
- """
384
- Checkout as package
385
-
386
- :return:
387
- """
388
- return self.packages.checkout(package=self)
389
-
390
- def delete(self) -> bool:
391
- """
392
- Delete Package object
393
-
394
- :return: True
395
- """
396
- return self.packages.delete(package=self)
397
-
398
- def push(self,
399
- codebase: Union[entities.GitCodebase, entities.ItemCodebase] = None,
400
- src_path: str = None,
401
- package_name: str = None,
402
- modules: list = None,
403
- checkout: bool = False,
404
- revision_increment: str = None,
405
- service_update: bool = False,
406
- service_config: dict = None,
407
- package_type='faas'
408
- ):
409
- """
410
- Push local package
411
-
412
- :param dtlpy.entities.codebase.Codebase codebase: PackageCode object - defines how to store the package code
413
- :param bool checkout: save package to local checkout
414
- :param str src_path: location of pacjage codebase folder to zip
415
- :param str package_name: name of package
416
- :param list modules: list of PackageModule
417
- :param str revision_increment: optional - str - version bumping method - major/minor/patch - default = None
418
- :param bool service_update: optional - bool - update the service
419
- :param dict service_config : Service object as dict. Contains the spec of the default service to create.
420
- :param str package_type: default is "faas", one of "app", "ml"
421
- :return: package entity
422
- :rtype: dtlpy.entities.package.Package
423
-
424
- **Example**:
425
-
426
- .. code-block:: python
427
-
428
- package = packages.push(package_name='package_name',
429
- modules=[module],
430
- version='1.0.0',
431
- src_path=os.getcwd())
432
- """
433
- return self.project.packages.push(
434
- package_name=package_name if package_name is not None else self.name,
435
- modules=modules if modules is not None else self.modules,
436
- revision_increment=revision_increment,
437
- codebase=codebase,
438
- src_path=src_path,
439
- checkout=checkout,
440
- service_update=service_update,
441
- service_config=service_config,
442
- package_type=package_type
443
- )
444
-
445
- def pull(self, version=None, local_path=None) -> str:
446
- """
447
- Pull local package
448
-
449
- :param str version: version
450
- :param str local_path: local path
451
-
452
- **Example**:
453
-
454
- .. code-block:: python
455
-
456
- path = package.pull(local_path='local_path')
457
- """
458
- return self.packages.pull(package=self,
459
- version=version,
460
- local_path=local_path)
461
-
462
- def build(self, module_name=None, init_inputs=None, local_path=None, from_local=None):
463
- """
464
- Instantiate a module from the package code. Returns a loaded instance of the runner class
465
-
466
- :param module_name: Name of the module to build the runner class
467
- :param str init_inputs: dictionary of the class init variables (if exists). will be used to init the module class
468
- :param str local_path: local path of the package (if from_local=False - codebase will be downloaded)
469
- :param bool from_local: bool. if true - codebase will not be downloaded (only use local files)
470
- :return: dl.BaseServiceRunner
471
- """
472
- return self.packages.build(package=self,
473
- module_name=module_name,
474
- local_path=local_path,
475
- init_inputs=init_inputs,
476
- from_local=from_local)
477
-
478
- def open_in_web(self):
479
- """
480
- Open the package in web platform
481
-
482
- """
483
- url = self._client_api._get_resource_url(
484
- f"projects/{self.project.id}/faas?byCreator=false&byProject=true&byDataloop=false&tab=library&name={self.name}")
485
- self._client_api._open_in_web(url=url)
486
-
487
- def test(self,
488
- cwd=None,
489
- concurrency=None,
490
- module_name=entities.package_defaults.DEFAULT_PACKAGE_MODULE_NAME,
491
- function_name=entities.package_defaults.DEFAULT_PACKAGE_FUNCTION_NAME,
492
- class_name=entities.package_defaults.DEFAULT_PACKAGE_CLASS_NAME,
493
- entry_point=entities.package_defaults.DEFAULT_PACKAGE_ENTRY_POINT
494
- ):
495
- """
496
- Test local package in local environment.
497
-
498
- :param str cwd: path to the file
499
- :param int concurrency: the concurrency of the test
500
- :param str module_name: module name
501
- :param str function_name: function name
502
- :param str class_name: class name
503
- :param str entry_point: the file to run like main.py
504
- :return: list created by the function that tested the output
505
- :rtype: list
506
-
507
- **Example**:
508
-
509
- .. code-block:: python
510
-
511
- package.test(cwd='path_to_package',
512
- function_name='run')
513
- """
514
- return self.project.packages.test_local_package(
515
- cwd=cwd,
516
- concurrency=concurrency,
517
- package=self,
518
- module_name=module_name,
519
- function_name=function_name,
520
- class_name=class_name,
521
- entry_point=entry_point
522
- )
523
-
524
- @staticmethod
525
- def _mockify_input(input_type):
526
- _json = dict()
527
- if input_type == 'Dataset':
528
- _json.update({'dataset_id': 'id'})
529
- if input_type == 'Item':
530
- _json.update({'item_id': 'id', 'dataset_id': 'id'})
531
- if input_type == 'Annotation':
532
- _json.update({'annotation_id': 'id', 'item_id': 'id', 'dataset_id': 'id'})
533
- return _json
534
-
535
- def mockify(self, local_path=None, module_name=None, function_name=None):
536
- if local_path is None:
537
- local_path = os.getcwd()
538
-
539
- if module_name is None:
540
- if self.modules:
541
- module_name = self.modules[0].name
542
- else:
543
- raise exceptions.PlatformException('400', 'Package has no modules')
544
-
545
- modules = [module for module in self.modules if module.name == module_name]
546
- if not modules:
547
- raise exceptions.PlatformException('404', 'Module not found: {}'.format(module_name))
548
- module = modules[0]
549
-
550
- if function_name is None:
551
- funcs = [func for func in module.functions]
552
- if funcs:
553
- func = funcs[0]
554
- else:
555
- raise exceptions.PlatformException('400', 'Module: {} has no functions'.format(module_name))
556
- else:
557
- funcs = [func for func in module.functions if func.name == function_name]
558
- if not funcs:
559
- raise exceptions.PlatformException('404', 'Function not found: {}'.format(function_name))
560
- func = funcs[0]
561
-
562
- mock = dict()
563
- for module in self.modules:
564
- mock['module_name'] = module.name
565
- mock['function_name'] = func.name
566
- mock['init_params'] = {inpt.name: self._mockify_input(input_type=inpt.type) for inpt in module.init_inputs}
567
- mock['inputs'] = [{'name': inpt.name, 'value': self._mockify_input(input_type=inpt.type)} for inpt in
568
- func.inputs]
569
-
570
- with open(os.path.join(local_path, 'mock.json'), 'w') as f:
571
- json.dump(mock, f)
572
-
573
- @staticmethod
574
- def get_ml_metadata(cls=None,
575
- available_methods=None,
576
- output_type=entities.AnnotationType.CLASSIFICATION,
577
- input_type='image',
578
- default_configuration: dict = None):
579
- """
580
- Create ML metadata for the package
581
- :param cls: ModelAdapter class, to get the list of available_methods
582
- :param available_methods: available user function on the adapter. ['load', 'save', 'predict', 'train']
583
- :param output_type: annotation type the model create, e.g. dl.AnnotationType.CLASSIFICATION
584
- :param input_type: input file type the model gets, one of ['image', 'video', 'txt']
585
- :param default_configuration: default service configuration for the deployed services
586
- :return:
587
- """
588
- user_implemented_methods = ['load', 'save', 'predict', 'train']
589
- if available_methods is None:
590
- # default
591
- available_methods = user_implemented_methods
592
-
593
- if cls is not None:
594
- # TODO dont check if function is on the adapter - check if the functions is implemented (not raise NotImplemented)
595
- available_methods = [
596
- {name: 'BaseModelAdapter' not in getattr(cls, name).__qualname__}
597
- for name in user_implemented_methods
598
- ]
599
- if default_configuration is None:
600
- default_configuration = dict()
601
- metadata = {
602
- 'system': {'ml': {'defaultConfiguration': default_configuration,
603
- 'outputType': output_type,
604
- 'inputType': input_type,
605
- 'supportedMethods': available_methods
606
- }}}
607
- return metadata
608
-
609
- class decorators:
610
- @staticmethod
611
- def module(name='default-module', description='', init_inputs=None):
612
- def wrapper(cls: typing.Callable):
613
- # package_module_dict = package_module.to_json()
614
- package_module_dict = {"name": name,
615
- "description": description,
616
- "functions": list(),
617
- "className": cls.__name__}
618
- if init_inputs is not None:
619
- package_module_dict.update(initInputs=Package.decorators.parse_io(io_list=init_inputs))
620
- for member_name, member in inspect.getmembers(cls, predicate=inspect.isfunction):
621
- spec = getattr(member, '__dtlpy__', None)
622
- if spec is not None:
623
- package_module_dict["functions"].append(spec)
624
- cls.__dtlpy__ = package_module_dict
625
- return cls
626
-
627
- return wrapper
628
-
629
- @staticmethod
630
- def function(display_name=None, inputs=None, outputs=None):
631
- def wrapper(func: typing.Callable):
632
- if display_name is None:
633
- d_name = func.__name__
634
- else:
635
- d_name = display_name
636
- func.__dtlpy__ = {"name": func.__name__,
637
- "displayName": d_name,
638
- "input": Package.decorators.parse_io(io_list=inputs),
639
- "output": Package.decorators.parse_io(io_list=outputs)}
640
- return func
641
-
642
- return wrapper
643
-
644
- @staticmethod
645
- def parse_io(io_list: dict):
646
- output = list()
647
- if io_list is not None:
648
- for io_name, io_type in io_list.items():
649
- if isinstance(io_type, Enum):
650
- io_type = io_type.name
651
- if isinstance(io_type, type):
652
- io_type = io_type.__name__
653
- else:
654
- io_type = str(io_type)
655
- output.append({"name": io_name,
656
- "type": str(io_type)})
657
- return output
1
+ from collections import namedtuple
2
+ from typing import Union
3
+ from enum import Enum
4
+ import traceback
5
+ import logging
6
+ import inspect
7
+ import typing
8
+ import json
9
+ import os
10
+
11
+ from .package_module import PackageModule
12
+ from .package_slot import PackageSlot
13
+ from .. import repositories, entities, exceptions
14
+ from ..services.api_client import ApiClient
15
+
16
+ logger = logging.getLogger(name='dtlpy')
17
+
18
+
19
+ class RequirementOperator(str, Enum):
20
+ EQUAL = '==',
21
+ GREATER_THAN = '>',
22
+ LESS_THAN = '<',
23
+ EQUAL_OR_LESS_THAN = '<=',
24
+ EQUAL_OR_GREATER_THAN = '>='
25
+
26
+ @staticmethod
27
+ def keys():
28
+ return [key.value for key in list(RequirementOperator)]
29
+
30
+
31
+ class PackageRequirement:
32
+
33
+ def __init__(self, name: str, version: str = None, operator: str = None):
34
+ self.name = name
35
+ self.version = version
36
+
37
+ valid_operators = RequirementOperator.keys()
38
+ if operator is not None and operator not in valid_operators:
39
+ raise Exception('Illegal operator: {}. Please select from: {}'.format(operator, valid_operators))
40
+
41
+ self.operator = operator
42
+
43
+ def to_json(self):
44
+ _json = {'name': self.name}
45
+ if self.version is not None:
46
+ _json['version'] = self.version
47
+ if self.operator is not None:
48
+ _json['operator'] = self.operator
49
+ return _json
50
+
51
+ @classmethod
52
+ def from_json(cls, _json: dict):
53
+ return cls(**_json)
54
+
55
+
56
+ class Package(entities.DlEntity):
57
+ """
58
+ Package object
59
+ """
60
+ # platform
61
+ id: str = entities.DlProperty(location=['id'], _type=str)
62
+ url: str = entities.DlProperty(location=['url'], _type=str)
63
+ name: str = entities.DlProperty(location=['name'], _type=str)
64
+ version: str = entities.DlProperty(location=['version'], _type=str)
65
+ created_at: str = entities.DlProperty(location=['createdAt'], _type=str)
66
+ updated_at: str = entities.DlProperty(location=['updatedAt'], _type=str)
67
+ project_id: str = entities.DlProperty(location=['projectId'], _type=str)
68
+ creator: str = entities.DlProperty(location=['creator'], _type=str)
69
+ type: str = entities.DlProperty(location=['type'], _type=str)
70
+ metadata: dict = entities.DlProperty(location=['metadata'], _type=dict)
71
+ ui_hooks: list = entities.DlProperty(location=['uiHooks'], _type=str)
72
+ service_config: dict = entities.DlProperty(location=['serviceConfig'], _type=str)
73
+ is_global: bool = entities.DlProperty(location=['global'], _type=str)
74
+
75
+ codebase: typing.Any = entities.DlProperty(location=['codebase'], _kls='Codebase')
76
+ modules: typing.List[PackageModule] = entities.DlProperty(location=['modules'], _kls='PackageModule')
77
+ slots: typing.Union[typing.List[PackageSlot], None] = entities.DlProperty(location=['slots'],
78
+ _kls='PackageSlot')
79
+ requirements: typing.Union[typing.List[PackageRequirement], None] = entities.DlProperty(location=['requirements'],
80
+ _kls='PackageRequirement')
81
+
82
+ # sdk
83
+ _client_api: ApiClient
84
+ _revisions = None
85
+ __repositories = None
86
+ _project = None
87
+
88
+ def __repr__(self):
89
+ # TODO need to move to DlEntity
90
+ return "Package(id={id}, name={name}, creator={creator}, project_id={project_id}, type={type}, version={version})".format(
91
+ id=self.id,
92
+ name=self.name,
93
+ version=self.version,
94
+ type=self.type,
95
+ project_id=self.project_id,
96
+ creator=self.creator)
97
+
98
+ @property
99
+ def createdAt(self):
100
+ return self.created_at
101
+
102
+ @property
103
+ def updatedAt(self):
104
+ return self.updated_at
105
+
106
+ @property
107
+ def revisions(self):
108
+ if self._revisions is None:
109
+ self._revisions = self.packages.revisions(package=self)
110
+ return self._revisions
111
+
112
+ @property
113
+ def platform_url(self):
114
+ return self._client_api._get_resource_url("projects/{}/packages/{}/main".format(self.project.id, self.id))
115
+
116
+ @property
117
+ def codebase_id(self):
118
+ if self.codebase is not None and self.codebase.type == entities.PackageCodebaseType.ITEM:
119
+ return self.codebase.item_id
120
+ return None
121
+
122
+ @codebase_id.setter
123
+ def codebase_id(self, item_id: str):
124
+ self.codebase = entities.ItemCodebase(item_id=item_id)
125
+
126
+ @staticmethod
127
+ def _protected_from_json(_json, client_api, project=None, is_fetched=True):
128
+ """
129
+ Same as from_json but with try-except to catch if error
130
+
131
+ :param _json: platform json
132
+ :param client_api: ApiClient entity
133
+ :return:
134
+ """
135
+ try:
136
+ package = Package.from_json(_json=_json,
137
+ client_api=client_api,
138
+ project=project,
139
+ is_fetched=is_fetched)
140
+ status = True
141
+ except Exception:
142
+ package = traceback.format_exc()
143
+ status = False
144
+ return status, package
145
+
146
+ @classmethod
147
+ def from_json(cls, _json, client_api, project=None, is_fetched=True):
148
+ """
149
+ Turn platform representation of package into a package entity
150
+
151
+ :param dict _json: platform representation of package
152
+ :param dl.ApiClient client_api: ApiClient entity
153
+ :param dtlpy.entities.project.Project project: project entity
154
+ :param is_fetched: is Entity fetched from Platform
155
+ :return: Package entity
156
+ :rtype: dtlpy.entities.package.Package
157
+ """
158
+ if project is not None:
159
+ if project.id != _json.get('projectId', None):
160
+ logger.warning('Package has been fetched from a project that is not belong to it')
161
+ project = None
162
+ # Entity
163
+ inst = cls(_dict=_json)
164
+ # Platform
165
+ inst._project = project
166
+ inst._client_api = client_api
167
+ inst.is_fetched = is_fetched
168
+
169
+ return inst
170
+
171
+ def to_json(self):
172
+ """
173
+ Turn Package entity into a platform representation of Package
174
+
175
+ :return: platform json of package
176
+ :rtype: dict
177
+ """
178
+ _json = self._dict.copy()
179
+ return _json
180
+
181
+ ############
182
+ # entities #
183
+ ############
184
+ @property
185
+ def project(self):
186
+ if self._project is None:
187
+ self._project = self.projects.get(project_id=self.project_id, fetch=None)
188
+ assert isinstance(self._project, entities.Project)
189
+ return self._project
190
+
191
+ @project.setter
192
+ def project(self, project):
193
+ assert isinstance(self._project, entities.Project), "Unknwon 'project' type: {}".format(type(project))
194
+ self._project = project
195
+
196
+ ################
197
+ # repositories #
198
+ ################
199
+ @property
200
+ def _repositories(self):
201
+ if self.__repositories is None:
202
+ reps = namedtuple('repositories',
203
+ field_names=['executions', 'services', 'projects', 'packages', 'artifacts', 'codebases',
204
+ 'models'])
205
+
206
+ self.__repositories = reps(
207
+ executions=repositories.Executions(client_api=self._client_api,
208
+ project=self._project),
209
+ services=repositories.Services(client_api=self._client_api,
210
+ package=self,
211
+ project=self._project,
212
+ project_id=self.project_id),
213
+ projects=repositories.Projects(client_api=self._client_api),
214
+ packages=repositories.Packages(client_api=self._client_api,
215
+ project=self._project),
216
+ artifacts=repositories.Artifacts(client_api=self._client_api,
217
+ project=self._project,
218
+ project_id=self.project_id,
219
+ package=self),
220
+ codebases=repositories.Codebases(client_api=self._client_api, project=self._project,
221
+ project_id=self.project_id),
222
+ models=repositories.Models(client_api=self._client_api,
223
+ project=self._project,
224
+ package=self,
225
+ project_id=self.project_id)
226
+ )
227
+ return self.__repositories
228
+
229
+ @property
230
+ def executions(self):
231
+ assert isinstance(self._repositories.executions, repositories.Executions)
232
+ return self._repositories.executions
233
+
234
+ @property
235
+ def services(self):
236
+ assert isinstance(self._repositories.services, repositories.Services)
237
+ return self._repositories.services
238
+
239
+ @property
240
+ def projects(self):
241
+ assert isinstance(self._repositories.projects, repositories.Projects)
242
+ return self._repositories.projects
243
+
244
+ @property
245
+ def packages(self):
246
+ assert isinstance(self._repositories.packages, repositories.Packages)
247
+ return self._repositories.packages
248
+
249
+ @property
250
+ def codebases(self):
251
+ assert isinstance(self._repositories.codebases, repositories.Codebases)
252
+ return self._repositories.codebases
253
+
254
+ @property
255
+ def artifacts(self):
256
+ assert isinstance(self._repositories.artifacts, repositories.Artifacts)
257
+ return self._repositories.artifacts
258
+
259
+ @property
260
+ def models(self):
261
+ assert isinstance(self._repositories.models, repositories.Models)
262
+ return self._repositories.models
263
+
264
+ ##############
265
+ # properties #
266
+ ##############
267
+ @property
268
+ def git_status(self):
269
+ status = 'Git status unavailable'
270
+ try:
271
+ if self.codebase.type == entities.PackageCodebaseType.ITEM:
272
+ if 'git' in self.codebase.item.metadata:
273
+ status = self.codebase.item.metadata['git'].get('status', status)
274
+ except Exception:
275
+ logging.debug('Error getting codebase')
276
+ return status
277
+
278
+ @property
279
+ def git_log(self):
280
+ log = 'Git log unavailable'
281
+ try:
282
+ if self.codebase.type == entities.PackageCodebaseType.ITEM:
283
+ if 'git' in self.codebase.item.metadata:
284
+ log = self.codebase.item.metadata['git'].get('log', log)
285
+ except Exception:
286
+ logging.debug('Error getting codebase')
287
+ return log
288
+
289
+ ###########
290
+ # methods #
291
+ ###########
292
+ def update(self):
293
+ """
294
+ Update Package changes to platform
295
+
296
+ :return: Package entity
297
+ """
298
+ return self.packages.update(package=self)
299
+
300
+ def deploy(self,
301
+ service_name=None,
302
+ revision=None,
303
+ init_input=None,
304
+ runtime=None,
305
+ sdk_version=None,
306
+ agent_versions=None,
307
+ verify=True,
308
+ bot=None,
309
+ pod_type=None,
310
+ module_name=None,
311
+ run_execution_as_process=None,
312
+ execution_timeout=None,
313
+ drain_time=None,
314
+ on_reset=None,
315
+ max_attempts=None,
316
+ force=False,
317
+ secrets: list = None,
318
+ **kwargs):
319
+ """
320
+ Deploy package
321
+
322
+ :param str service_name: service name
323
+ :param str revision: package revision - default=latest
324
+ :param init_input: config to run at startup
325
+ :param dict runtime: runtime resources
326
+ :param str sdk_version: - optional - string - sdk version
327
+ :param dict agent_versions: - dictionary - - optional -versions of sdk, agent runner and agent proxy
328
+ :param str bot: bot email
329
+ :param str pod_type: pod type dl.InstanceCatalog
330
+ :param bool verify: verify the inputs
331
+ :param str module_name: module name
332
+ :param bool run_execution_as_process: run execution as process
333
+ :param int execution_timeout: execution timeout
334
+ :param int drain_time: drain time
335
+ :param str on_reset: on reset
336
+ :param int max_attempts: Maximum execution retries in-case of a service reset
337
+ :param bool force: optional - terminate old replicas immediately
338
+ :param list secrets: list of the integrations ids
339
+ :return: Service object
340
+ :rtype: dtlpy.entities.service.Service
341
+
342
+ **Example**:
343
+
344
+ .. code-block:: python
345
+ service: dl.Service = package.deploy(service_name=package_name,
346
+ execution_timeout=3 * 60 * 60,
347
+ module_name=module.name,
348
+ runtime=dl.KubernetesRuntime(
349
+ concurrency=10,
350
+ pod_type=dl.InstanceCatalog.REGULAR_S,
351
+ autoscaler=dl.KubernetesRabbitmqAutoscaler(
352
+ min_replicas=1,
353
+ max_replicas=20,
354
+ queue_length=20
355
+ )
356
+ )
357
+ )
358
+
359
+ """
360
+ return self.project.packages.deploy(package=self,
361
+ service_name=service_name,
362
+ project_id=self.project_id,
363
+ revision=revision,
364
+ init_input=init_input,
365
+ runtime=runtime,
366
+ sdk_version=sdk_version,
367
+ agent_versions=agent_versions,
368
+ pod_type=pod_type,
369
+ bot=bot,
370
+ verify=verify,
371
+ module_name=module_name,
372
+ run_execution_as_process=run_execution_as_process,
373
+ execution_timeout=execution_timeout,
374
+ drain_time=drain_time,
375
+ on_reset=on_reset,
376
+ max_attempts=max_attempts,
377
+ force=force,
378
+ jwt_forward=kwargs.get('jwt_forward', None),
379
+ is_global=kwargs.get('is_global', None),
380
+ secrets=secrets)
381
+
382
+ def checkout(self):
383
+ """
384
+ Checkout as package
385
+
386
+ :return:
387
+ """
388
+ return self.packages.checkout(package=self)
389
+
390
+ def delete(self) -> bool:
391
+ """
392
+ Delete Package object
393
+
394
+ :return: True
395
+ """
396
+ return self.packages.delete(package=self)
397
+
398
+ def push(self,
399
+ codebase: Union[entities.GitCodebase, entities.ItemCodebase] = None,
400
+ src_path: str = None,
401
+ package_name: str = None,
402
+ modules: list = None,
403
+ checkout: bool = False,
404
+ revision_increment: str = None,
405
+ service_update: bool = False,
406
+ service_config: dict = None,
407
+ package_type='faas'
408
+ ):
409
+ """
410
+ Push local package
411
+
412
+ :param dtlpy.entities.codebase.Codebase codebase: PackageCode object - defines how to store the package code
413
+ :param bool checkout: save package to local checkout
414
+ :param str src_path: location of pacjage codebase folder to zip
415
+ :param str package_name: name of package
416
+ :param list modules: list of PackageModule
417
+ :param str revision_increment: optional - str - version bumping method - major/minor/patch - default = None
418
+ :param bool service_update: optional - bool - update the service
419
+ :param dict service_config : Service object as dict. Contains the spec of the default service to create.
420
+ :param str package_type: default is "faas", one of "app", "ml"
421
+ :return: package entity
422
+ :rtype: dtlpy.entities.package.Package
423
+
424
+ **Example**:
425
+
426
+ .. code-block:: python
427
+
428
+ package = packages.push(package_name='package_name',
429
+ modules=[module],
430
+ version='1.0.0',
431
+ src_path=os.getcwd())
432
+ """
433
+ return self.project.packages.push(
434
+ package_name=package_name if package_name is not None else self.name,
435
+ modules=modules if modules is not None else self.modules,
436
+ revision_increment=revision_increment,
437
+ codebase=codebase,
438
+ src_path=src_path,
439
+ checkout=checkout,
440
+ service_update=service_update,
441
+ service_config=service_config,
442
+ package_type=package_type
443
+ )
444
+
445
+ def pull(self, version=None, local_path=None) -> str:
446
+ """
447
+ Pull local package
448
+
449
+ :param str version: version
450
+ :param str local_path: local path
451
+
452
+ **Example**:
453
+
454
+ .. code-block:: python
455
+
456
+ path = package.pull(local_path='local_path')
457
+ """
458
+ return self.packages.pull(package=self,
459
+ version=version,
460
+ local_path=local_path)
461
+
462
+ def build(self, module_name=None, init_inputs=None, local_path=None, from_local=None):
463
+ """
464
+ Instantiate a module from the package code. Returns a loaded instance of the runner class
465
+
466
+ :param module_name: Name of the module to build the runner class
467
+ :param str init_inputs: dictionary of the class init variables (if exists). will be used to init the module class
468
+ :param str local_path: local path of the package (if from_local=False - codebase will be downloaded)
469
+ :param bool from_local: bool. if true - codebase will not be downloaded (only use local files)
470
+ :return: dl.BaseServiceRunner
471
+ """
472
+ return self.packages.build(package=self,
473
+ module_name=module_name,
474
+ local_path=local_path,
475
+ init_inputs=init_inputs,
476
+ from_local=from_local)
477
+
478
+ def open_in_web(self):
479
+ """
480
+ Open the package in web platform
481
+
482
+ """
483
+ url = self._client_api._get_resource_url(
484
+ f"projects/{self.project.id}/faas?byCreator=false&byProject=true&byDataloop=false&tab=library&name={self.name}")
485
+ self._client_api._open_in_web(url=url)
486
+
487
+ def test(self,
488
+ cwd=None,
489
+ concurrency=None,
490
+ module_name=entities.package_defaults.DEFAULT_PACKAGE_MODULE_NAME,
491
+ function_name=entities.package_defaults.DEFAULT_PACKAGE_FUNCTION_NAME,
492
+ class_name=entities.package_defaults.DEFAULT_PACKAGE_CLASS_NAME,
493
+ entry_point=entities.package_defaults.DEFAULT_PACKAGE_ENTRY_POINT
494
+ ):
495
+ """
496
+ Test local package in local environment.
497
+
498
+ :param str cwd: path to the file
499
+ :param int concurrency: the concurrency of the test
500
+ :param str module_name: module name
501
+ :param str function_name: function name
502
+ :param str class_name: class name
503
+ :param str entry_point: the file to run like main.py
504
+ :return: list created by the function that tested the output
505
+ :rtype: list
506
+
507
+ **Example**:
508
+
509
+ .. code-block:: python
510
+
511
+ package.test(cwd='path_to_package',
512
+ function_name='run')
513
+ """
514
+ return self.project.packages.test_local_package(
515
+ cwd=cwd,
516
+ concurrency=concurrency,
517
+ package=self,
518
+ module_name=module_name,
519
+ function_name=function_name,
520
+ class_name=class_name,
521
+ entry_point=entry_point
522
+ )
523
+
524
+ @staticmethod
525
+ def _mockify_input(input_type):
526
+ _json = dict()
527
+ if input_type == 'Dataset':
528
+ _json.update({'dataset_id': 'id'})
529
+ if input_type == 'Item':
530
+ _json.update({'item_id': 'id', 'dataset_id': 'id'})
531
+ if input_type == 'Annotation':
532
+ _json.update({'annotation_id': 'id', 'item_id': 'id', 'dataset_id': 'id'})
533
+ return _json
534
+
535
+ def mockify(self, local_path=None, module_name=None, function_name=None):
536
+ if local_path is None:
537
+ local_path = os.getcwd()
538
+
539
+ if module_name is None:
540
+ if self.modules:
541
+ module_name = self.modules[0].name
542
+ else:
543
+ raise exceptions.PlatformException('400', 'Package has no modules')
544
+
545
+ modules = [module for module in self.modules if module.name == module_name]
546
+ if not modules:
547
+ raise exceptions.PlatformException('404', 'Module not found: {}'.format(module_name))
548
+ module = modules[0]
549
+
550
+ if function_name is None:
551
+ funcs = [func for func in module.functions]
552
+ if funcs:
553
+ func = funcs[0]
554
+ else:
555
+ raise exceptions.PlatformException('400', 'Module: {} has no functions'.format(module_name))
556
+ else:
557
+ funcs = [func for func in module.functions if func.name == function_name]
558
+ if not funcs:
559
+ raise exceptions.PlatformException('404', 'Function not found: {}'.format(function_name))
560
+ func = funcs[0]
561
+
562
+ mock = dict()
563
+ for module in self.modules:
564
+ mock['module_name'] = module.name
565
+ mock['function_name'] = func.name
566
+ mock['init_params'] = {inpt.name: self._mockify_input(input_type=inpt.type) for inpt in module.init_inputs}
567
+ mock['inputs'] = [{'name': inpt.name, 'value': self._mockify_input(input_type=inpt.type)} for inpt in
568
+ func.inputs]
569
+
570
+ with open(os.path.join(local_path, 'mock.json'), 'w') as f:
571
+ json.dump(mock, f)
572
+
573
+ @staticmethod
574
+ def get_ml_metadata(cls=None,
575
+ available_methods=None,
576
+ output_type=entities.AnnotationType.CLASSIFICATION,
577
+ input_type='image',
578
+ default_configuration: dict = None):
579
+ """
580
+ Create ML metadata for the package
581
+ :param cls: ModelAdapter class, to get the list of available_methods
582
+ :param available_methods: available user function on the adapter. ['load', 'save', 'predict', 'train']
583
+ :param output_type: annotation type the model create, e.g. dl.AnnotationType.CLASSIFICATION
584
+ :param input_type: input file type the model gets, one of ['image', 'video', 'txt']
585
+ :param default_configuration: default service configuration for the deployed services
586
+ :return:
587
+ """
588
+ user_implemented_methods = ['load', 'save', 'predict', 'train']
589
+ if available_methods is None:
590
+ # default
591
+ available_methods = user_implemented_methods
592
+
593
+ if cls is not None:
594
+ # TODO dont check if function is on the adapter - check if the functions is implemented (not raise NotImplemented)
595
+ available_methods = [
596
+ {name: 'BaseModelAdapter' not in getattr(cls, name).__qualname__}
597
+ for name in user_implemented_methods
598
+ ]
599
+ if default_configuration is None:
600
+ default_configuration = dict()
601
+ metadata = {
602
+ 'system': {'ml': {'defaultConfiguration': default_configuration,
603
+ 'outputType': output_type,
604
+ 'inputType': input_type,
605
+ 'supportedMethods': available_methods
606
+ }}}
607
+ return metadata
608
+
609
+ class decorators:
610
+ @staticmethod
611
+ def module(name='default-module', description='', init_inputs=None):
612
+ def wrapper(cls: typing.Callable):
613
+ # package_module_dict = package_module.to_json()
614
+ package_module_dict = {"name": name,
615
+ "description": description,
616
+ "functions": list(),
617
+ "className": cls.__name__}
618
+ if init_inputs is not None:
619
+ package_module_dict.update(initInputs=Package.decorators.parse_io(io_list=init_inputs))
620
+ for member_name, member in inspect.getmembers(cls, predicate=inspect.isfunction):
621
+ spec = getattr(member, '__dtlpy__', None)
622
+ if spec is not None:
623
+ package_module_dict["functions"].append(spec)
624
+ cls.__dtlpy__ = package_module_dict
625
+ return cls
626
+
627
+ return wrapper
628
+
629
+ @staticmethod
630
+ def function(display_name=None, inputs=None, outputs=None):
631
+ def wrapper(func: typing.Callable):
632
+ if display_name is None:
633
+ d_name = func.__name__
634
+ else:
635
+ d_name = display_name
636
+ func.__dtlpy__ = {"name": func.__name__,
637
+ "displayName": d_name,
638
+ "input": Package.decorators.parse_io(io_list=inputs),
639
+ "output": Package.decorators.parse_io(io_list=outputs)}
640
+ return func
641
+
642
+ return wrapper
643
+
644
+ @staticmethod
645
+ def parse_io(io_list: dict):
646
+ output = list()
647
+ if io_list is not None:
648
+ for io_name, io_type in io_list.items():
649
+ if isinstance(io_type, Enum):
650
+ io_type = io_type.name
651
+ if isinstance(io_type, type):
652
+ io_type = io_type.__name__
653
+ else:
654
+ io_type = str(io_type)
655
+ output.append({"name": io_name,
656
+ "type": str(io_type)})
657
+ return output