dtlpy 1.90.39__py3-none-any.whl → 1.91.37__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. dtlpy/__version__.py +1 -1
  2. dtlpy/assets/lock_open.png +0 -0
  3. dtlpy/entities/analytic.py +118 -98
  4. dtlpy/entities/annotation.py +22 -31
  5. dtlpy/entities/annotation_collection.py +19 -21
  6. dtlpy/entities/app.py +13 -3
  7. dtlpy/entities/assignment.py +6 -0
  8. dtlpy/entities/base_entity.py +0 -23
  9. dtlpy/entities/dataset.py +1 -1
  10. dtlpy/entities/dpk.py +15 -0
  11. dtlpy/entities/execution.py +13 -1
  12. dtlpy/entities/filters.py +85 -6
  13. dtlpy/entities/integration.py +1 -1
  14. dtlpy/entities/item.py +26 -0
  15. dtlpy/entities/node.py +38 -2
  16. dtlpy/entities/ontology.py +61 -0
  17. dtlpy/entities/package_function.py +2 -0
  18. dtlpy/entities/package_module.py +13 -0
  19. dtlpy/entities/pipeline_execution.py +14 -6
  20. dtlpy/entities/prompt_item.py +10 -0
  21. dtlpy/entities/recipe.py +37 -0
  22. dtlpy/entities/service.py +31 -2
  23. dtlpy/ml/base_model_adapter.py +92 -2
  24. dtlpy/repositories/apps.py +12 -12
  25. dtlpy/repositories/assignments.py +1 -1
  26. dtlpy/repositories/datasets.py +1 -1
  27. dtlpy/repositories/dpks.py +29 -0
  28. dtlpy/repositories/executions.py +27 -30
  29. dtlpy/repositories/features.py +4 -1
  30. dtlpy/repositories/packages.py +6 -3
  31. dtlpy/repositories/pipeline_executions.py +5 -5
  32. dtlpy/repositories/services.py +28 -7
  33. dtlpy/repositories/tasks.py +8 -2
  34. dtlpy/repositories/uploader.py +2 -2
  35. dtlpy/services/api_client.py +15 -9
  36. {dtlpy-1.90.39.dist-info → dtlpy-1.91.37.dist-info}/METADATA +2 -2
  37. {dtlpy-1.90.39.dist-info → dtlpy-1.91.37.dist-info}/RECORD +45 -45
  38. tests/features/environment.py +38 -1
  39. {dtlpy-1.90.39.data → dtlpy-1.91.37.data}/scripts/dlp +0 -0
  40. {dtlpy-1.90.39.data → dtlpy-1.91.37.data}/scripts/dlp.bat +0 -0
  41. {dtlpy-1.90.39.data → dtlpy-1.91.37.data}/scripts/dlp.py +0 -0
  42. {dtlpy-1.90.39.dist-info → dtlpy-1.91.37.dist-info}/LICENSE +0 -0
  43. {dtlpy-1.90.39.dist-info → dtlpy-1.91.37.dist-info}/WHEEL +0 -0
  44. {dtlpy-1.90.39.dist-info → dtlpy-1.91.37.dist-info}/entry_points.txt +0 -0
  45. {dtlpy-1.90.39.dist-info → dtlpy-1.91.37.dist-info}/top_level.txt +0 -0
dtlpy/__version__.py CHANGED
@@ -1 +1 @@
1
- version = '1.90.39'
1
+ version = '1.91.37'
Binary file
@@ -14,6 +14,7 @@ class BaseSample:
14
14
  event_type,
15
15
  action,
16
16
  status,
17
+ other_keys: dict = None
17
18
  ):
18
19
  self.start_time = start_time
19
20
  self.end_time = end_time
@@ -23,6 +24,31 @@ class BaseSample:
23
24
  self.event_type = event_type
24
25
  self.action = action
25
26
  self.status = status
