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

@@ -1021,13 +1021,66 @@ class DatasetApi(UpdateableModule, RemoveableModuleApi):
1021
1021
 
1022
1022
  return dataset_tree
1023
1023
 
1024
- def tree(self, project_id: int) -> Generator[Tuple[List[str], DatasetInfo], None, None]:
1024
+ def _yield_tree(
1025
+ self, tree: Dict[DatasetInfo, Dict], path: List[str]
1026
+ ) -> Generator[Tuple[List[str], DatasetInfo], None, None]:
1027
+ """
1028
+ Helper method for recursive tree traversal.
1029
+ Yields tuples of (path, dataset) for all datasets in the tree. For each node (dataset) at the current level,
1030
+ yields its (path, dataset) before recursively traversing and yielding from its children.
1031
+
1032
+ :param tree: Tree structure to yield from.
1033
+ :type tree: Dict[DatasetInfo, Dict]
1034
+ :param path: Current path (used for recursion).
1035
+ :type path: List[str]
1036
+ :return: Generator of tuples of (path, dataset).
1037
+ :rtype: Generator[Tuple[List[str], DatasetInfo], None, None]
1038
+ """
1039
+ for dataset, children in tree.items():
1040
+ yield path, dataset
1041
+ new_path = path + [dataset.name]
1042
+ if children:
1043
+ yield from self._yield_tree(children, new_path)
1044
+
1045
+ def _find_dataset_in_tree(
1046
+ self, tree: Dict[DatasetInfo, Dict], target_id: int, path: List[str] = None
1047
+ ) -> Tuple[Optional[DatasetInfo], Optional[Dict], List[str]]:
1048
+ """Find a specific dataset in the tree and return its subtree and path.
1049
+
1050
+ :param tree: Tree structure to search in.
1051
+ :type tree: Dict[DatasetInfo, Dict]
1052
+ :param target_id: ID of the dataset to find.
1053
+ :type target_id: int
1054
+ :param path: Current path (used for recursion).
1055
+ :type path: List[str], optional
1056
+ :return: Tuple of (found_dataset, its_subtree, path_to_dataset).
1057
+ :rtype: Tuple[Optional[DatasetInfo], Optional[Dict], List[str]]
1058
+ """
1059
+ if path is None:
1060
+ path = []
1061
+
1062
+ for dataset, children in tree.items():
1063
+ if dataset.id == target_id:
1064
+ return dataset, children, path
1065
+ # Search in children
1066
+ if children:
1067
+ found_dataset, found_children, found_path = self._find_dataset_in_tree(
1068
+ children, target_id, path + [dataset.name]
1069
+ )
1070
+ if found_dataset is not None:
1071
+ return found_dataset, found_children, found_path
1072
+ return None, None, []
1073
+
1074
+ def tree(self, project_id: int, dataset_id: Optional[int] = None) -> Generator[Tuple[List[str], DatasetInfo], None, None]:
1025
1075
  """Yields tuples of (path, dataset) for all datasets in the project.
1026
1076
  Path of the dataset is a list of parents, e.g. ["ds1", "ds2", "ds3"].
1027
1077
  For root datasets, the path is an empty list.
1028
1078
 
1029
1079
  :param project_id: Project ID in which the Dataset is located.
1030
1080
  :type project_id: int
1081
+ :param dataset_id: Optional Dataset ID to start the tree from. If provided, only yields
1082
+ the subtree starting from this dataset (including the dataset itself and all its children).
1083
+ :type dataset_id: Optional[int]
1031
1084
  :return: Generator of tuples of (path, dataset).
1032
1085
  :rtype: Generator[Tuple[List[str], DatasetInfo], None, None]
1033
1086
  :Usage example:
@@ -1040,11 +1093,17 @@ class DatasetApi(UpdateableModule, RemoveableModuleApi):
1040
1093
 
1041
1094
  project_id = 123
1042
1095
 
1096
+ # Get all datasets in the project
1043
1097
  for parents, dataset in api.dataset.tree(project_id):
1044
1098
  parents: List[str]
1045
1099
  dataset: sly.DatasetInfo
1046
1100
  print(parents, dataset.name)
1047
1101
 
1102
+ # Get only a specific branch starting from dataset_id = 456
1103
+ for parents, dataset in api.dataset.tree(project_id, dataset_id=456):
1104
+ parents: List[str]
1105
+ dataset: sly.DatasetInfo
1106
+ print(parents, dataset.name)
1048
1107
 
1049
1108
  # Output:
1050
1109
  # [] ds1
@@ -1052,17 +1111,20 @@ class DatasetApi(UpdateableModule, RemoveableModuleApi):
1052
1111
  # ["ds1", "ds2"] ds3
1053
1112
  """
