dtlpy 1.115.44__py3-none-any.whl → 1.116.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dtlpy/__init__.py +491 -491
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__init__.py +26 -26
- dtlpy/assets/code_server/config.yaml +2 -2
- dtlpy/assets/code_server/installation.sh +24 -24
- dtlpy/assets/code_server/launch.json +13 -13
- dtlpy/assets/code_server/settings.json +2 -2
- dtlpy/assets/main.py +53 -53
- dtlpy/assets/main_partial.py +18 -18
- dtlpy/assets/mock.json +11 -11
- dtlpy/assets/model_adapter.py +83 -83
- dtlpy/assets/package.json +61 -61
- dtlpy/assets/package_catalog.json +29 -29
- dtlpy/assets/package_gitignore +307 -307
- dtlpy/assets/service_runners/__init__.py +33 -33
- dtlpy/assets/service_runners/converter.py +96 -96
- dtlpy/assets/service_runners/multi_method.py +49 -49
- dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
- dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
- dtlpy/assets/service_runners/multi_method_item.py +52 -52
- dtlpy/assets/service_runners/multi_method_json.py +52 -52
- dtlpy/assets/service_runners/single_method.py +37 -37
- dtlpy/assets/service_runners/single_method_annotation.py +43 -43
- dtlpy/assets/service_runners/single_method_dataset.py +43 -43
- dtlpy/assets/service_runners/single_method_item.py +41 -41
- dtlpy/assets/service_runners/single_method_json.py +42 -42
- dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
- dtlpy/assets/voc_annotation_template.xml +23 -23
- dtlpy/caches/base_cache.py +32 -32
- dtlpy/caches/cache.py +473 -473
- dtlpy/caches/dl_cache.py +201 -201
- dtlpy/caches/filesystem_cache.py +89 -89
- dtlpy/caches/redis_cache.py +84 -84
- dtlpy/dlp/__init__.py +20 -20
- dtlpy/dlp/cli_utilities.py +367 -367
- dtlpy/dlp/command_executor.py +764 -764
- dtlpy/dlp/dlp +1 -1
- dtlpy/dlp/dlp.bat +1 -1
- dtlpy/dlp/dlp.py +128 -128
- dtlpy/dlp/parser.py +651 -651
- dtlpy/entities/__init__.py +83 -83
- dtlpy/entities/analytic.py +347 -347
- dtlpy/entities/annotation.py +1879 -1879
- dtlpy/entities/annotation_collection.py +699 -699
- dtlpy/entities/annotation_definitions/__init__.py +20 -20
- dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
- dtlpy/entities/annotation_definitions/box.py +195 -195
- dtlpy/entities/annotation_definitions/classification.py +67 -67
- dtlpy/entities/annotation_definitions/comparison.py +72 -72
- dtlpy/entities/annotation_definitions/cube.py +204 -204
- dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
- dtlpy/entities/annotation_definitions/description.py +32 -32
- dtlpy/entities/annotation_definitions/ellipse.py +124 -124
- dtlpy/entities/annotation_definitions/free_text.py +62 -62
- dtlpy/entities/annotation_definitions/gis.py +69 -69
- dtlpy/entities/annotation_definitions/note.py +139 -139
- dtlpy/entities/annotation_definitions/point.py +117 -117
- dtlpy/entities/annotation_definitions/polygon.py +182 -182
- dtlpy/entities/annotation_definitions/polyline.py +111 -111
- dtlpy/entities/annotation_definitions/pose.py +92 -92
- dtlpy/entities/annotation_definitions/ref_image.py +86 -86
- dtlpy/entities/annotation_definitions/segmentation.py +240 -240
- dtlpy/entities/annotation_definitions/subtitle.py +34 -34
- dtlpy/entities/annotation_definitions/text.py +85 -85
- dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
- dtlpy/entities/app.py +220 -220
- dtlpy/entities/app_module.py +107 -107
- dtlpy/entities/artifact.py +174 -174
- dtlpy/entities/assignment.py +399 -399
- dtlpy/entities/base_entity.py +214 -214
- dtlpy/entities/bot.py +113 -113
- dtlpy/entities/codebase.py +292 -292
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +449 -449
- dtlpy/entities/dataset.py +1299 -1299
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +235 -235
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +145 -145
- dtlpy/entities/filters.py +798 -798
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +959 -959
- dtlpy/entities/label.py +123 -123
- dtlpy/entities/links.py +85 -85
- dtlpy/entities/message.py +175 -175
- dtlpy/entities/model.py +684 -684
- dtlpy/entities/node.py +1005 -1005
- dtlpy/entities/ontology.py +810 -803
- dtlpy/entities/organization.py +287 -287
- dtlpy/entities/package.py +657 -657
- dtlpy/entities/package_defaults.py +5 -5
- dtlpy/entities/package_function.py +185 -185
- dtlpy/entities/package_module.py +113 -113
- dtlpy/entities/package_slot.py +118 -118
- dtlpy/entities/paged_entities.py +299 -299
- dtlpy/entities/pipeline.py +624 -624
- dtlpy/entities/pipeline_execution.py +279 -279
- dtlpy/entities/project.py +394 -394
- dtlpy/entities/prompt_item.py +505 -505
- dtlpy/entities/recipe.py +301 -301
- dtlpy/entities/reflect_dict.py +102 -102
- dtlpy/entities/resource_execution.py +138 -138
- dtlpy/entities/service.py +963 -963
- dtlpy/entities/service_driver.py +117 -117
- dtlpy/entities/setting.py +294 -294
- dtlpy/entities/task.py +495 -495
- dtlpy/entities/time_series.py +143 -143
- dtlpy/entities/trigger.py +426 -426
- dtlpy/entities/user.py +118 -118
- dtlpy/entities/webhook.py +124 -124
- dtlpy/examples/__init__.py +19 -19
- dtlpy/examples/add_labels.py +135 -135
- dtlpy/examples/add_metadata_to_item.py +21 -21
- dtlpy/examples/annotate_items_using_model.py +65 -65
- dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
- dtlpy/examples/annotations_convert_to_voc.py +9 -9
- dtlpy/examples/annotations_convert_to_yolo.py +9 -9
- dtlpy/examples/convert_annotation_types.py +51 -51
- dtlpy/examples/converter.py +143 -143
- dtlpy/examples/copy_annotations.py +22 -22
- dtlpy/examples/copy_folder.py +31 -31
- dtlpy/examples/create_annotations.py +51 -51
- dtlpy/examples/create_video_annotations.py +83 -83
- dtlpy/examples/delete_annotations.py +26 -26
- dtlpy/examples/filters.py +113 -113
- dtlpy/examples/move_item.py +23 -23
- dtlpy/examples/play_video_annotation.py +13 -13
- dtlpy/examples/show_item_and_mask.py +53 -53
- dtlpy/examples/triggers.py +49 -49
- dtlpy/examples/upload_batch_of_items.py +20 -20
- dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
- dtlpy/examples/upload_items_with_modalities.py +43 -43
- dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
- dtlpy/examples/upload_yolo_format_annotations.py +70 -70
- dtlpy/exceptions.py +125 -125
- dtlpy/miscellaneous/__init__.py +20 -20
- dtlpy/miscellaneous/dict_differ.py +95 -95
- dtlpy/miscellaneous/git_utils.py +217 -217
- dtlpy/miscellaneous/json_utils.py +14 -14
- dtlpy/miscellaneous/list_print.py +105 -105
- dtlpy/miscellaneous/zipping.py +130 -130
- dtlpy/ml/__init__.py +20 -20
- dtlpy/ml/base_feature_extractor_adapter.py +27 -27
- dtlpy/ml/base_model_adapter.py +1257 -1230
- dtlpy/ml/metrics.py +461 -461
- dtlpy/ml/predictions_utils.py +274 -274
- dtlpy/ml/summary_writer.py +57 -57
- dtlpy/ml/train_utils.py +60 -60
- dtlpy/new_instance.py +252 -252
- dtlpy/repositories/__init__.py +56 -56
- dtlpy/repositories/analytics.py +85 -85
- dtlpy/repositories/annotations.py +916 -916
- dtlpy/repositories/apps.py +383 -383
- dtlpy/repositories/artifacts.py +452 -452
- dtlpy/repositories/assignments.py +599 -599
- dtlpy/repositories/bots.py +213 -213
- dtlpy/repositories/codebases.py +559 -559
- dtlpy/repositories/collections.py +332 -332
- dtlpy/repositories/commands.py +152 -152
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +439 -439
- dtlpy/repositories/datasets.py +1504 -1504
- dtlpy/repositories/downloader.py +976 -923
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -482
- dtlpy/repositories/executions.py +815 -815
- dtlpy/repositories/feature_sets.py +226 -226
- dtlpy/repositories/features.py +255 -255
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +912 -912
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +1000 -1000
- dtlpy/repositories/nodes.py +80 -80
- dtlpy/repositories/ontologies.py +511 -511
- dtlpy/repositories/organizations.py +525 -525
- dtlpy/repositories/packages.py +1941 -1941
- dtlpy/repositories/pipeline_executions.py +451 -451
- dtlpy/repositories/pipelines.py +640 -640
- dtlpy/repositories/projects.py +539 -539
- dtlpy/repositories/recipes.py +419 -399
- dtlpy/repositories/resource_executions.py +137 -137
- dtlpy/repositories/schema.py +120 -120
- dtlpy/repositories/service_drivers.py +213 -213
- dtlpy/repositories/services.py +1704 -1704
- dtlpy/repositories/settings.py +339 -339
- dtlpy/repositories/tasks.py +1477 -1477
- dtlpy/repositories/times_series.py +278 -278
- dtlpy/repositories/triggers.py +536 -536
- dtlpy/repositories/upload_element.py +257 -257
- dtlpy/repositories/uploader.py +661 -661
- dtlpy/repositories/webhooks.py +249 -249
- dtlpy/services/__init__.py +22 -22
- dtlpy/services/aihttp_retry.py +131 -131
- dtlpy/services/api_client.py +1785 -1785
- dtlpy/services/api_reference.py +40 -40
- dtlpy/services/async_utils.py +133 -133
- dtlpy/services/calls_counter.py +44 -44
- dtlpy/services/check_sdk.py +68 -68
- dtlpy/services/cookie.py +115 -115
- dtlpy/services/create_logger.py +156 -156
- dtlpy/services/events.py +84 -84
- dtlpy/services/logins.py +235 -235
- dtlpy/services/reporter.py +256 -256
- dtlpy/services/service_defaults.py +91 -91
- dtlpy/utilities/__init__.py +20 -20
- dtlpy/utilities/annotations/__init__.py +16 -16
- dtlpy/utilities/annotations/annotation_converters.py +269 -269
- dtlpy/utilities/base_package_runner.py +285 -264
- dtlpy/utilities/converter.py +1650 -1650
- dtlpy/utilities/dataset_generators/__init__.py +1 -1
- dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
- dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
- dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
- dtlpy/utilities/local_development/__init__.py +1 -1
- dtlpy/utilities/local_development/local_session.py +179 -179
- dtlpy/utilities/reports/__init__.py +2 -2
- dtlpy/utilities/reports/figures.py +343 -343
- dtlpy/utilities/reports/report.py +71 -71
- dtlpy/utilities/videos/__init__.py +17 -17
- dtlpy/utilities/videos/video_player.py +598 -598
- dtlpy/utilities/videos/videos.py +470 -470
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp +1 -1
- dtlpy-1.116.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/METADATA +186 -186
- dtlpy-1.116.6.dist-info/RECORD +239 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/licenses/LICENSE +200 -200
- tests/features/environment.py +551 -551
- dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
- dtlpy-1.115.44.data/scripts/dlp.bat +0 -2
- dtlpy-1.115.44.dist-info/RECORD +0 -240
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/top_level.txt +0 -0
dtlpy/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
|