27
+ self.other_keys = other_keys
28
+
29
+ def to_json(self):
30
+ _json = {
31
+ 'startTime': self.start_time,
32
+ 'endTime': self.end_time,
33
+ 'context': {
34
+ 'projectId': self.project_id,
35
+ 'projectOrgId': self.org_id,
36
+ 'pipelineId': self.pipeline_id
37
+ },
38
+ 'eventType': self.event_type,
39
+ 'action': self.action,
40
+ 'data': {
41
+ 'status': self.status
42
+ }
43
+ }
44
+ if self.other_keys is not None:
45
+ if 'context' in self.other_keys:
46
+ _json['context'].update(self.other_keys['context'])
47
+ if 'data' in self.other_keys:
48
+ _json['data'].update(self.other_keys['data'])
49
+ _json.update({k: v for k, v in self.other_keys.items() if k not in ['context', 'data']})
50
+
51
+ return _json
26
52
 
27
53
 
28
54
  class ServiceSample(BaseSample):
@@ -47,16 +73,21 @@ class ServiceSample(BaseSample):
47
73
  queue_size=None,
48
74
  num_executions=None,
49
75
  service_type: entities.ServiceType = None,
50
- interval: int = None
76
+ interval: int = None,
77
+ driver_id: str = None,
78
+ other_keys: dict = None
51
79
  ):
52
- super().__init__(start_time=start_time,
53
- end_time=end_time,
54
- project_id=project_id,
55
- org_id=org_id,
56
- pipeline_id=pipeline_id,
57
- event_type=event_type,
58
- action=action,
59
- status=status)
80
+ super().__init__(
81
+ start_time=start_time,
82
+ end_time=end_time,
83
+ project_id=project_id,
84
+ org_id=org_id,
85
+ pipeline_id=pipeline_id,
86
+ event_type=event_type,
87
+ action=action,
88
+ status=status,
89
+ other_keys=other_keys
90
+ )
60
91
  self.user_id = user_id
61
92
  self.pipeline_node_id = pipeline_node_id
62
93
  self.service_id = service_id
@@ -70,38 +101,32 @@ class ServiceSample(BaseSample):
70
101
  self.num_executions = num_executions
71
102
  self.service_type = service_type if service_type is not None else entities.ServiceType.REGULAR
72
103
  self.interval = interval
104
+ self.driver_id = driver_id
73
105
 
74
106
  def to_json(self):
75
- _json = {
76
- 'startTime': self.start_time,
77
- 'endTime': self.end_time,
78
- 'context': {
79
- 'userId': self.user_id,
80
- 'projectId': self.project_id,
81
- 'projectOrgId': self.org_id,
82
- 'pipelineId': self.pipeline_id,
83
- 'pipelineNodeId': self.pipeline_node_id,
84
- 'serviceId': self.service_id,
85
- 'podId': self.pod_id,
86
- 'podType': self.pod_type,
87
- 'serviceType': self.service_type
88
- },
89
- 'eventType': self.event_type,
90
- 'entityType': self.entity_type,
91
- 'action': self.action,
92
- 'data': {
93
- 'status': self.status,
94
- 'numRestarts': self.num_restarts,
95
- 'cpu': self.cpu,
96
- 'ram': self.ram,
97
- 'queueSize': self.queue_size,
98
- 'numExecutions': self.num_executions,
99
- 'interval': self.interval
100
- }
101
- }
107
+ _json = super().to_json()
108
+ _json['context'].update({
109
+ 'userId': self.user_id,
110
+ 'pipelineNodeId': self.pipeline_node_id,
111
+ 'serviceId': self.service_id,
112
+ 'podId': self.pod_id,
113
+ 'podType': self.pod_type,
114
+ 'serviceType': self.service_type
115
+ })
116
+ _json['data'].update({
117
+ 'numRestarts': self.num_restarts,
118
+ 'cpu': self.cpu,
119
+ 'ram': self.ram,
120
+ 'queueSize': self.queue_size,
121
+ 'numExecutions': self.num_executions,
122
+ 'interval': self.interval,
123
+ 'driverId': self.driver_id
124
+ })
125
+ _json.update({
126
+ 'entityType': self.entity_type
127
+ })
102
128
  _json['context'] = {k: v for k, v in _json['context'].items() if v is not None}