1054
1113
 
1055
- def yield_tree(
1056
- tree: Dict[DatasetInfo, Dict], path: List[str]
1057
- ) -> Generator[Tuple[List[str], DatasetInfo], None, None]:
1058
- """Yields tuples of (path, dataset) for all datasets in the tree."""
1059
- for dataset, children in tree.items():
1060
- yield path, dataset
1061
- new_path = path + [dataset.name]
1062
- if children:
1063
- yield from yield_tree(children, new_path)
1064
-
1065
- yield from yield_tree(self.get_tree(project_id), [])
1114
+ full_tree = self.get_tree(project_id)
1115
+
1116
+ if dataset_id is None:
1117
+ # Return the full tree
1118
+ yield from self._yield_tree(full_tree, [])
1119
+ else:
1120
+ # Find the specific dataset and return only its subtree
1121
+ target_dataset, subtree, dataset_path = self._find_dataset_in_tree(full_tree, dataset_id)
1122
+ if target_dataset is not None:
1123
+ # Yield the target dataset first, then its children
1124
+ yield dataset_path, target_dataset
1125
+ if subtree:
1126
+ new_path = dataset_path + [target_dataset.name]
1127
+ yield from self._yield_tree(subtree, new_path)
1066
1128
 
1067
1129
  def get_nested(self, project_id: int, dataset_id: int) -> List[DatasetInfo]:
1068
1130
  """Returns a list of all nested datasets in the specified dataset.
@@ -329,6 +329,7 @@ class SelectDatasetTree(Widget):
329
329
  """
330
330
  if not self._multiselect:
331
331
  raise ValueError("This method can only be called when multiselect is enabled.")
332
+ self._select_all_datasets_checkbox.uncheck()
332
333
  self._select_dataset.set_selected_by_id(dataset_ids)
333
334
 
334
335
  def team_changed(self, func: Callable) -> Callable:
@@ -2,6 +2,9 @@ import threading
2
2
  from typing import Any, Dict, List
3
3
 
4
4
  from supervisely.api.api import Api
