dtlpy 1.115.44__py3-none-any.whl → 1.117.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +152 -145
- dtlpy/entities/filters.py +798 -798
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +975 -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 +974 -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 +1287 -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 +1585 -1504
- dtlpy/repositories/downloader.py +1157 -923
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -482
- dtlpy/repositories/executions.py +815 -815
- dtlpy/repositories/feature_sets.py +256 -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 +429 -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 +1786 -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.117.6.data}/scripts/dlp +1 -1
- dtlpy-1.117.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/METADATA +186 -186
- dtlpy-1.117.6.dist-info/RECORD +239 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.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.117.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/top_level.txt +0 -0
dtlpy/entities/recipe.py
CHANGED
|
@@ -1,301 +1,301 @@
|
|
|
1
|
-
from collections import namedtuple
|
|
2
|
-
import traceback
|
|
3
|
-
import logging
|
|
4
|
-
import uuid
|
|
5
|
-
import attr
|
|
6
|
-
import os
|
|
7
|
-
|
|
8
|
-
from .. import repositories, entities, exceptions
|
|
9
|
-
from ..services.api_client import ApiClient
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(name='dtlpy')
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@attr.s
|
|
15
|
-
class Recipe(entities.BaseEntity):
|
|
16
|
-
"""
|
|
17
|
-
Recipe object
|
|
18
|
-
"""
|
|
19
|
-
id = attr.ib()
|
|
20
|
-
creator = attr.ib()
|
|
21
|
-
url = attr.ib(repr=False)
|
|
22
|
-
title = attr.ib()
|
|
23
|
-
project_ids = attr.ib()
|
|
24
|
-
description = attr.ib()
|
|
25
|
-
ontology_ids = attr.ib(repr=False)
|
|
26
|
-
instructions = attr.ib(repr=False)
|
|
27
|
-
examples = attr.ib(repr=False)
|
|
28
|
-
custom_actions = attr.ib(repr=False)
|
|
29
|
-
metadata = attr.ib()
|
|
30
|
-
created_at = attr.ib()
|
|
31
|
-
updated_at = attr.ib()
|
|
32
|
-
updated_by = attr.ib()
|
|
33
|
-
|
|
34
|
-
# name change
|
|
35
|
-
ui_settings = attr.ib()
|
|
36
|
-
|
|
37
|
-
# platform
|
|
38
|
-
_client_api = attr.ib(type=ApiClient, repr=False)
|
|
39
|
-
# entities
|
|
40
|
-
_dataset = attr.ib(repr=False, default=None)
|
|
41
|
-
_project = attr.ib(repr=False, default=None)
|
|
42
|
-
# repositories
|
|
43
|
-
_repositories = attr.ib(repr=False)
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def customActions(self):
|
|
47
|
-
return self.custom_actions
|
|
48
|
-
|
|
49
|
-
@property
|
|
50
|
-
def ontologyIds(self):
|
|
51
|
-
logger.warning('Deprecation Warning - ontologyIds will be Deprecation from version 1.52.0 use ontology_ids')
|
|
52
|
-
return self.ontology_ids
|
|
53
|
-
|
|
54
|
-
@classmethod
|
|
55
|
-
def from_json(cls, _json, client_api, dataset=None, project=None, is_fetched=True):
|
|
56
|
-
"""
|
|
57
|
-
Build a Recipe entity object from a json
|
|
58
|
-
|
|
59
|
-
:param dict _json: _json response from host
|
|
60
|
-
:param dtlpy.entities.dataset.Dataset dataset: Dataset entity
|
|
61
|
-
:param dtlpy.entities.project.Project project: project entity
|
|
62
|
-
:param dl.ApiClient client_api: ApiClient entity
|
|
63
|
-
:param bool is_fetched: is Entity fetched from Platform
|
|
64
|
-
:return: Recipe object
|
|
65
|
-
"""
|
|
66
|
-
project_ids = _json.get('projectIds', None)
|
|
67
|
-
if project is not None and project_ids is not None:
|
|
68
|
-
if project.id not in project_ids:
|
|
69
|
-
logger.warning('Recipe has been fetched from a project that is not belong to it')
|
|
70
|
-
project = None
|
|
71
|
-
|
|
72
|
-
inst = cls(
|
|
73
|
-
client_api=client_api,
|
|
74
|
-
dataset=dataset,
|
|
75
|
-
project=project,
|
|
76
|
-
id=_json['id'],
|
|
77
|
-
creator=_json.get('creator', None),
|
|
78
|
-
url=_json.get('url', None),
|
|
79
|
-
title=_json.get('title', None),
|
|
80
|
-
project_ids=project_ids,
|
|
81
|
-
description=_json.get('description', None),
|
|
82
|
-
ontology_ids=_json.get('ontologyIds', None),
|
|
83
|
-
instructions=_json.get('instructions', None),
|
|
84
|
-
ui_settings=_json.get('uiSettings', None),
|
|
85
|
-
metadata=_json.get('metadata', None),
|
|
86
|
-
examples=_json.get('examples', None),
|
|
87
|
-
custom_actions=_json.get('customActions', None),
|
|
88
|
-
created_at=_json.get("createdAt", None),
|
|
89
|
-
updated_at=_json.get("updatedAt", None),
|
|
90
|
-
updated_by=_json.get("updatedBy", None))
|
|
91
|
-
inst.is_fetched = is_fetched
|
|
92
|
-
return inst
|
|
93
|
-
|
|
94
|
-
@staticmethod
|
|
95
|
-
def _protected_from_json(_json, client_api, project=None, dataset=None, is_fetched=True):
|
|
96
|
-
"""
|
|
97
|
-
Same as from_json but with try-except to catch if error
|
|
98
|
-
|
|
99
|
-
:param _json: platform json
|
|
100
|
-
:param client_api: ApiClient entity
|
|
101
|
-
:param project: project entity
|
|
102
|
-
:param dataset: dataset entity
|
|
103
|
-
:param is_fetched: is Entity fetched from Platform
|
|
104
|
-
:return:
|
|
105
|
-
"""
|
|
106
|
-
try:
|
|
107
|
-
recipe = Recipe.from_json(_json=_json,
|
|
108
|
-
client_api=client_api,
|
|
109
|
-
project=project,
|
|
110
|
-
dataset=dataset,
|
|
111
|
-
is_fetched=is_fetched)
|
|
112
|
-
status = True
|
|
113
|
-
except Exception:
|
|
114
|
-
recipe = traceback.format_exc()
|
|
115
|
-
status = False
|
|
116
|
-
return status, recipe
|
|
117
|
-
|
|
118
|
-
@_repositories.default
|
|
119
|
-
def set_repositories(self):
|
|
120
|
-
reps = namedtuple('repositories',
|
|
121
|
-
field_names=['ontologies', 'recipes'])
|
|
122
|
-
if self._dataset is None and self._project is None:
|
|
123
|
-
recipes = repositories.Recipes(client_api=self._client_api, dataset=self._dataset, project=self._project)
|
|
124
|
-
elif self._dataset is not None:
|
|
125
|
-
recipes = self.dataset.recipes
|
|
126
|
-
else:
|
|
127
|
-
recipes = self.project.recipes
|
|
128
|
-
r = reps(ontologies=repositories.Ontologies(recipe=self, client_api=self._client_api),
|
|
129
|
-
recipes=recipes)
|
|
130
|
-
return r
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def dataset(self):
|
|
134
|
-
if self._dataset is not None:
|
|
135
|
-
assert isinstance(self._dataset, entities.Dataset)
|
|
136
|
-
return self._dataset
|
|
137
|
-
|
|
138
|
-
@property
|
|
139
|
-
def project(self):
|
|
140
|
-
if self._project is not None:
|
|
141
|
-
assert isinstance(self._project, entities.Project)
|
|
142
|
-
return self._project
|
|
143
|
-
|
|
144
|
-
@property
|
|
145
|
-
def recipes(self):
|
|
146
|
-
assert isinstance(self._repositories.recipes, repositories.Recipes)
|
|
147
|
-
return self._repositories.recipes
|
|
148
|
-
|
|
149
|
-
@property
|
|
150
|
-
def ontologies(self):
|
|
151
|
-
assert isinstance(self._repositories.ontologies, repositories.Ontologies)
|
|
152
|
-
return self._repositories.ontologies
|
|
153
|
-
|
|
154
|
-
def to_json(self):
|
|
155
|
-
"""
|
|
156
|
-
Returns platform _json format of object
|
|
157
|
-
|
|
158
|
-
:return: platform json format of object
|
|
159
|
-
:rtype: dict
|
|
160
|
-
"""
|
|
161
|
-
_json = attr.asdict(self, filter=attr.filters.exclude(attr.fields(Recipe)._client_api,
|
|
162
|
-
attr.fields(Recipe)._dataset,
|
|
163
|
-
attr.fields(Recipe)._project,
|
|
164
|
-
attr.fields(Recipe).project_ids,
|
|
165
|
-
attr.fields(Recipe).ui_settings,
|
|
166
|
-
attr.fields(Recipe)._repositories,
|
|
167
|
-
attr.fields(Recipe).custom_actions,
|
|
168
|
-
attr.fields(Recipe).ontology_ids,
|
|
169
|
-
attr.fields(Recipe).created_at,
|
|
170
|
-
attr.fields(Recipe).updated_at,
|
|
171
|
-
attr.fields(Recipe).updated_by,
|
|
172
|
-
))
|
|
173
|
-
_json['uiSettings'] = self.ui_settings
|
|
174
|
-
_json['projectIds'] = self.project_ids
|
|
175
|
-
_json['customActions'] = self.custom_actions
|
|
176
|
-
_json['ontologyIds'] = self.ontology_ids
|
|
177
|
-
_json['createdAt'] = self.created_at
|
|
178
|
-
_json['updatedAt'] = self.updated_at
|
|
179
|
-
_json['updatedBy'] = self.updated_by
|
|
180
|
-
return _json
|
|
181
|
-
|
|
182
|
-
@property
|
|
183
|
-
def platform_url(self):
|
|
184
|
-
return self._client_api._get_resource_url("projects/{}/recipes/{}".format(self.project_ids[0], self.id))
|
|
185
|
-
|
|
186
|
-
def open_in_web(self):
|
|
187
|
-
"""
|
|
188
|
-
Open the recipes in web platform
|
|
189
|
-
|
|
190
|
-
:return:
|
|
191
|
-
"""
|
|
192
|
-
self._client_api._open_in_web(url=self.platform_url)
|
|
193
|
-
|
|
194
|
-
def delete(self, force: bool = False):
|
|
195
|
-
"""
|
|
196
|
-
Delete recipe from platform
|
|
197
|
-
|
|
198
|
-
:param bool force: force delete recipe
|
|
199
|
-
|
|
200
|
-
:return: True
|
|
201
|
-
:rtype: bool
|
|
202
|
-
"""
|
|
203
|
-
return self.recipes.delete(self.id, force=force)
|
|
204
|
-
|
|
205
|
-
def update(self, system_metadata=False):
|
|
206
|
-
"""
|
|
207
|
-
Update Recipe
|
|
208
|
-
|
|
209
|
-
:param bool system_metadata: bool - True, if you want to change metadata system
|
|
210
|
-
:return: Recipe object
|
|
211
|
-
:rtype: dtlpy.entities.recipe.Recipe
|
|
212
|
-
"""
|
|
213
|
-
return self.recipes.update(recipe=self, system_metadata=system_metadata)
|
|
214
|
-
|
|
215
|
-
def clone(self, shallow=False):
|
|
216
|
-
"""
|
|
217
|
-
Clone Recipe
|
|
218
|
-
|
|
219
|
-
:param bool shallow: If True, link ot existing ontology, clones all ontology that are link to the recipe as well
|
|
220
|
-
:return: Cloned ontology object
|
|
221
|
-
:rtype: dtlpy.entities.recipe.Recipe
|
|
222
|
-
"""
|
|
223
|
-
return self.recipes.clone(recipe=self,
|
|
224
|
-
shallow=shallow)
|
|
225
|
-
|
|
226
|
-
def get_annotation_template_id(self, template_name):
|
|
227
|
-
"""
|
|
228
|
-
Get annotation template id by template name
|
|
229
|
-
|
|
230
|
-
:param str template_name:
|
|
231
|
-
:return: template id or None if does not exist
|
|
232
|
-
"""
|
|
233
|
-
collection_templates = list()
|
|
234
|
-
if 'system' in self.metadata and 'collectionTemplates' in self.metadata['system']:
|
|
235
|
-
collection_templates = self.metadata['system']['collectionTemplates']
|
|
236
|
-
|
|
237
|
-
for template in collection_templates:
|
|
238
|
-
if "name" and 'id' in template:
|
|
239
|
-
if template_name == template['name']:
|
|
240
|
-
return template['id']
|
|
241
|
-
raise exceptions.NotFound('404', "annotation template {!r} not found".format(template_name))
|
|
242
|
-
|
|
243
|
-
def add_instruction(self, annotation_instruction_file):
|
|
244
|
-
"""
|
|
245
|
-
Add instruction to recipe
|
|
246
|
-
|
|
247
|
-
:param str annotation_instruction_file: file path or url of the recipe instruction
|
|
248
|
-
"""
|
|
249
|
-
_, ext = os.path.splitext(annotation_instruction_file)
|
|
250
|
-
if ext != '.pdf':
|
|
251
|
-
raise exceptions.PlatformException(error='400',
|
|
252
|
-
message='file Must be pdf')
|
|
253
|
-
for project_id in self.project_ids:
|
|
254
|
-
project = repositories.Projects(client_api=self._client_api).get(project_id=project_id)
|
|
255
|
-
dataset = project.datasets._get_binaries_dataset()
|
|
256
|
-
remote_path = '/.dataloop/recipes/{}/instructions'.format(self.id)
|
|
257
|
-
instruction_item = dataset.items.upload(local_path=annotation_instruction_file,
|
|
258
|
-
remote_path=remote_path,
|
|
259
|
-
remote_name=str(uuid.uuid4()) + '.pdf',
|
|
260
|
-
overwrite=True)
|
|
261
|
-
self.metadata['system']['instructionDocument'] = {'itemId': instruction_item.id,
|
|
262
|
-
'datasetId': dataset.id,
|
|
263
|
-
'name': instruction_item.name}
|
|
264
|
-
self.update(True)
|
|
265
|
-
|
|
266
|
-
def upload_annotations_verification_file(self, local_path: str, overwrite: bool = False) -> entities.Item:
|
|
267
|
-
"""
|
|
268
|
-
Add Annotations Verification js file to the recipe.
|
|
269
|
-
|
|
270
|
-
:param str local_path: file path of the annotations verification js file.
|
|
271
|
-
:param bool overwrite: overwrite exiting file if the local and the remote names are matching
|
|
272
|
-
:return: annotations verification js item.
|
|
273
|
-
"""
|
|
274
|
-
|
|
275
|
-
validation_file_metadata = self.metadata.get("system", dict()).get("validationFile", None)
|
|
276
|
-
if validation_file_metadata is None:
|
|
277
|
-
validation_file_metadata = dict()
|
|
278
|
-
|
|
279
|
-
remote_name = validation_file_metadata.get("name", None)
|
|
280
|
-
local_name = os.path.basename(local_path)
|
|
281
|
-
binaries_dataset = self._project.datasets._get_binaries_dataset()
|
|
282
|
-
remote_path = f"/.dataloop/recipes/{self.id}/verification/"
|
|
283
|
-
|
|
284
|
-
if remote_name is None or overwrite or remote_name != local_name:
|
|
285
|
-
validation_item = binaries_dataset.items.upload(
|
|
286
|
-
local_path=local_path,
|
|
287
|
-
remote_path=remote_path,
|
|
288
|
-
remote_name=local_name,
|
|
289
|
-
overwrite=True
|
|
290
|
-
)
|
|
291
|
-
self.metadata["system"]["validationFile"] = {
|
|
292
|
-
"itemId": validation_item.id,
|
|
293
|
-
"datasetId": binaries_dataset.id,
|
|
294
|
-
"name": local_name
|
|
295
|
-
}
|
|
296
|
-
self.update(system_metadata=True)
|
|
297
|
-
else:
|
|
298
|
-
logger.debug(f"Existing Annotations Validation Script was found.")
|
|
299
|
-
validation_item_id = self.metadata["system"]["validationFile"]["itemId"]
|
|
300
|
-
validation_item = binaries_dataset.items.get(item_id=validation_item_id)
|
|
301
|
-
return validation_item
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
import traceback
|
|
3
|
+
import logging
|
|
4
|
+
import uuid
|
|
5
|
+
import attr
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
from .. import repositories, entities, exceptions
|
|
9
|
+
from ..services.api_client import ApiClient
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(name='dtlpy')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@attr.s
|
|
15
|
+
class Recipe(entities.BaseEntity):
|
|
16
|
+
"""
|
|
17
|
+
Recipe object
|
|
18
|
+
"""
|
|
19
|
+
id = attr.ib()
|
|
20
|
+
creator = attr.ib()
|
|
21
|
+
url = attr.ib(repr=False)
|
|
22
|
+
title = attr.ib()
|
|
23
|
+
project_ids = attr.ib()
|
|
24
|
+
description = attr.ib()
|
|
25
|
+
ontology_ids = attr.ib(repr=False)
|
|
26
|
+
instructions = attr.ib(repr=False)
|
|
27
|
+
examples = attr.ib(repr=False)
|
|
28
|
+
custom_actions = attr.ib(repr=False)
|
|
29
|
+
metadata = attr.ib()
|
|
30
|
+
created_at = attr.ib()
|
|
31
|
+
updated_at = attr.ib()
|
|
32
|
+
updated_by = attr.ib()
|
|
33
|
+
|
|
34
|
+
# name change
|
|
35
|
+
ui_settings = attr.ib()
|
|
36
|
+
|
|
37
|
+
# platform
|
|
38
|
+
_client_api = attr.ib(type=ApiClient, repr=False)
|
|
39
|
+
# entities
|
|
40
|
+
_dataset = attr.ib(repr=False, default=None)
|
|
41
|
+
_project = attr.ib(repr=False, default=None)
|
|
42
|
+
# repositories
|
|
43
|
+
_repositories = attr.ib(repr=False)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def customActions(self):
|
|
47
|
+
return self.custom_actions
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def ontologyIds(self):
|
|
51
|
+
logger.warning('Deprecation Warning - ontologyIds will be Deprecation from version 1.52.0 use ontology_ids')
|
|
52
|
+
return self.ontology_ids
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def from_json(cls, _json, client_api, dataset=None, project=None, is_fetched=True):
|
|
56
|
+
"""
|
|
57
|
+
Build a Recipe entity object from a json
|
|
58
|
+
|
|
59
|
+
:param dict _json: _json response from host
|
|
60
|
+
:param dtlpy.entities.dataset.Dataset dataset: Dataset entity
|
|
61
|
+
:param dtlpy.entities.project.Project project: project entity
|
|
62
|
+
:param dl.ApiClient client_api: ApiClient entity
|
|
63
|
+
:param bool is_fetched: is Entity fetched from Platform
|
|
64
|
+
:return: Recipe object
|
|
65
|
+
"""
|
|
66
|
+
project_ids = _json.get('projectIds', None)
|
|
67
|
+
if project is not None and project_ids is not None:
|
|
68
|
+
if project.id not in project_ids:
|
|
69
|
+
logger.warning('Recipe has been fetched from a project that is not belong to it')
|
|
70
|
+
project = None
|
|
71
|
+
|
|
72
|
+
inst = cls(
|
|
73
|
+
client_api=client_api,
|
|
74
|
+
dataset=dataset,
|
|
75
|
+
project=project,
|
|
76
|
+
id=_json['id'],
|
|
77
|
+
creator=_json.get('creator', None),
|
|
78
|
+
url=_json.get('url', None),
|
|
79
|
+
title=_json.get('title', None),
|
|
80
|
+
project_ids=project_ids,
|
|
81
|
+
description=_json.get('description', None),
|
|
82
|
+
ontology_ids=_json.get('ontologyIds', None),
|
|
83
|
+
instructions=_json.get('instructions', None),
|
|
84
|
+
ui_settings=_json.get('uiSettings', None),
|
|
85
|
+
metadata=_json.get('metadata', None),
|
|
86
|
+
examples=_json.get('examples', None),
|
|
87
|
+
custom_actions=_json.get('customActions', None),
|
|
88
|
+
created_at=_json.get("createdAt", None),
|
|
89
|
+
updated_at=_json.get("updatedAt", None),
|
|
90
|
+
updated_by=_json.get("updatedBy", None))
|
|
91
|
+
inst.is_fetched = is_fetched
|
|
92
|
+
return inst
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def _protected_from_json(_json, client_api, project=None, dataset=None, is_fetched=True):
|
|
96
|
+
"""
|
|
97
|
+
Same as from_json but with try-except to catch if error
|
|
98
|
+
|
|
99
|
+
:param _json: platform json
|
|
100
|
+
:param client_api: ApiClient entity
|
|
101
|
+
:param project: project entity
|
|
102
|
+
:param dataset: dataset entity
|
|
103
|
+
:param is_fetched: is Entity fetched from Platform
|
|
104
|
+
:return:
|
|
105
|
+
"""
|
|
106
|
+
try:
|
|
107
|
+
recipe = Recipe.from_json(_json=_json,
|
|
108
|
+
client_api=client_api,
|
|
109
|
+
project=project,
|
|
110
|
+
dataset=dataset,
|
|
111
|
+
is_fetched=is_fetched)
|
|
112
|
+
status = True
|
|
113
|
+
except Exception:
|
|
114
|
+
recipe = traceback.format_exc()
|
|
115
|
+
status = False
|
|
116
|
+
return status, recipe
|
|
117
|
+
|
|
118
|
+
@_repositories.default
|
|
119
|
+
def set_repositories(self):
|
|
120
|
+
reps = namedtuple('repositories',
|
|
121
|
+
field_names=['ontologies', 'recipes'])
|
|
122
|
+
if self._dataset is None and self._project is None:
|
|
123
|
+
recipes = repositories.Recipes(client_api=self._client_api, dataset=self._dataset, project=self._project)
|
|
124
|
+
elif self._dataset is not None:
|
|
125
|
+
recipes = self.dataset.recipes
|
|
126
|
+
else:
|
|
127
|
+
recipes = self.project.recipes
|
|
128
|
+
r = reps(ontologies=repositories.Ontologies(recipe=self, client_api=self._client_api),
|
|
129
|
+
recipes=recipes)
|
|
130
|
+
return r
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def dataset(self):
|
|
134
|
+
if self._dataset is not None:
|
|
135
|
+
assert isinstance(self._dataset, entities.Dataset)
|
|
136
|
+
return self._dataset
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def project(self):
|
|
140
|
+
if self._project is not None:
|
|
141
|
+
assert isinstance(self._project, entities.Project)
|
|
142
|
+
return self._project
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def recipes(self):
|
|
146
|
+
assert isinstance(self._repositories.recipes, repositories.Recipes)
|
|
147
|
+
return self._repositories.recipes
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def ontologies(self):
|
|
151
|
+
assert isinstance(self._repositories.ontologies, repositories.Ontologies)
|
|
152
|
+
return self._repositories.ontologies
|
|
153
|
+
|
|
154
|
+
def to_json(self):
|
|
155
|
+
"""
|
|
156
|
+
Returns platform _json format of object
|
|
157
|
+
|
|
158
|
+
:return: platform json format of object
|
|
159
|
+
:rtype: dict
|
|
160
|
+
"""
|
|
161
|
+
_json = attr.asdict(self, filter=attr.filters.exclude(attr.fields(Recipe)._client_api,
|
|
162
|
+
attr.fields(Recipe)._dataset,
|
|
163
|
+
attr.fields(Recipe)._project,
|
|
164
|
+
attr.fields(Recipe).project_ids,
|
|
165
|
+
attr.fields(Recipe).ui_settings,
|
|
166
|
+
attr.fields(Recipe)._repositories,
|
|
167
|
+
attr.fields(Recipe).custom_actions,
|
|
168
|
+
attr.fields(Recipe).ontology_ids,
|
|
169
|
+
attr.fields(Recipe).created_at,
|
|
170
|
+
attr.fields(Recipe).updated_at,
|
|
171
|
+
attr.fields(Recipe).updated_by,
|
|
172
|
+
))
|
|
173
|
+
_json['uiSettings'] = self.ui_settings
|
|
174
|
+
_json['projectIds'] = self.project_ids
|
|
175
|
+
_json['customActions'] = self.custom_actions
|
|
176
|
+
_json['ontologyIds'] = self.ontology_ids
|
|
177
|
+
_json['createdAt'] = self.created_at
|
|
178
|
+
_json['updatedAt'] = self.updated_at
|
|
179
|
+
_json['updatedBy'] = self.updated_by
|
|
180
|
+
return _json
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def platform_url(self):
|
|
184
|
+
return self._client_api._get_resource_url("projects/{}/recipes/{}".format(self.project_ids[0], self.id))
|
|
185
|
+
|
|
186
|
+
def open_in_web(self):
|
|
187
|
+
"""
|
|
188
|
+
Open the recipes in web platform
|
|
189
|
+
|
|
190
|
+
:return:
|
|
191
|
+
"""
|
|
192
|
+
self._client_api._open_in_web(url=self.platform_url)
|
|
193
|
+
|
|
194
|
+
def delete(self, force: bool = False):
|
|
195
|
+
"""
|
|
196
|
+
Delete recipe from platform
|
|
197
|
+
|
|
198
|
+
:param bool force: force delete recipe
|
|
199
|
+
|
|
200
|
+
:return: True
|
|
201
|
+
:rtype: bool
|
|
202
|
+
"""
|
|
203
|
+
return self.recipes.delete(self.id, force=force)
|
|
204
|
+
|
|
205
|
+
def update(self, system_metadata=False):
|
|
206
|
+
"""
|
|
207
|
+
Update Recipe
|
|
208
|
+
|
|
209
|
+
:param bool system_metadata: bool - True, if you want to change metadata system
|
|
210
|
+
:return: Recipe object
|
|
211
|
+
:rtype: dtlpy.entities.recipe.Recipe
|
|
212
|
+
"""
|
|
213
|
+
return self.recipes.update(recipe=self, system_metadata=system_metadata)
|
|
214
|
+
|
|
215
|
+
def clone(self, shallow=False):
|
|
216
|
+
"""
|
|
217
|
+
Clone Recipe
|
|
218
|
+
|
|
219
|
+
:param bool shallow: If True, link ot existing ontology, clones all ontology that are link to the recipe as well
|
|
220
|
+
:return: Cloned ontology object
|
|
221
|
+
:rtype: dtlpy.entities.recipe.Recipe
|
|
222
|
+
"""
|
|
223
|
+
return self.recipes.clone(recipe=self,
|
|
224
|
+
shallow=shallow)
|
|
225
|
+
|
|
226
|
+
def get_annotation_template_id(self, template_name):
|
|
227
|
+
"""
|
|
228
|
+
Get annotation template id by template name
|
|
229
|
+
|
|
230
|
+
:param str template_name:
|
|
231
|
+
:return: template id or None if does not exist
|
|
232
|
+
"""
|
|
233
|
+
collection_templates = list()
|
|
234
|
+
if 'system' in self.metadata and 'collectionTemplates' in self.metadata['system']:
|
|
235
|
+
collection_templates = self.metadata['system']['collectionTemplates']
|
|
236
|
+
|
|
237
|
+
for template in collection_templates:
|
|
238
|
+
if "name" and 'id' in template:
|
|
239
|
+
if template_name == template['name']:
|
|
240
|
+
return template['id']
|
|
241
|
+
raise exceptions.NotFound('404', "annotation template {!r} not found".format(template_name))
|
|
242
|
+
|
|
243
|
+
def add_instruction(self, annotation_instruction_file):
|
|
244
|
+
"""
|
|
245
|
+
Add instruction to recipe
|
|
246
|
+
|
|
247
|
+
:param str annotation_instruction_file: file path or url of the recipe instruction
|
|
248
|
+
"""
|
|
249
|
+
_, ext = os.path.splitext(annotation_instruction_file)
|
|
250
|
+
if ext != '.pdf':
|
|
251
|
+
raise exceptions.PlatformException(error='400',
|
|
252
|
+
message='file Must be pdf')
|
|
253
|
+
for project_id in self.project_ids:
|
|
254
|
+
project = repositories.Projects(client_api=self._client_api).get(project_id=project_id)
|
|
255
|
+
dataset = project.datasets._get_binaries_dataset()
|
|
256
|
+
remote_path = '/.dataloop/recipes/{}/instructions'.format(self.id)
|
|
257
|
+
instruction_item = dataset.items.upload(local_path=annotation_instruction_file,
|
|
258
|
+
remote_path=remote_path,
|
|
259
|
+
remote_name=str(uuid.uuid4()) + '.pdf',
|
|
260
|
+
overwrite=True)
|
|
261
|
+
self.metadata['system']['instructionDocument'] = {'itemId': instruction_item.id,
|
|
262
|
+
'datasetId': dataset.id,
|
|
263
|
+
'name': instruction_item.name}
|
|
264
|
+
self.update(True)
|
|
265
|
+
|
|
266
|
+
def upload_annotations_verification_file(self, local_path: str, overwrite: bool = False) -> entities.Item:
|
|
267
|
+
"""
|
|
268
|
+
Add Annotations Verification js file to the recipe.
|
|
269
|
+
|
|
270
|
+
:param str local_path: file path of the annotations verification js file.
|
|
271
|
+
:param bool overwrite: overwrite exiting file if the local and the remote names are matching
|
|
272
|
+
:return: annotations verification js item.
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
validation_file_metadata = self.metadata.get("system", dict()).get("validationFile", None)
|
|
276
|
+
if validation_file_metadata is None:
|
|
277
|
+
validation_file_metadata = dict()
|
|
278
|
+
|
|
279
|
+
remote_name = validation_file_metadata.get("name", None)
|
|
280
|
+
local_name = os.path.basename(local_path)
|
|
281
|
+
binaries_dataset = self._project.datasets._get_binaries_dataset()
|
|
282
|
+
remote_path = f"/.dataloop/recipes/{self.id}/verification/"
|
|
283
|
+
|
|
284
|
+
if remote_name is None or overwrite or remote_name != local_name:
|
|
285
|
+
validation_item = binaries_dataset.items.upload(
|
|
286
|
+
local_path=local_path,
|
|
287
|
+
remote_path=remote_path,
|
|
288
|
+
remote_name=local_name,
|
|
289
|
+
overwrite=True
|
|
290
|
+
)
|
|
291
|
+
self.metadata["system"]["validationFile"] = {
|
|
292
|
+
"itemId": validation_item.id,
|
|
293
|
+
"datasetId": binaries_dataset.id,
|
|
294
|
+
"name": local_name
|
|
295
|
+
}
|
|
296
|
+
self.update(system_metadata=True)
|
|
297
|
+
else:
|
|
298
|
+
logger.debug(f"Existing Annotations Validation Script was found.")
|
|
299
|
+
validation_item_id = self.metadata["system"]["validationFile"]["itemId"]
|
|
300
|
+
validation_item = binaries_dataset.items.get(item_id=validation_item_id)
|
|
301
|
+
return validation_item
|