103
129
  _json['data'] = {k: v for k, v in _json['data'].items() if v is not None}
104
-
105
130
  return {k: v for k, v in _json.items() if v is not None}
106
131
 
107
132
  @classmethod
@@ -127,6 +152,8 @@ class ServiceSample(BaseSample):
127
152
  queue_size=_json.get('data', {}).get('queueSize', None),
128
153
  num_executions=_json.get('data', {}).get('numExecutions', None),
129
154
  service_type=_json.get('type', entities.ServiceType.REGULAR),
155
+ interval=_json.get('data', {}).get('interval', None),
156
+ driver_id=_json.get('data', {}).get('driverId', None)
130
157
  )
131
158
  return inst
132
159
 
@@ -149,16 +176,20 @@ class ExecutionSample(BaseSample):
149
176
  execution_id=None,
150
177
  trigger_id=None,
151
178
  function_name=None,
152
- duration=None
179
+ duration=None,
180
+ other_keys: dict = None
153
181
  ):
154
- super().__init__(start_time=start_time,
155
- end_time=end_time,
156
- project_id=project_id,
157
- org_id=org_id,
158
- pipeline_id=pipeline_id,
159
- event_type=event_type,
160
- action=action,
161
- status=status)
182
+ super().__init__(
183
+ start_time=start_time,
184
+ end_time=end_time,
185
+ project_id=project_id,
186
+ org_id=org_id,
187
+ pipeline_id=pipeline_id,
188
+ event_type=event_type,
189
+ action=action,
190
+ status=status,
191
+ other_keys=other_keys
192
+ )
162
193
  self.user_id = user_id
163
194
  self.account_id = account_id
164
195
  self.pipeline_node_id = pipeline_node_id
@@ -170,30 +201,22 @@ class ExecutionSample(BaseSample):
170
201
  self.duration = duration
171
202
 
172
203
  def to_json(self):
173
- _json = {
174
- 'startTime': self.start_time,
175
- 'endTime': self.end_time,
176
- 'context': {
177
- 'userId': self.user_id,
178
- 'projectId': self.project_id,
179
- 'projectOrgId': self.org_id,
180
- 'accountId': self.account_id,
181
- 'pipelineId': self.pipeline_id,
182
- 'pipelineNodeId': self.pipeline_node_id,
183
- 'pipelineExecutionId': self.pipeline_execution_id,
184
- 'serviceId': self.service_id,
185
- 'executionId': self.execution_id,
186
- 'triggerId': self.trigger_id,
187
- },
188
- 'eventType': self.event_type,
189
- 'action': self.action,
190
- 'data': {
191
- 'status': self.status,
192
- 'functionName': self.function_name,
193
- 'duration': self.duration
194
- }
195
- }
196
- return _json
204
+ _json = super().to_json()
205
+ _json['context'].update({
206
+ 'userId': self.user_id,
207
+ 'accountId': self.account_id,
208
+ 'pipelineNodeId': self.pipeline_node_id,
209
+ 'pipelineExecutionId': self.pipeline_execution_id,
210
+ 'serviceId': self.service_id,
211
+ 'triggerId': self.trigger_id
212
+ })
213
+ _json['data'].update({
214
+ 'functionName': self.function_name,
215
+ 'duration': self.duration
216
+ })
217
+ _json['context'] = {k: v for k, v in _json['context'].items() if v is not None}
218
+ _json['data'] = {k: v for k, v in _json['data'].items() if v is not None}
219
+ return {k: v for k, v in _json.items() if v is not None}
197
220
 
198
221
  @classmethod
199
222
  def from_json(cls, _json):
@@ -234,15 +257,19 @@ class PipelineExecutionSample(BaseSample):
234
257
  pipeline_execution_id=None,
235
258
  trigger_id=None,
236
259
  node_status=None,
260
+ other_keys: dict = None
237
261
  ):
