supervisely 6.73.199__py3-none-any.whl → 6.73.200__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.

Potentially problematic release.


This version of supervisely might be problematic. Click here for more details.

@@ -14,6 +14,7 @@ from supervisely.api.module_api import (
14
14
  UpdateableModule,
15
15
  _get_single_item,
16
16
  )
17
+ from supervisely.project.project_type import ProjectType
17
18
 
18
19
 
19
20
  class DatasetInfo(NamedTuple):
@@ -418,6 +419,13 @@ class DatasetApi(UpdateableModule, RemoveableModuleApi):
418
419
  raise RuntimeError(
419
420
  'Can not match "ids" and "new_names" lists, len(ids) != len(new_names)'
420
421
  )
422
+ project_info = self._api.project.get_info_by_id(dst_project_id)
423
+ if project_info.type == str(ProjectType.IMAGES):
424
+ items_api = self._api.image
425
+ elif project_info.type == str(ProjectType.VIDEOS):
426
+ items_api = self._api.video
427
+ else:
428
+ raise RuntimeError(f"Unsupported project type: {project_info.type}")
421
429
 
422
430
  new_datasets = []
423
431
  for idx, dataset_id in enumerate(ids):
@@ -425,16 +433,16 @@ class DatasetApi(UpdateableModule, RemoveableModuleApi):
425
433
  new_dataset_name = dataset.name
426
434
  if new_names is not None:
427
435
  new_dataset_name = new_names[idx]
428
- src_images = self._api.image.get_list(dataset.id)
429
- src_image_ids = [image.id for image in src_images]
436
+ src_items = items_api.get_list(dataset.id)
437
+ src_item_ids = [item.id for item in src_items]
430
438
  new_dataset = self._api.dataset.create(
431
439
  dst_project_id,
432
440
  new_dataset_name,
433
441
  dataset.description,
434
442
  change_name_if_conflict=change_name_if_conflict,
435
443
  )