5
+ from supervisely.api.dataset_api import DatasetInfo
6
+ from supervisely.api.project_api import ProjectInfo
7
+ from supervisely.api.video.video_api import VideoInfo
5
8
  from supervisely.app.widgets import (
6
9
  Button,
7
10
  Card,
@@ -202,6 +205,53 @@ class InputSelector:
202
205
 
203
206
  self.select_video.add_rows(rows)
204
207
 
208
+ def select_project(self, project_id: int, project_info: ProjectInfo = None):
209
+ if project_info is None:
210
+ project_info = self.api.project.get_info_by_id(project_id)
211
+ if project_info.type == ProjectType.IMAGES.value:
212
+ self.select_dataset_for_images.set_project_id(project_id)
213
+ self.select_dataset_for_images.select_all()
214
+ self.radio.set_value(ProjectType.IMAGES.value)
215
+ elif project_info.type == ProjectType.VIDEOS.value:
216
+ self.select_dataset_for_video.set_project_id(project_id)
217
+ self.select_dataset_for_video.select_all()
218
+ self._refresh_video_table()
219
+ self.select_video.select_rows(list(range(len(self.select_video._rows_total))))
220
+ self.radio.set_value(ProjectType.VIDEOS.value)
221
+ else:
222
+ raise ValueError(f"Project of type {project_info.type} is not supported.")
223
+
224
+ def select_datasets(self, dataset_ids: List[int], dataset_infos: List[DatasetInfo] = None):
225
+ if dataset_infos is None:
226
+ dataset_infos = [self.api.dataset.get_info_by_id(ds_id) for ds_id in dataset_ids]
227
+ project_ids = set(ds.project_id for ds in dataset_infos)
228
+ if len(project_ids) > 1:
229
+ raise ValueError("Cannot select datasets from different projects")
230
+ project_id = project_ids.pop()
231
+ project_info = self.api.project.get_info_by_id(project_id)
232
+ if project_info.type == ProjectType.IMAGES.value:
233
+ self.select_dataset_for_images.set_project_id(project_id)
234
+ self.select_dataset_for_images.set_dataset_ids(dataset_ids)
235
+ self.radio.set_value(ProjectType.IMAGES.value)
236
+ elif project_info.type == ProjectType.VIDEOS.value:
237
+ self.select_dataset_for_video.set_project_id(project_id)
238
+ self.select_dataset_for_video.set_dataset_ids(dataset_ids)
239
+ self._refresh_video_table()
240
+ self.select_video.select_rows(list(range(self.select_video._rows_total)))
241
+ self.radio.set_value(ProjectType.VIDEOS.value)
242
+ else:
243
+ raise ValueError(f"Project of type {project_info.type} is not supported.")
244
+
245
+ def select_videos(self, video_ids: List[int], video_infos: List[VideoInfo] = None):
246
+ if video_infos is None:
247
+ video_infos = self.api.video.get_info_by_id_batch(video_ids)
248
+ project_id = video_infos[0].project_id
249
+ self.select_dataset_for_video.set_project_id(project_id)
250
+ self.select_dataset_for_video.select_all()
251
+ self._refresh_video_table()
252
+ self.select_video.select_row_by_value("id", video_ids)
253
+ self.radio.set_value(ProjectType.VIDEOS.value)
254
+
205
255
  def disable(self):
206
256
  for widget in self.widgets_to_disable:
207
257
  widget.disable()
@@ -249,37 +299,13 @@ class InputSelector:
249
299
  video_infos = self.api.video.get_info_by_id_batch(video_ids)
250
300
  if not video_infos:
251
301
  raise ValueError(f"Videos with video ids {video_ids} are not found")
252
- project_id = video_infos[0].project_id
253
- self.select_dataset_for_video.set_project_id(project_id)
254
- self.select_dataset_for_video.select_all()
255
- self.select_video.select_row_by_value("id", data["video_ids"])
256
- self.radio.set_value(ProjectType.VIDEOS.value)
302
+ self.select_videos(video_ids, video_infos)
257
303
  elif "dataset_ids" in data:
258
304
  dataset_ids = data["dataset_ids"]
259
- if len(dataset_ids) == 0:
260
- raise ValueError("Dataset ids cannot be empty")
261
- dataset_id = dataset_ids[0]
262
- dataset_info = self.api.dataset.get_info_by_id(dataset_id)
263
- project_info = self.api.project.get_info_by_id(dataset_info.project_id)
264
- if project_info.type == ProjectType.VIDEOS:
265
- self.select_dataset_for_video.set_project_id(project_info.id)
266
- self.select_dataset_for_video.set_dataset_ids(dataset_ids)
267
- self.radio.set_value(ProjectType.VIDEOS.value)
268
- else:
269
- self.select_dataset_for_images.set_project_id(project_info.id)
270
- self.select_dataset_for_images.set_dataset_ids(dataset_ids)
271
- self.radio.set_value(ProjectType.IMAGES.value)
305
+ self.select_datasets(dataset_ids)
272
306
  elif "project_id" in data:
273
307
  project_id = data["project_id"]
274
- project_info = self.api.project.get_info_by_id(project_id)
275
- if project_info.type == ProjectType.VIDEOS:
276
- self.select_dataset_for_video.set_project_id(project_id)
277
- self.select_dataset_for_video.select_all()
278
- self.radio.set_value(ProjectType.VIDEOS.value)
279
- else:
280
- self.select_dataset_for_images.set_project_id(project_id)
281
- self.select_dataset_for_images.select_all()
282
- self.radio.set_value(ProjectType.IMAGES.value)
308
+ self.select_project(project_id)
283
309
 
284
310
  def get_project_id(self) -> int:
285
311
  if self.radio.get_value() == ProjectType.IMAGES.value:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.464
3
+ Version: 6.73.466
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -26,7 +26,7 @@ supervisely/api/annotation_api.py,sha256=TNOqVGE94FqDc7WDLBZiDY3aSIiyTQwn_bZv5_C
26
26
  supervisely/api/api.py,sha256=_ZiC1R2lu2eHXw_vBMUiylr-jQcU9-nZZvH5jJHVqoc,68828
27
27
  supervisely/api/app_api.py,sha256=OMgmZM7I5nmTn7P9J0F6fpNwWnFE-UO3wzlL1Rciqh4,79038
28
28
  supervisely/api/constants.py,sha256=WfqIcEpRnU4Mcfb6q0njeRs2VVSoTAJaIyrqBkBjP8I,253
29
- supervisely/api/dataset_api.py,sha256=BD6kG2lj826ajWjHxmiKEsyWb2Ov6CyTQlItzAxADbo,48955
29
+ supervisely/api/dataset_api.py,sha256=VxJH59G_EApGeFCw-Eu4RB2qowb5wMIj0eHusvxeGKM,51946
30
30
  supervisely/api/entities_collection_api.py,sha256=Be13HsfMFLmq9XpiOfQog0Y569kbUn52hXv6x5vX3Vg,22624
31
31
  supervisely/api/file_api.py,sha256=gNXNsikocSYRojoZrVmXIqXycqXm0e320piAwaLN6JI,92978
32
32
  supervisely/api/github_api.py,sha256=NIexNjEer9H5rf5sw2LEZd7C1WR-tK4t6IZzsgeAAwQ,623
@@ -461,7 +461,7 @@ supervisely/app/widgets/select_dataset/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
461
461
  supervisely/app/widgets/select_dataset/select_dataset.py,sha256=S7zl83lUhquJ1U8GugiViEiGId6a5nVDfyIRRxh_LT4,10295
462
462
  supervisely/app/widgets/select_dataset/template.html,sha256=7O_ZgmRs0vOL8tng6QvYbI_0o6A4yMAPB2MlfzWHeHQ,984
463
463
  supervisely/app/widgets/select_dataset_tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
464
- supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py,sha256=HQwKXzz5yhmdcS79qfP_AGDUpGgQESNmLcASZx2rv78,25802
464
+ supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py,sha256=zFb7a70Zb7iWAtoM7zESCWcobQ2YEROJIJoj0CKpQ3k,25855
465
465
  supervisely/app/widgets/select_dataset_tree/template.html,sha256=_uvKCMP0nkpSl3FiTUxqy10JZw3q8-9hXCv22W3BDF0,38
466
466
  supervisely/app/widgets/select_item/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
467
467
  supervisely/app/widgets/select_item/select_item.py,sha256=dcB0UN46rn3nFQybgrGpLRfwB6xnPo-GGrv9rsMeCbA,3833
@@ -937,7 +937,7 @@ supervisely/nn/inference/predict_app/predict_app.py,sha256=jgpNLfbi5sQCiOYITHego
937
937
  supervisely/nn/inference/predict_app/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
938
938
  supervisely/nn/inference/predict_app/gui/classes_selector.py,sha256=qjc0-bpV2L2vIUr-LoNSLKXhNNrNfliJpl44ybAgSyw,6369
939
939
  supervisely/nn/inference/predict_app/gui/gui.py,sha256=Zkp3M2aKZEKX6kZQbYiaSPiTEFM_Ul_xtuNozQ7dkMs,39526
940
- supervisely/nn/inference/predict_app/gui/input_selector.py,sha256=vEGsS-XMjV052UbJIpg-aFfGxIfyz5inHqr8dIg6N_E,12461
940
+ supervisely/nn/inference/predict_app/gui/input_selector.py,sha256=jZ3H9TP9flu1LrulS936I6jenHnC_a3a6iixjTL4srY,13781
941
941
  supervisely/nn/inference/predict_app/gui/model_selector.py,sha256=UvUErutEI8COCWA1WU5MMvMrju0k7W_65Sgp7URa9Qc,2369
942
942
  supervisely/nn/inference/predict_app/gui/output_selector.py,sha256=IEwR3CJUAh26eztfdPqfIyzjfyAHbV-fRTwmuwJE09g,6535
943
943
  supervisely/nn/inference/predict_app/gui/preview.py,sha256=UpOrXmjV32qDRdRKPO15BbRVIzhIEh906BkUtjjGaio,2871
@@ -1129,9 +1129,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
1129
1129
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
1130
1130
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
1131
1131
  supervisely_lib/__init__.py,sha256=yRwzEQmVwSd6lUQoAUdBngKEOlnoQ6hA9ZcoZGJRNC4,331
1132
- supervisely-6.73.464.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1133
- supervisely-6.73.464.dist-info/METADATA,sha256=LetWCHVdHoghuOfeeVXPlpSzx46mBvxCsBpAf1P1uYs,35604
1134
- supervisely-6.73.464.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1135
- supervisely-6.73.464.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1136
- supervisely-6.73.464.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1137
- supervisely-6.73.464.dist-info/RECORD,,
1132
+ supervisely-6.73.466.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1133
+ supervisely-6.73.466.dist-info/METADATA,sha256=q2FJduEmU6_lERCigGsJJPQnDn7McmbPDVAASKsP-P4,35604
1134
+ supervisely-6.73.466.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1135
+ supervisely-6.73.466.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1136
+ supervisely-6.73.466.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1137
+ supervisely-6.73.466.dist-info/RECORD,,