238
- super().__init__(start_time=start_time,
239
- end_time=end_time,
240
- project_id=project_id,
241
- org_id=org_id,
242
- pipeline_id=pipeline_id,
243
- event_type=event_type,
244
- action=action,
245
- status=status)
262
+ super().__init__(
263
+ start_time=start_time,
264
+ end_time=end_time,
265
+ project_id=project_id,
266
+ org_id=org_id,
267
+ pipeline_id=pipeline_id,
268
+ event_type=event_type,
269
+ action=action,
270
+ status=status,
271
+ other_keys=other_keys
272
+ )
246
273
  self.account_id = account_id
247
274
  self.pipeline_node_id = pipeline_node_id
248
275
  self.pipeline_execution_id = pipeline_execution_id
@@ -250,26 +277,19 @@ class PipelineExecutionSample(BaseSample):
250
277
  self.node_status = node_status
251
278
 
252
279
  def to_json(self):
253
- _json = {
254
- 'startTime': self.start_time,
255
- 'endTime': self.end_time,
256
- 'context': {
257
- 'projectId': self.project_id,
258
- 'projectOrgId': self.org_id,
259
- 'accountId': self.account_id,
260
- 'pipelineId': self.pipeline_id,
261
- 'pipelineExecutionId': self.pipeline_execution_id,
262
- 'triggerId': self.trigger_id,
263
- },
264
- 'eventType': self.event_type,
265
- 'action': self.action,
266
- 'data': {
267
- 'status': self.status,
268
- 'nodeId': self.pipeline_node_id,
269
- 'nodeStatus': self.node_status
270
- }
271
- }
272
- return _json
280
+ _json = super().to_json()
281
+ _json['context'].update({
282
+ 'accountId': self.account_id,
283
+ 'pipelineNodeId': self.pipeline_node_id,
284
+ 'pipelineExecutionId': self.pipeline_execution_id,
285
+ 'triggerId': self.trigger_id
286
+ })
287
+ _json['data'].update({
288
+ 'nodeStatus': self.node_status
289
+ })
290
+ _json['context'] = {k: v for k, v in _json['context'].items() if v is not None}
291
+ _json['data'] = {k: v for k, v in _json['data'].items() if v is not None}
292
+ return {k: v for k, v in _json.items() if v is not None}
273
293
 
274
294
  @classmethod
275
295
  def from_json(cls, _json):
@@ -418,28 +418,25 @@ class Annotation(entities.BaseEntity):
418
418
  def label(self, label):
419
419
  self.annotation_definition.label = label
420
420
 
421
- @property
422
- def _use_attributes_2(self):
423
- if self.__client_api is None and self._item is None:
424
- return os.environ.get("USE_ATTRIBUTE_2", 'false') == 'true'
425
- return self._client_api.attributes_mode.use_attributes_2
426
-
427
421
  @property
428
422
  def attributes(self):
429
- return self._recipe_2_attributes if self._use_attributes_2 else self.annotation_definition.attributes
423
+ if self._recipe_2_attributes or not self.annotation_definition.attributes:
424
+ return self._recipe_2_attributes
425
+ return self.annotation_definition.attributes
430
426
 
431
427
  @attributes.setter
432
428
  def attributes(self, attributes):
433
- if self._use_attributes_2:
434
- if not isinstance(attributes, dict):
435
- raise ValueError(
436
- 'Attributes must be a dict. If you are using v1 attributes please use dl.use_attributes_2(False)')
429
+ if isinstance(attributes, dict):
437
430
  self._recipe_2_attributes = attributes
438
- else:
439
- if not isinstance(attributes, list):
440
- raise ValueError(
441
- 'Attributes must be a list. If you are using v2 attributes please use dl.use_attributes_2(True)')
431
+ elif isinstance(attributes, list):
442
432
  self.annotation_definition.attributes = attributes
433
+ elif attributes is None:
434
+ if self._recipe_2_attributes:
435
+ self._recipe_2_attributes = {}
436
+ if self.annotation_definition.attributes:
437
+ self.annotation_definition.attributes = []
438
+ else:
439
+ raise ValueError('Attributes must be a dictionary or a list')
443
440
 