436
- self._api.image.copy_batch(
437
- new_dataset.id, src_image_ids, change_name_if_conflict, with_annotations
444
+ items_api.copy_batch(
445
+ new_dataset.id, src_item_ids, change_name_if_conflict, with_annotations
438
446
  )
439
447
  new_datasets.append(new_dataset)
440
448
  return new_datasets
@@ -6,6 +6,7 @@ from typing import Callable, Dict, List, Optional, Union
6
6
 
7
7
  from tqdm import tqdm
8
8
 
9
+ from supervisely._utils import batched
9
10
  from supervisely.api.entity_annotation.entity_annotation_api import EntityAnnotationAPI
10
11
  from supervisely.api.module_api import ApiField
11
12
  from supervisely.io.json import load_json_file
@@ -182,3 +183,67 @@ class VideoAnnotationAPI(EntityAnnotationAPI):
182
183
  self.append(video_id, ann)
183
184
  if progress_cb is not None:
184
185
  progress_cb(1)
186
+
187
+ def copy_batch(
188
+ self,
189
+ src_video_ids: List[int],
190
+ dst_video_ids: List[int],
191
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
192
+ ) -> None:
193
+ """
194
+ Copy annotations from one images IDs to another in API.
195
+
196
+ :param src_video_ids: Images IDs in Supervisely.
197
+ :type src_video_ids: List[int]
198
+ :param dst_video_ids: Unique IDs of images in API.
199
+ :type dst_video_ids: List[int]
200
+ :param progress_cb: Function for tracking download progress.
201
+ :type progress_cb: tqdm or callable, optional
202
+ :raises: :class:`RuntimeError`, if len(src_video_ids) != len(dst_video_ids)
203
+ :return: None
204
+ :rtype: :class:`NoneType`
205
+
206
+ :Usage example:
207
+
208
+ .. code-block:: python
209
+
210
+ import supervisely as sly
211
+ from tqdm import tqdm
212
+
213
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
214
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
215
+ api = sly.Api.from_env()
216
+
217
+ src_ids = [121236918, 121236919]
218
+ dst_ids = [547837053, 547837054]
219
+ p = tqdm(desc="Annotations copy: ", total=len(src_ids))
220
+
221
+ copy_anns = api.annotation.copy_batch(src_ids, dst_ids, progress_cb=p)
222
+ # Output:
223
+ # {"message": "progress", "event_type": "EventType.PROGRESS", "subtask": "Annotations copy: ", "current": 0, "total": 2, "timestamp": "2021-03-16T15:24:31.286Z", "level": "info"}
224
+ # {"message": "progress", "event_type": "EventType.PROGRESS", "subtask": "Annotations copy: ", "current": 2, "total": 2, "timestamp": "2021-03-16T15:24:31.288Z", "level": "info"}
225
+ """
226
+ if len(src_video_ids) != len(dst_video_ids):
227
+ raise RuntimeError(
228
+ 'Can not match "src_video_ids" and "dst_video_ids" lists, '
229
+ "len(src_video_ids) != len(dst_video_ids)"
230
+ )
231
+ if len(src_video_ids) == 0:
232
+ return
233
+
234
+ src_dataset_id = self._api.video.get_info_by_id(src_video_ids[0]).dataset_id
235
+ dst_dataset_id = self._api.video.get_info_by_id(dst_video_ids[0]).dataset_id
236
+ dst_dataset_info = self._api.dataset.get_info_by_id(dst_dataset_id)
237
+ dst_project_meta = ProjectMeta.from_json(
238
+ self._api.project.get_meta(dst_dataset_info.project_id)
239
+ )
240
+ for src_ids_batch, dst_ids_batch in batched(list(zip(src_video_ids, dst_video_ids))):
241
+ ann_jsons = self.download_bulk(src_dataset_id, src_ids_batch)
242
+ for dst_id, ann_json in zip(dst_ids_batch, ann_jsons):
243
+ try:
244
+ ann = VideoAnnotation.from_json(ann_json, dst_project_meta)
245
+ except Exception as e:
246
+ raise RuntimeError("Failed to validate Annotation") from e
247
+ self.append(dst_id, ann)
248
+ if progress_cb is not None:
249
+ progress_cb(1)
@@ -950,6 +950,91 @@ class VideoApi(RemoveableBulkModuleApi):
950
950
 
951
951
  return result
952
952
 
953
+ def copy_batch(
954
+ self,
955
+ dst_dataset_id: int,
956
+ ids: List[int],
957
+ change_name_if_conflict: Optional[bool] = False,
958
+ with_annotations: Optional[bool] = False,
959
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
960
+ ) -> List[VideoInfo]:
961
+ """
962
+ Copies Videos with given IDs to Dataset.
963
+
964
+ :param dst_dataset_id: Destination Dataset ID in Supervisely.
965
+ :type dst_dataset_id: int
966
+ :param ids: Videos IDs in Supervisely.
967
+ :type ids: List[int]
968
+ :param change_name_if_conflict: If True adds suffix to the end of Image name when Dataset already contains an Image with identical name, If False and images with the identical names already exist in Dataset raises error.
969
+ :type change_name_if_conflict: bool, optional
970
+ :param with_annotations: If True Image will be copied to Dataset with annotations, otherwise only Images without annotations.
971
+ :type with_annotations: bool, optional
972
+ :param progress_cb: Function for tracking the progress of copying.
973
+ :type progress_cb: tqdm or callable, optional
974
+ :raises: :class:`TypeError` if type of ids is not list
975
+ :raises: :class:`ValueError` if videos ids are from the destination Dataset
976
+ :return: List with information about Videos. See :class:`info_sequence<info_sequence>`
977
+ :rtype: :class:`List[VideoInfo]`
978
+ :Usage example:
979
+
980
+ .. code-block:: python
981
+
982
+ import supervisely as sly
983
+
984
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
985
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
986
+ api = sly.Api.from_env()
987
+
988
+ dataset_id = 1780
989
+
990
+ video_infos = api.video.get_list(dataset_id)
991
+
992
+ video_ids = [video_info.id for video_info in video_infos]
993
+
994
+ destination_dataset_id = 2574
995
+ destination_video_infos = api.video.copy_batch(destination_dataset_id, video_ids, with_annotations=True)
996
+ """
997
+ if type(ids) is not list:
998
+ raise TypeError(
999
+ "ids parameter has type {!r}. but has to be of type {!r}".format(type(ids), list)
1000
+ )
1001
+
1002
+ if len(ids) == 0:
1003
+ return
1004
+
1005
+ ids_info = self.get_info_by_id_batch(ids, force_metadata_for_links=False)
1006
+ if len(set(vid_info.dataset_id for vid_info in ids_info)) > 1:
1007
+ raise ValueError("Videos ids have to be from the same dataset")
1008
+
1009
+ existing_videos = self.get_list(dst_dataset_id)
1010
+ existing_names = {video.name for video in existing_videos}
1011
+
1012
+ if change_name_if_conflict:
1013
+ new_names = [
1014
+ generate_free_name(existing_names, info.name, with_ext=True, extend_used_names=True)
1015
+ for info in ids_info
1016
+ ]
1017
+ else:
1018
+ new_names = [info.name for info in ids_info]
1019
+ names_intersection = existing_names.intersection(set(new_names))
1020
+ if len(names_intersection) != 0:
1021
+ raise ValueError(
1022
+ "Videos with the same names already exist in destination dataset. "
1023
+ 'Please, use argument "change_name_if_conflict=True" to automatically resolve '
1024
+ "names intersection"
1025
+ )
1026
+
1027
+ new_videos = self.upload_ids(dst_dataset_id, new_names, ids, progress_cb=progress_cb)
1028
+ new_ids = [new_video.id for new_video in new_videos]
1029
+
1030
+ if with_annotations:
1031
+ src_project_id = self._api.dataset.get_info_by_id(ids_info[0].dataset_id).project_id
1032
+ dst_project_id = self._api.dataset.get_info_by_id(dst_dataset_id).project_id
1033
+ self._api.project.merge_metas(src_project_id, dst_project_id)
1034
+ self._api.video.annotation.copy_batch(ids, new_ids)
1035
+
1036
+ return new_videos
1037
+
953
1038
  def _upload_bulk_add(
954
1039
  self, func_item_to_kv, dataset_id, names, items, metas=None, progress_cb=None
955
1040
  ):
@@ -4,6 +4,7 @@
4
4
  style="width: {{{widget._width}}}"
5
5
  :content="data.{{{widget.widget_id}}}.table_data"
6
6
  :options="data.{{{widget.widget_id}}}.table_options"
7
+ :sort="state.{{{widget.widget_id}}}.sort"
7
8
  {%
8
9
  if
9
10
  widget._click_handled
@@ -11,12 +12,11 @@
11
12
  :value="state.{{{widget.widget_id}}}.selected_row"
12
13
  @input="state.{{{widget.widget_id}}}.selected_row = $event;
13
14
  post('/{{{widget.widget_id}}}/cell_clicked_cb')"
15
+ @update:sort="state.{{{widget.widget_id}}}.sort = $event;
16
+ post('/{{{widget.widget_id}}}/update_sort_cb')"
14
17
  {%
15
18
  endif
16
19
  %}
17
- :sort="state.{{{widget.widget_id}}}.sort"
18
- @update:sort="state.{{{widget.widget_id}}}.sort = $event;
19
- post('/{{{widget.widget_id}}}/update_sort_cb')"
20
20
  >
21
21
  </sly-table>
22
22
  <div v-if="data.{{{widget.widget_id}}}.table_data.data.length === 0">
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.199
3
+ Version: 6.73.200
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -24,7 +24,7 @@ supervisely/api/agent_api.py,sha256=ShWAIlXcWXcyI9fqVuP5GZVCigCMJmjnvdGUfLspD6Y,
24
24
  supervisely/api/annotation_api.py,sha256=Eps-Jf10_SQFy7DjghUnyiM6DcVJBsamHDViRAXv2fg,51403
25
25
  supervisely/api/api.py,sha256=u2T0yOQ-tUnP3iIzFu8zEQb4t_EDrXQSKnaXHCvFDyg,36514
26
26
  supervisely/api/app_api.py,sha256=zX3Iy16RuGwtcLZfMs3YfUFc93S9AVGb3W_eINeMjOs,66729
27
- supervisely/api/dataset_api.py,sha256=5di6OiBti9AMTd2bfjkHnO4uocEzAUPDra-P6qG9aQc,37542
27
+ supervisely/api/dataset_api.py,sha256=7iwAyz3pmzFG2i072gLdXjczfBGbyj-V_rRl7Tx-V30,37944
28
28
  supervisely/api/file_api.py,sha256=ouqhqlFbBjxbpuf1hvUAJPIfabnxIzHqL3JDu-lUmHI,53094
29
29
  supervisely/api/github_api.py,sha256=NIexNjEer9H5rf5sw2LEZd7C1WR-tK4t6IZzsgeAAwQ,623
30
30
  supervisely/api/image_annotation_tool_api.py,sha256=YcUo78jRDBJYvIjrd-Y6FJAasLta54nnxhyaGyanovA,5237
@@ -63,8 +63,8 @@ supervisely/api/pointcloud/pointcloud_figure_api.py,sha256=r1sk3g9IgYVHuNhxyZT1T
63
63
  supervisely/api/pointcloud/pointcloud_object_api.py,sha256=bO1USWb9HAywG_CW4CDu1HLu6l58OqQFuD3ikS9F3bM,5130
64
64
  supervisely/api/pointcloud/pointcloud_tag_api.py,sha256=iShtr052nOElxsyMyZEUT2vypEm6kP00gnP13ABX24A,4691
65
65
  supervisely/api/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
- supervisely/api/video/video_annotation_api.py,sha256=6lG2Y7VvxEPNY9x18rg4M9InAoAHq0_9W8RHPaln86E,6361
67
- supervisely/api/video/video_api.py,sha256=caqot3B1qBV5XGE_KnJ9Nluj1kF7SkiD9fRA9FxxJ2g,78790
66
+ supervisely/api/video/video_annotation_api.py,sha256=DwZh11fBLa_AWwdYbpbSH1ZGh_5TFfLJiPKcXuOVc14,9319
67
+ supervisely/api/video/video_api.py,sha256=4XrV-sAhsskSvYT6Lu1AILjAkmCumIOetb-NHUtcbjc,82597
68
68
  supervisely/api/video/video_figure_api.py,sha256=quksohjhgrK2l2-PtbbNE99fOW6uWXX59-_4xfc-I-k,6244
69
69
  supervisely/api/video/video_frame_api.py,sha256=4GwSI4xdCNYEUvTqzKc-Ewd44fw5zqkFoD24jrrN_aY,10214
70
70
  supervisely/api/video/video_object_api.py,sha256=IC0NP8EoIT_d3xxDRgz2cA3ixSiuJ5ymy64eS-RfmDM,2227
@@ -466,7 +466,7 @@ supervisely/app/widgets/switch/switch.py,sha256=k0oWbMjN9-ak1UcqBBEC3-yeJlEfiF4i
466
466
  supervisely/app/widgets/switch/template.html,sha256=Hqo565LsnWlq5fK13KZ04aLNaqr1kbZDQX8JPJnR5e4,462
467
467
  supervisely/app/widgets/table/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
468
468
  supervisely/app/widgets/table/table.py,sha256=knuSWJM5sBHfePYDFD4MVuGUM8W3oQgBQzyfWLYhr3g,16750
469
- supervisely/app/widgets/table/template.html,sha256=aOtGkX6T-Zg8rA-_HjQ-1tUNviObolH2ZxJw_cjBnmE,778
469
+ supervisely/app/widgets/table/template.html,sha256=f895pzZzrc2dMN7ZFZ9iywQjxS2bWvSMIJxdqFbFL8k,778
470
470
  supervisely/app/widgets/tabs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
471
471
  supervisely/app/widgets/tabs/tabs.py,sha256=9TcBFyDEiOkNdHPrhodNuRAe_3bTGrUgb1vavYhsYJo,2356
472
472
  supervisely/app/widgets/tabs/template.html,sha256=kVesXGZrIR_YjqhLMwbbpzEku0FR3GAyPGGtEWh5OuU,402
@@ -953,9 +953,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
953
953
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
954
954
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
955
955
  supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
956
- supervisely-6.73.199.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
957
- supervisely-6.73.199.dist-info/METADATA,sha256=P_MB6rbtG8u9TNCV7jK84uRVaC4JRTPZWKkziTL8VdE,33077
958
- supervisely-6.73.199.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
959
- supervisely-6.73.199.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
960
- supervisely-6.73.199.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
961
- supervisely-6.73.199.dist-info/RECORD,,
956
+ supervisely-6.73.200.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
957
+ supervisely-6.73.200.dist-info/METADATA,sha256=7nxrYfel8T-VAi0k_ist_K7npAJifyIQe2Wwv9H0ip0,33077
958
+ supervisely-6.73.200.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
959
+ supervisely-6.73.200.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
960
+ supervisely-6.73.200.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
961
+ supervisely-6.73.200.dist-info/RECORD,,