444
441
  @property
445
442
  def color(self):
@@ -1362,12 +1359,8 @@ class Annotation(entities.BaseEntity):
1362
1359
  object_id = _json['metadata']['system'].get('objectId', object_id)
1363
1360
  status = _json['metadata']['system'].get('status', status)
1364
1361
 
1365
- if client_api is not None:
1366
- recipe_2_attributes = client_api.attributes_mode.use_attributes_2
1367
- else:
1368
- recipe_2_attributes = False
1369
1362
  named_attributes = metadata.get('system', dict()).get('attributes', None)
1370
- attributes = named_attributes if recipe_2_attributes else _json.get('attributes', None)
1363
+ attributes = named_attributes if named_attributes else _json.get('attributes', None)
1371
1364
 
1372
1365
  first_frame_attributes = attributes
1373
1366
  first_frame_coordinates = list()
@@ -1598,7 +1591,7 @@ class Annotation(entities.BaseEntity):
1598
1591
  if isinstance(self.annotation_definition, entities.Description):
1599
1592
  _json['metadata']['system']['system'] = True
1600
1593
 
1601
- if self._use_attributes_2:
1594
+ if self._recipe_2_attributes is not None:
1602
1595
  _json['metadata']['system']['attributes'] = self._recipe_2_attributes
1603
1596
  if 'attributes' in self._platform_dict:
1604
1597
  _json['attributes'] = self._platform_dict['attributes']
@@ -1685,20 +1678,18 @@ class FrameAnnotation(entities.BaseEntity):
1685
1678
 
1686
1679
  @property
1687
1680
  def attributes(self):
1688
- return self._recipe_2_attributes if self.annotation._use_attributes_2 else self.annotation_definition.attributes
1681
+ if self._recipe_2_attributes or not self.annotation_definition.attributes:
1682
+ return self._recipe_2_attributes
1683
+ return self.annotation_definition.attributes
1689
1684
 
1690
1685
  @attributes.setter
1691
1686
  def attributes(self, attributes):
1692
- if self.annotation._use_attributes_2:
1693
- if not isinstance(attributes, dict):
1694
- raise ValueError(
1695
- 'Attributes must be a dict. If you are using v1 attributes please use dl.use_attributes_2(False)')
1687
+ if isinstance(attributes, dict):
1696
1688
  self._recipe_2_attributes = attributes
1697
- else:
1698
- if not isinstance(attributes, list):
1699
- raise ValueError(
1700
- 'Attributes must be a list. If you are using v2 attributes please use dl.use_attributes_2(True)')
1689
+ elif isinstance(attributes, list):
1701
1690
  self.annotation_definition.attributes = attributes
1691
+ else:
1692
+ raise ValueError('Attributes must be a dictionary or a list')
1702
1693
 
1703
1694
  @property
1704
1695
  def geo(self):
@@ -1879,7 +1870,7 @@ class FrameAnnotation(entities.BaseEntity):
1879
1870
  'data': self.coordinates
1880
1871
  }
1881
1872
 
1882
- if self.annotation._use_attributes_2:
1873
+ if self.annotation._recipe_2_attributes:
1883
1874
  snapshot_dict['namedAttributes'] = self._recipe_2_attributes
1884
1875
  else:
1885
1876
  snapshot_dict['attributes'] = self.attributes
@@ -63,7 +63,7 @@ class AnnotationCollection(entities.BaseEntity):
63
63
  """
64
64
  Add annotations to collection
65
65
 
66
- :param annotation_definition: dl.Polygon, dl.Segmentation, dl.Point, dl.Box etc
66
+ :param annotation_definition: dl.Polygon, dl.Segmentation, dl.Point, dl.Box etc.
67
67
  :param object_id: Object id (any id given by user). If video - must input to match annotations between frames
68
68
  :param frame_num: video only, number of frame
69
69
  :param end_frame_num: video only, the end frame of the annotation
@@ -72,12 +72,12 @@ class AnnotationCollection(entities.BaseEntity):
72
72
  :param automated:
73
73
  :param fixed: video only, mark frame as fixed
74
74
  :param object_visible: video only, does the annotated object is visible
75
- :param metadata: optional- metadata dictionary for annotation
75
+ :param metadata: optional, metadata dictionary for annotation
76
76
  :param parent_id: set a parent for this annotation (parent annotation ID)
77
77
  :param prompt_id: Connect the annotation with a specific prompt in a dl.PromptItem
78
- :param model_info: optional - set model on annotation {'confidence':0 [Mandatory], (Float between 0-1)
79
- 'name',:'' [Optional], ('name' refers to 'model_name')
80
- 'model_id':''[Optional]}
78
+ :param model_info: optional - set model on annotation {'confidence': 0, # [Mandatory], (Float between 0-1)
79
+ 'name': '', # [Optional], ('name' refers to 'model_name')
80
+ 'model_id': ''} # [Optional]
81
81
  :return:
82
82
  """
83
83
  if model_info is not None:
@@ -163,7 +163,7 @@ class AnnotationCollection(entities.BaseEntity):
163
163
  annotation_format: entities.ViewAnnotationOptions = entities.ViewAnnotationOptions.MASK,
164
164
  label_instance_dict=None,
165
165
  color=None,
166
- alpha=1,
166
+ alpha=1.,
167
167
  frame_num=None):
168
168
  """
169
169
  Show annotations according to annotation_format
@@ -188,8 +188,7 @@ class AnnotationCollection(entities.BaseEntity):
188
188
 
189
189
  image = builder.show(image='ndarray',
190
190
  thickness=1,
191
- annotation_format=dl.VIEW_ANNOTATION_OPTIONS_MASK,
192
- )
191
+ annotation_format=dl.VIEW_ANNOTATION_OPTIONS_MASK)
193
192
  """
194
193
  # if 'video' in self.item.mimetype and (annotation_format != 'json' or annotation_format != ['json']):
195
194
  # raise PlatformException('400', 'Cannot show mask or instance of video item')
@@ -210,7 +209,7 @@ class AnnotationCollection(entities.BaseEntity):
210
209
  else:
211
210
  rest_annotations.append(annotation)
212
211
  all_annotations = segment_annotations + rest_annotations
213
- # gor over all annotations and put the id where the annotations is
212
+ # gor over all annotations and put the id where the annotations are
214
213
  for annotation in all_annotations:
215
214
  # get the mask of the annotation
216
215
  image = annotation.show(thickness=thickness,
@@ -231,7 +230,7 @@ class AnnotationCollection(entities.BaseEntity):
231
230
  thickness=1,
232
231
  annotation_format=entities.ViewAnnotationOptions.ANNOTATION_ON_IMAGE,
233
232
  with_text=False,
234
- alpha=1):
233
+ alpha=1.):
235
234
  """
236
235
  create a video from frames
237
236
 
@@ -240,6 +239,8 @@ class AnnotationCollection(entities.BaseEntity):
240
239
  :param thickness: int - thickness of the annotations
241
240
  :param annotation_format: str - ViewAnnotationOptions - annotations format
242
241
  :param with_text: bool - if True show the label in the output
242
+ :param float alpha: opacity value [0 1], default 1
243
+
243
244
  """
244
245
  try:
245
246
  import cv2
@@ -288,7 +289,8 @@ class AnnotationCollection(entities.BaseEntity):
288
289
  if reader is not None:
289
290
  reader.release()
290
291
 
291
- def _set_flip_args(self, orientation):
292
+ @staticmethod
293
+ def _set_flip_args(orientation):
292
294
  try:
293
295
  import cv2
294
296
  except (ImportError, ModuleNotFoundError):
@@ -329,10 +331,10 @@ class AnnotationCollection(entities.BaseEntity):
329
331
  :param int height: height
330
332
  :param int width: width
331
333
  :param int thickness: thickness
332
- :param bool with_text: add a text to the image
334
+ :param bool with_text: add a text to an image
333
335
  :param int orientation: the image orientation
334
336
  :param float alpha: opacity value [0 1], default 1
335
- :return: file path of the downlaod annotation
337
+ :return: file path of the download annotation
336
338
  :rtype: str
337
339
 
338
340
  **Example**:
@@ -521,8 +523,8 @@ class AnnotationCollection(entities.BaseEntity):
521
523
  :param dict _json: platform json
522
524
  :param dtlpy.entities.item.Item item: item
523
525
  :param client_api: ApiClient entity
524
- :param bool is_video: is video
525
- :param fps: video fps
526
+ :param bool is_video: whether the item is video
527
+ :param fps: frame rate of the video
526
528
  :param float height: height
527
529
  :param float width: width
528
530
  :param bool is_audio: is audio
@@ -614,19 +616,15 @@ class AnnotationCollection(entities.BaseEntity):
614
616
  start_time = datetime.timedelta(hours=float(h), minutes=float(m), seconds=float(s)).total_seconds()
615
617
  h, m, s = caption.end.split(':')
616
618
  end_time = datetime.timedelta(hours=float(h), minutes=float(m), seconds=float(s)).total_seconds()
617
- if self.item.fps is not None:
618
- start_frame = round(start_time * self.item.fps)
619
- else:
620
- raise ValueError('Item do not have fps, please wait for video-preprocess to complete')
621
619
  annotation_definition = entities.Subtitle(text=caption.text, label='Text')
622
620
  annotation = entities.Annotation.new(
623
621
  annotation_definition=annotation_definition,
624
- frame_num=start_frame,
625
622
  item=self.item,
626
623
  start_time=start_time)
627
624
 
628
625
  annotation.add_frames(annotation_definition=annotation_definition,
629
- frame_num=start_frame, end_time=end_time)
626
+ start_time=start_time,
627
+ end_time=end_time)
630
628
 
631
629
  self.annotations.append(annotation)
632
630
 
dtlpy/entities/app.py CHANGED
@@ -47,6 +47,7 @@ class App(entities.BaseEntity):
47
47
  custom_installation = attr.ib(type=dict)
48
48
  metadata = attr.ib(type=dict)
49
49
  status = attr.ib(type=entities.CompositionStatus)
50
+ settings = attr.ib(type=dict)
50
51
 
51
52
  # sdk
52
53
  _project = attr.ib(type=entities.Project, repr=False)
@@ -55,10 +56,11 @@ class App(entities.BaseEntity):
55
56
 
56
57
  @_repositories.default
57
58
  def set_repositories(self):
58
- reps = namedtuple('repositories', field_names=['projects', 'apps'])
59
+ reps = namedtuple('repositories', field_names=['projects', 'apps', 'compositions'])
59
60
  return reps(
60
61
  projects=repositories.Projects(client_api=self._client_api),
61
- apps=repositories.Apps(client_api=self._client_api, project=self._project)
62
+ apps=repositories.Apps(client_api=self._client_api, project=self._project),
63
+ compositions=repositories.Compositions(client_api=self._client_api, project=self._project)
62
64
  )
63
65
 
64
66
  @property
@@ -77,6 +79,11 @@ class App(entities.BaseEntity):
77
79
  assert isinstance(self._repositories.apps, repositories.Apps)
78
80
  return self._repositories.apps
79
81
 
82
+ @property
83
+ def compositions(self):
84
+ assert isinstance(self._repositories.compositions, repositories.Compositions)
85
+ return self._repositories.compositions
86
+
80
87
  def uninstall(self):
81
88
  """
82
89
  Uninstall an app installed app from the project.
@@ -177,6 +184,8 @@ class App(entities.BaseEntity):
177
184
  _json['metadata'] = self.metadata
178
185
  if self.status is not None:
179
186
  _json['status'] = self.status
187
+ if self.settings != {}:
188
+ _json['settings'] = self.settings
180
189
 
181
190
  return _json
182
191
 
@@ -200,7 +209,8 @@ class App(entities.BaseEntity):
200
209
  client_api=client_api,
201
210
  project=project,
202
211
  metadata=_json.get('metadata', None),
203
- status=_json.get('status', None)
212
+ status=_json.get('status', None),
213
+ settings=_json.get('settings', {})
204
214
  )
205
215
  app.is_fetched = is_fetched
206
216
  return app
@@ -19,6 +19,8 @@ class Assignment(entities.BaseEntity):
19
19
  metadata = attr.ib(repr=False)
20
20
  id = attr.ib()
21
21
  url = attr.ib(repr=False)
22
+ updated_at = attr.ib(repr=False)
23
+ updated_by = attr.ib(repr=False)
22
24
  task_id = attr.ib(repr=False)
23
25
  dataset_id = attr.ib(repr=False)
24
26
  annotation_status = attr.ib(repr=False)
@@ -62,6 +64,8 @@ class Assignment(entities.BaseEntity):
62
64
  metadata=metadata,
63
65
  url=_json.get('url', None),
64
66
  id=_json['id'],
67
+ updated_by=_json.get('updatedBy', None),
68
+ updated_at=_json.get('updatedAt', None),
65
69
  client_api=client_api,
66
70
  project=project,
67
71
  dataset=dataset,
@@ -143,6 +147,8 @@ class Assignment(entities.BaseEntity):
143
147
  attr.fields(Assignment)._dataset,
144
148
  attr.fields(Assignment)._task,
145
149
  attr.fields(Assignment).annotation_status,
150
+ attr.fields(Assignment).updated_at,
151
+ attr.fields(Assignment).updated_by,
146
152
  attr.fields(Assignment).item_status,
147
153
  attr.fields(Assignment).total_items,
148
154
  attr.fields(Assignment).for_review,
@@ -98,22 +98,6 @@ class DlEntity(object):
98
98
  """
99
99
  return miscellaneous.List([self]).to_df(show_all=show_all, columns=columns)
100
100
 
101
- # def __repr__(self):
102
- # string = '{}('.format(self.__class__.__name__)
103
- # for prop in dir(self):
104
- # if isinstance(prop, DlProperty) and prop.repr is True:
105
- # string += '{}={}'.format()
106
- # params = json.dumps(self._dict, indent=4)
107
- # return "{}({})".format(self.__class__.__name__, params)
108
-
109
- # def __repr__(self):
110
- # self.print()
111
-
112
- # def __getattribute__(self, attr):
113
- # if super(BaseEntity, self).__getattribute__(attr) is None:
114
- # pass
115
- # return super(BaseEntity, self).__getattribute__(attr)
116
-
117
101
 
118
102
  class DlProperty:
119
103
  def __init__(self, location=None, default='NODEFAULT', _type=None, _kls=None):
@@ -206,16 +190,9 @@ class DlProperty:
206
190
 
207
191
  # instantiate dictionary to the type
208
192
  value = self._to_instance(_dict=value)
209
-
210
- # isinstance(value, typing_extensions.get_args(self._type))
211
193
  return value
212
194
 
213
195
  def __set__(self, instance, value):
214
- # TODO still not working properly. need to fix this validation
215
- # if not isinstance(value, typing_extensions.get_args(self._type)):
216
- # logger.warning(
217
- # f'Incorrect typing for type: {type(instance)}. {self.location} must be of type {self._type}. Received: {type(value)}')
218
- _client_api = getattr(instance, 'client_api', None)
219
196
 
220
197
  # validate - if validator is set
221
198
  if self._validator is not None:
dtlpy/entities/dataset.py CHANGED
@@ -240,7 +240,7 @@ class Dataset(entities.BaseEntity):
240
240
 
241
241
  @property
242
242
  def platform_url(self):
243
- return self._client_api._get_resource_url("projects/{}/datasets/{}".format(self.project.id, self.id))
243
+ return self._client_api._get_resource_url("projects/{}/datasets/{}/items".format(self.project.id, self.id))
244
244
 
245
245
  @readonly.setter
246
246
  def readonly(self, state):