supervisely 6.73.322__py3-none-any.whl → 6.73.324__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.
supervisely/_utils.py CHANGED
@@ -471,9 +471,20 @@ def get_or_create_event_loop() -> asyncio.AbstractEventLoop:
471
471
  return loop
472
472
 
473
473
 
474
- def sync_call(coro):
474
+ def run_coroutine(coroutine):
475
475
  """
476
- This function is used to run asynchronous functions in synchronous context.
476
+ Runs an asynchronous coroutine in a synchronous context and waits for its result.
477
+
478
+ This function checks if an event loop is already running:
479
+ - If a loop is running, it schedules the coroutine using `asyncio.run_coroutine_threadsafe()`
480
+ and waits for the result.
481
+ - If no loop is running, it creates one and executes the coroutine with `run_until_complete()`.
482
+
483
+ This ensures compatibility with both synchronous and asynchronous environments
484
+ without creating unnecessary event loops.
485
+
486
+ ⚠️ Note: This method is preferable when working with `asyncio` objects like `Semaphore`,
487
+ since it avoids issues with mismatched event loops.
477
488
 
478
489
  :param coro: Asynchronous function.
479
490
  :type coro: Coroutine
@@ -484,13 +495,13 @@ def sync_call(coro):
484
495
 
485
496
  .. code-block:: python
486
497
 
487
- from supervisely.utils import sync_call
498
+ from supervisely._utils import run_coroutine
488
499
 
489
500
  async def async_function():
490
501
  await asyncio.sleep(1)
491
502
  return "Hello, World!"
492
503
  coro = async_function()
493
- result = sync_call(coro)
504
+ result = run_coroutine(coro)
494
505
  print(result)
495
506
  # Output: Hello, World!
496
507
  """
@@ -498,10 +509,10 @@ def sync_call(coro):
498
509
  loop = get_or_create_event_loop()
499
510
 
500
511
  if loop.is_running():
501
- future = asyncio.run_coroutine_threadsafe(coro, loop=loop)
512
+ future = asyncio.run_coroutine_threadsafe(coroutine, loop=loop)
502
513
  return future.result()
503
514
  else:
504
- return loop.run_until_complete(coro)
515
+ return loop.run_until_complete(coroutine)
505
516
 
506
517
 
507
518
  def get_filename_from_headers(url):
@@ -404,7 +404,7 @@ class Annotation:
404
404
  f"Failed to deserialize one of the label from JSON format annotation: \n{repr(e)}"
405
405
  )
406
406
 
407
- custom_data = data.get(AnnotationJsonFields.CUSTOM_DATA, {})
407
+ custom_data = data.get(AnnotationJsonFields.CUSTOM_DATA, {}) or {}
408
408
  prob_labels = None
409
409
  if (
410
410
  AnnotationJsonFields.PROBABILITY_LABELS in custom_data
@@ -23,7 +23,7 @@ from typing_extensions import Literal
23
23
 
24
24
  import supervisely.io.env as env
25
25
  import supervisely.io.fs as sly_fs
26
- from supervisely._utils import batched, rand_str
26
+ from supervisely._utils import batched, rand_str, run_coroutine
27
27
  from supervisely.api.module_api import ApiField, ModuleApiBase
28
28
  from supervisely.io.fs import (
29
29
  ensure_base_path,
@@ -2302,3 +2302,89 @@ class FileApi(ModuleApiBase):
2302
2302
  else:
2303
2303
  raise e
2304
2304
  return res_remote_dir
2305
+
2306
+ def upload_directory_fast(
2307
+ self,
2308
+ team_id: int,
2309
+ local_dir: str,
2310
+ remote_dir: str,
2311
+ change_name_if_conflict: Optional[bool] = True,
2312
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
2313
+ replace_if_conflict: Optional[bool] = False,
2314
+ enable_fallback: Optional[bool] = True,
2315
+ ) -> str:
2316
+ """
2317
+ Upload Directory to Team Files from local path in fast mode.
2318
+ Files are uploaded asynchronously. If an error occurs, the method will fallback to synchronous upload.
2319
+
2320
+ :param team_id: Team ID in Supervisely.
2321
+ :type team_id: int
2322
+ :param local_dir: Path to local Directory.
2323
+ :type local_dir: str
2324
+ :param remote_dir: Path to Directory in Team Files.
2325
+ :type remote_dir: str
2326
+ :param change_name_if_conflict: Checks if given name already exists and adds suffix to the end of the name.
2327
+ :type change_name_if_conflict: bool, optional
2328
+ :param progress_cb: Function for tracking download progress in bytes.
2329
+ :type progress_cb: Progress, optional
2330
+ :param replace_if_conflict: If True, replace existing dir.
2331
+ :type replace_if_conflict: bool, optional
2332
+ :param enable_fallback: If True, the method will fallback to synchronous upload if an error occurs.
2333
+ :type enable_fallback: bool, optional
2334
+ :return: Path to Directory in Team Files
2335
+ :rtype: :class:`str`
2336
+ """
2337
+ coroutine = self.upload_directory_async(
2338
+ team_id=team_id,
2339
+ local_dir=local_dir,
2340
+ remote_dir=remote_dir,
2341
+ change_name_if_conflict=change_name_if_conflict,
2342
+ progress_size_cb=progress_cb,
2343
+ replace_if_conflict=replace_if_conflict,
2344
+ enable_fallback=enable_fallback,
2345
+ )
2346
+ return run_coroutine(coroutine)
2347
+
2348
+ def upload_bulk_fast(
2349
+ self,
2350
+ team_id: int,
2351
+ src_paths: List[str],
2352
+ dst_paths: List[str],
2353
+ semaphore: Optional[asyncio.Semaphore] = None,
2354
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
2355
+ progress_cb_type: Literal["number", "size"] = "size",
2356
+ enable_fallback: Optional[bool] = True,
2357
+ ) -> None:
2358
+ """
2359
+ Upload multiple files from local paths to Team Files in fast mode.
2360
+ Files are uploaded asynchronously. If an error occurs, the method will fallback to synchronous upload.
2361
+
2362
+ :param team_id: Team ID in Supervisely.
2363
+ :type team_id: int
2364
+ :param src_paths: List of local paths to files.
2365
+ :type src_paths: List[str]
2366
+ :param dst_paths: List of paths to save files in Team Files.
2367
+ :type dst_paths: List[str]
2368
+ :param semaphore: Semaphore for limiting the number of simultaneous uploads.
2369
+ :type semaphore: asyncio.Semaphore, optional
2370
+ :param progress_cb: Function for tracking download progress.
2371
+ :type progress_cb: tqdm or callable, optional
2372
+ :param progress_cb_type: Type of progress callback. Can be "number" or "size". Default is "size".
2373
+ "size" is used to track the number of transferred bytes.
2374
+ "number" is used to track the number of transferred files.
2375
+ :type progress_cb_type: Literal["number", "size"], optional
2376
+ :param enable_fallback: If True, the method will fallback to synchronous upload if an error occurs.
2377
+ :type enable_fallback: bool, optional
2378
+ :return: None
2379
+ :rtype: :class:`NoneType`
2380
+ """
2381
+ coroutine = self.upload_bulk_async(
2382
+ team_id=team_id,
2383
+ src_paths=src_paths,
2384
+ dst_paths=dst_paths,
2385
+ semaphore=semaphore,
2386
+ progress_cb=progress_cb,
2387
+ progress_cb_type=progress_cb_type,
2388
+ enable_fallback=enable_fallback,
2389
+ )
2390
+ return run_coroutine(coroutine)
@@ -3,6 +3,20 @@ import concurrent.futures
3
3
 
4
4
 
5
5
  def run_sync(coroutine):
6
+ """
7
+ Runs an asynchronous coroutine in a separate thread and waits for its result.
8
+ It is useful for running async functions in a synchronous
9
+ environment.
10
+
11
+ This method creates a new thread using ThreadPoolExecutor and executes the coroutine
12
+ inside a new event loop.
13
+
14
+ ⚠️ Note: This function creates a new event loop every time it is called,
15
+ which can cause issues when using objects tied to a specific loop (e.g., asyncio.Semaphore).
16
+
17
+ :param coroutine: coroutine to run
18
+ :return: result of coroutine
19
+ """
6
20
  try:
7
21
  with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
8
22
  result = executor.submit(
@@ -71,6 +71,7 @@ class AvailablePointcloudEpisodesConverters:
71
71
  class AvailableVolumeConverters:
72
72
  SLY = "supervisely"
73
73
  DICOM = "dicom"
74
+ NII = "nii"
74
75
 
75
76
 
76
77
  class BaseConverter:
@@ -1,3 +1,4 @@
1
1
  # Volume
2
2
  from supervisely.convert.volume.sly.sly_volume_converter import SLYVolumeConverter
3
3
  from supervisely.convert.volume.dicom.dicom_converter import DICOMConverter
4
+ from supervisely.convert.volume.nii.nii_volume_converter import NiiConverter
File without changes
@@ -0,0 +1,151 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ import magic
5
+
6
+ from supervisely import ProjectMeta, generate_free_name, logger
7
+ from supervisely._utils import batched, is_development
8
+ from supervisely.annotation.obj_class import ObjClass
9
+ from supervisely.annotation.obj_class_collection import ObjClassCollection
10
+ from supervisely.api.api import Api
11
+ from supervisely.convert.base_converter import AvailableVolumeConverters
12
+ from supervisely.convert.volume.nii import nii_volume_helper as helper
13
+ from supervisely.convert.volume.volume_converter import VolumeConverter
14
+ from supervisely.geometry.mask_3d import Mask3D
15
+ from supervisely.io.fs import (
16
+ get_file_ext,
17
+ get_file_name,
18
+ get_file_name_with_ext,
19
+ list_files,
20
+ )
21
+ from supervisely.volume.volume import is_nifti_file
22
+ from supervisely.volume_annotation.volume_annotation import VolumeAnnotation
23
+ from supervisely.volume_annotation.volume_object import VolumeObject
24
+
25
+
26
+ class NiiConverter(VolumeConverter):
27
+
28
+ def __str__(self) -> str:
29
+ return AvailableVolumeConverters.NII
30
+
31
+ def validate_format(self) -> bool:
32
+ # create Items
33
+ converted_dir_name = "converted"
34
+ # nrrds_dict = {}
35
+ nifti_dict = {}
36
+ nifti_dirs = {}
37
+ for root, _, files in os.walk(self._input_data):
38
+ dir_name = os.path.basename(root)
39
+ nifti_dirs[dir_name] = root
40
+ if converted_dir_name in root:
41
+ continue
42
+ for file in files:
43
+ path = os.path.join(root, file)
44
+ mime = magic.from_file(path, mime=True)
45
+ if mime == "application/gzip" or mime == "application/octet-stream":
46
+ if is_nifti_file(path): # is nifti
47
+ name = get_file_name(path)
48
+ if name.endswith(".nii"):
49
+ name = get_file_name(name)
50
+ nifti_dict[name] = path
51
+
52
+ self._items = []
53
+ skip_files = []
54
+ for name, nrrd_path in nifti_dict.items():
55
+ if name in nifti_dirs:
56
+ item = self.Item(item_path=nrrd_path)
57
+ ann_dir = nifti_dirs[name]
58
+ item.ann_data = list_files(ann_dir, [".nii", ".nii.gz", ".gz"], None, True)
59
+ self._items.append(item)
60
+ skip_files.extend(item.ann_data)
61
+ skip_files.append(nrrd_path)
62
+
63
+ for name, nrrd_path in nifti_dict.items():
64
+ if nrrd_path in skip_files:
65
+ continue
66
+ item = self.Item(item_path=nrrd_path)
67
+ self._items.append(item)
68
+
69
+ self._meta = ProjectMeta()
70
+ return self.items_count > 0
71
+
72
+ def upload_dataset(
73
+ self,
74
+ api: Api,
75
+ dataset_id: int,
76
+ batch_size: int = 1,
77
+ log_progress=True,
78
+ ):
79
+ """Upload converted data to Supervisely"""
80
+
81
+ meta, renamed_classes, renamed_tags = self.merge_metas_with_conflicts(api, dataset_id)
82
+
83
+ existing_names = set([vol.name for vol in api.volume.get_list(dataset_id)])
84
+
85
+ if log_progress:
86
+ progress, progress_cb = self.get_progress(
87
+ self.items_count, "Converting and uploading volumes..."
88
+ )
89
+ else:
90
+ progress_cb = None
91
+
92
+ converted_dir_name = "converted"
93
+ converted_dir = os.path.join(self._input_data, converted_dir_name)
94
+ meta_changed = False
95
+
96
+ for batch in batched(self._items, batch_size=batch_size):
97
+ item_names = []
98
+ item_paths = []
99
+
100
+ for item in batch:
101
+ # nii_path = item.path
102
+ item.path = helper.nifti_to_nrrd(item.path, converted_dir)
103
+ ext = get_file_ext(item.path)
104
+ if ext.lower() != ext:
105
+ new_volume_path = Path(item.path).with_suffix(ext.lower()).as_posix()
106
+ os.rename(item.path, new_volume_path)
107
+ item.path = new_volume_path
108
+ item.name = get_file_name_with_ext(item.path)
109
+ item.name = generate_free_name(
110
+ existing_names, item.name, with_ext=True, extend_used_names=True
111
+ )
112
+ item_names.append(item.name)
113
+ item_paths.append(item.path)
114
+
115
+ volume_info = api.volume.upload_nrrd_serie_path(
116
+ dataset_id, name=item.name, path=item.path
117
+ )
118
+
119
+ if isinstance(item.ann_data, list) and len(item.ann_data) > 0:
120
+ objs = []
121
+ spatial_figures = []
122
+ for ann_path in item.ann_data:
123
+ ann_name = get_file_name(ann_path)
124
+ if ann_name.endswith(".nii"):
125
+ ann_name = get_file_name(ann_name)
126
+ for mask, _ in helper.get_annotation_from_nii(ann_path):
127
+ obj_class = meta.get_obj_class(ann_name)
128
+ if obj_class is None:
129
+ obj_class = ObjClass(ann_name, Mask3D)
130
+ meta = meta.add_obj_class(obj_class)
131
+ meta_changed = True
132
+ obj = VolumeObject(obj_class, mask_3d=mask)
133
+ spatial_figures.append(obj.figure)
134
+ objs.append(obj)
135
+ ann = VolumeAnnotation(
136
+ volume_info.meta, objects=objs, spatial_figures=spatial_figures
137
+ )
138
+
139
+ if meta_changed:
140
+ self._meta = meta
141
+ _, _, _ = self.merge_metas_with_conflicts(api, dataset_id)
142
+
143
+ api.volume.annotation.append(volume_info.id, ann)
144
+
145
+ if log_progress:
146
+ progress_cb(len(batch))
147
+
148
+ if log_progress:
149
+ if is_development():
150
+ progress.close()
151
+ logger.info(f"Dataset ID:{dataset_id} has been successfully uploaded.")
@@ -0,0 +1,38 @@
1
+ import os
2
+ from typing import Generator
3
+
4
+ import nrrd
5
+ import numpy as np
6
+
7
+ from supervisely.geometry.mask_3d import Mask3D
8
+ from supervisely.io.fs import ensure_base_path, get_file_ext, get_file_name
9
+ from supervisely.volume.volume import convert_3d_nifti_to_nrrd
10
+
11
+
12
+ def nifti_to_nrrd(nii_file_path: str, converted_dir: str) -> str:
13
+ """Convert NIfTI 3D volume file to NRRD 3D volume file."""
14
+
15
+ output_name = get_file_name(nii_file_path)
16
+ if get_file_ext(output_name) == ".nii":
17
+ output_name = get_file_name(output_name)
18
+
19
+ data, header = convert_3d_nifti_to_nrrd(nii_file_path)
20
+
21
+ nrrd_file_path = os.path.join(converted_dir, f"{output_name}.nrrd")
22
+ ensure_base_path(nrrd_file_path)
23
+
24
+ nrrd.write(nrrd_file_path, data, header)
25
+ return nrrd_file_path
26
+
27
+
28
+ def get_annotation_from_nii(path: str) -> Generator[Mask3D, None, None]:
29
+ """Get annotation from NIfTI 3D volume file."""
30
+
31
+ data, _ = convert_3d_nifti_to_nrrd(path)
32
+ unique_classes = np.unique(data)
33
+
34
+ for class_id in unique_classes:
35
+ if class_id == 0:
36
+ continue
37
+ mask = Mask3D(data == class_id)
38
+ yield mask, class_id
@@ -39,7 +39,7 @@ from supervisely import (
39
39
  is_production,
40
40
  logger,
41
41
  )
42
- from supervisely._utils import abs_url, get_filename_from_headers, sync_call
42
+ from supervisely._utils import abs_url, get_filename_from_headers
43
43
  from supervisely.api.file_api import FileInfo
44
44
  from supervisely.app import get_synced_data_dir
45
45
  from supervisely.app.widgets import Progress
@@ -60,7 +60,7 @@ from supervisely.nn.utils import ModelSource
60
60
  from supervisely.output import set_directory
61
61
  from supervisely.project.download import (
62
62
  copy_from_cache,
63
- download_async_or_sync,
63
+ download_fast,
64
64
  download_to_cache,
65
65
  get_cache_size,
66
66
  is_cached,
@@ -806,7 +806,7 @@ class TrainApp:
806
806
  with self.progress_bar_main(message="Downloading input data", total=total_images) as pbar:
807
807
  logger.debug("Downloading project data without cache")
808
808
  self.progress_bar_main.show()
809
- download_async_or_sync(
809
+ download_fast(
810
810
  api=self._api,
811
811
  project_id=self.project_id,
812
812
  dest_dir=self.project_dir,
@@ -1619,14 +1619,13 @@ class TrainApp:
1619
1619
  unit_scale=True,
1620
1620
  ) as upload_artifacts_pbar:
1621
1621
  self.progress_bar_main.show()
1622
- remote_dir = sync_call(
1623
- self._api.file.upload_directory_async(
1624
- team_id=self.team_id,
1625
- local_dir=local_demo_dir,
1626
- remote_dir=remote_demo_dir,
1627
- progress_size_cb=upload_artifacts_pbar.update,
1628
- )
1622
+ remote_dir = self._api.file.upload_directory_fast(
1623
+ team_id=self.team_id,
1624
+ local_dir=local_demo_dir,
1625
+ remote_dir=remote_demo_dir,
1626
+ progress_cb=upload_artifacts_pbar.update,
1629
1627
  )
1628
+
1630
1629
  self.progress_bar_main.hide()
1631
1630
 
1632
1631
  def _get_train_val_splits_for_app_state(self) -> Dict:
@@ -1733,13 +1732,11 @@ class TrainApp:
1733
1732
  unit_scale=True,
1734
1733
  ) as upload_artifacts_pbar:
1735
1734
  self.progress_bar_main.show()
1736
- remote_dir = sync_call(
1737
- self._api.file.upload_directory_async(
1738
- team_id=self.team_id,
1739
- local_dir=self.output_dir,
1740
- remote_dir=remote_artifacts_dir,
1741
- progress_size_cb=upload_artifacts_pbar.update,
1742
- )
1735
+ remote_dir = self._api.file.upload_directory_fast(
1736
+ team_id=self.team_id,
1737
+ local_dir=self.output_dir,
1738
+ remote_dir=remote_artifacts_dir,
1739
+ progress_cb=upload_artifacts_pbar.update,
1743
1740
  )
1744
1741
  self.progress_bar_main.hide()
1745
1742
 
@@ -2524,13 +2521,11 @@ class TrainApp:
2524
2521
  logger.debug(f"Uploading {len(export_weights)} export weights of size {size} bytes")
2525
2522
  logger.debug(f"Destination paths: {file_dest_paths}")
2526
2523
  self.progress_bar_main.show()
2527
- sync_call(
2528
- self._api.file.upload_bulk_async(
2529
- team_id=self.team_id,
2530
- src_paths=export_weights.values(),
2531
- dst_paths=file_dest_paths,
2532
- progress_cb=export_upload_main_pbar.update,
2533
- )
2524
+ self._api.file.upload_bulk_fast(
2525
+ team_id=self.team_id,
2526
+ src_paths=export_weights.values(),
2527
+ dst_paths=file_dest_paths,
2528
+ progress_cb=export_upload_main_pbar.update,
2534
2529
  )
2535
2530
 
2536
2531
  self.progress_bar_main.hide()
@@ -281,6 +281,34 @@ def download_async_or_sync(
281
281
  )
282
282
 
283
283
 
284
+ def download_fast(
285
+ api: Api,
286
+ project_id: int,
287
+ dest_dir: str,
288
+ dataset_ids: Optional[List[int]] = None,
289
+ log_progress: bool = True,
290
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
291
+ semaphore: Optional[asyncio.Semaphore] = None,
292
+ **kwargs,
293
+ ) -> None:
294
+ """
295
+ Download project in a fast mode.
296
+ Items are downloaded asynchronously. If an error occurs, the method will fallback to synchronous download.
297
+ Automatically detects project type.
298
+ You can pass :class:`ProjectInfo` as `project_info` kwarg to avoid additional API requests.
299
+ """
300
+ download_async_or_sync(
301
+ api=api,
302
+ project_id=project_id,
303
+ dest_dir=dest_dir,
304
+ dataset_ids=dataset_ids,
305
+ log_progress=log_progress,
306
+ progress_cb=progress_cb,
307
+ semaphore=semaphore,
308
+ **kwargs,
309
+ )
310
+
311
+
284
312
  def _get_cache_dir(project_id: int, dataset_path: str = None) -> str:
285
313
  p = os.path.join(apps_cache_dir(), str(project_id))
286
314
  if dataset_path is not None:
@@ -468,7 +496,7 @@ def _download_project_to_cache(
468
496
  if len(dataset_infos) == 0:
469
497
  logger.debug("No datasets to download")
470
498
  return
471
- download_async_or_sync(
499
+ download_fast(
472
500
  api=api,
473
501
  project_id=project_id,
474
502
  dest_dir=cached_project_dir,
@@ -799,6 +799,49 @@ def convert_nifti_to_nrrd(path: str) -> Tuple[np.ndarray, dict]:
799
799
  }
800
800
  return data, header
801
801
 
802
+ def convert_3d_nifti_to_nrrd(path: str) -> Tuple[np.ndarray, dict]:
803
+ """Convert 3D NIFTI volume to NRRD format.
804
+ Volume automatically reordered to RAS orientation as closest to canonical.
805
+
806
+ :param path: Path to NIFTI volume file.
807
+ :type path: str
808
+ :return: Volume data in NumPy array format and dictionary with metadata (NRRD header).
809
+ :rtype: Tuple[np.ndarray, dict]
810
+ :Usage example:
811
+
812
+ .. code-block:: python
813
+
814
+ import supervisely as sly
815
+
816
+ path = "/home/admin/work/volumes/vol_01.nii"
817
+ data, header = sly.volume.convert_nifti_to_nrrd(path)
818
+ """
819
+
820
+ import nibabel as nib # pylint: disable=import-error
821
+
822
+ orientation_map = {
823
+ ('R', 'A', 'S'): "right-anterior-superior",
824
+ ('L', 'P', 'S'): "left-posterior-superior",
825
+ ('R', 'P', 'I'): "right-posterior-inferior",
826
+ ('L', 'A', 'I'): "left-anterior-inferior"
827
+ }
828
+ nifti = nib.load(path)
829
+ reordered_to_ras_nifti = nib.as_closest_canonical(nifti)
830
+ data = reordered_to_ras_nifti.get_fdata()
831
+ affine = reordered_to_ras_nifti.affine
832
+ orientation = nib.aff2axcodes(affine)
833
+ space_directions = affine[:3, :3].tolist()
834
+ space_origin = affine[:3, 3].tolist()
835
+ header = {
836
+ "space": orientation_map.get(orientation, "unknown"),
837
+ "space directions": space_directions,
838
+ "space origin": space_origin,
839
+ "sizes": data.shape,
840
+ "type": str(data.dtype),
841
+ "dimension": len(data.shape),
842
+ }
843
+ return data, header
844
+
802
845
 
803
846
  def is_nifti_file(path: str) -> bool:
804
847
  """Check if the file is a NIFTI file.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.322
3
+ Version: 6.73.324
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -1,11 +1,11 @@
1
1
  supervisely/README.md,sha256=XM-DiMC6To3I9RjQZ0c61905EFRR_jnCUx2q3uNR-X8,3331
2
2
  supervisely/__init__.py,sha256=mtgVKiRSlnRU7yKG0Re130mBL10wCzsNfOfi-w-Kj4c,10833
3
- supervisely/_utils.py,sha256=hYzGRVAh-cB2RmqixHbaJQZHy4byNip4KZm2Gdt8P7k,16849
3
+ supervisely/_utils.py,sha256=KWfbw8XFfV2uxLzhuku_J0UQKpG-D80Hp6UOQD316P8,17460
4
4
  supervisely/function_wrapper.py,sha256=R5YajTQ0GnRp2vtjwfC9hINkzQc0JiyGsu8TER373xY,1912
5
5
  supervisely/sly_logger.py,sha256=z92Vu5hmC0GgTIJO1n6kPDayRW9__8ix8hL6poDZj-Y,6274
6
6
  supervisely/tiny_timer.py,sha256=hkpe_7FE6bsKL79blSs7WBaktuPavEVu67IpEPrfmjE,183
7
7
  supervisely/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- supervisely/annotation/annotation.py,sha256=5AG1AhebkmiYy2r7nKbz6TjdmCF4tuf9FtqUjLLs7aU,114659
8
+ supervisely/annotation/annotation.py,sha256=x1RizD9DPiwk14Mf8xGvuwPdzx_zI5Zx1CVvmCy_sII,114665
9
9
  supervisely/annotation/annotation_transforms.py,sha256=TlVy_gUbM-XH6GbLpZPrAi6pMIGTr7Ow02iSKOSTa-I,9582
10
10
  supervisely/annotation/json_geometries_map.py,sha256=nL6AmMhFy02fw9ryBm75plKyOkDh61QdOToSuLAcz_Q,1659
11
11
  supervisely/annotation/label.py,sha256=NpHZ5o2H6dI4KiII22o2HpiLXG1yekh-bEy8WvI2Ljg,37498
@@ -25,7 +25,7 @@ supervisely/api/annotation_api.py,sha256=kuk4qwojTJxYr2iqAKbW-QhWw_DFc4TsjA2Wc2M
25
25
  supervisely/api/api.py,sha256=6TczKT1t0MWlbArSW31RmeyWP04pqngfUO_NrG5FETE,66287
26
26
  supervisely/api/app_api.py,sha256=RsbVej8WxWVn9cNo5s3Fqd1symsCdsfOaKVBKEUapRY,71927
27
27
  supervisely/api/dataset_api.py,sha256=GH7prDRJKyJlTv_7_Y-RkTwJN7ED4EkXNqqmi3iIdI4,41352
28
- supervisely/api/file_api.py,sha256=xVM4fFeIc52aKnxduCIU7L6Rgd7Rh36rzTJ8hVT8hw4,88925
28
+ supervisely/api/file_api.py,sha256=S2xZAy36YzWA1R41SIlLXX9JwSf9ax18AIAIQGgHGlA,92801
29
29
  supervisely/api/github_api.py,sha256=NIexNjEer9H5rf5sw2LEZd7C1WR-tK4t6IZzsgeAAwQ,623
30
30
  supervisely/api/image_annotation_tool_api.py,sha256=YcUo78jRDBJYvIjrd-Y6FJAasLta54nnxhyaGyanovA,5237
31
31
  supervisely/api/image_api.py,sha256=WIML_6N1qgOWBm3acexmGSWz4hAaSxlYmUtbytROaP8,192375
@@ -95,7 +95,7 @@ supervisely/app/fastapi/offline.py,sha256=CwMMkJ1frD6wiZS-SEoNDtQ1UJcJe1Ob6ohE3r
95
95
  supervisely/app/fastapi/request.py,sha256=NU7rKmxJ1pfkDZ7_yHckRcRAueJRQIqCor11UO2OHr8,766
96
96
  supervisely/app/fastapi/subapp.py,sha256=5lMfFLYBfHzE1OmITHsogB9hScyTJFjGV45AKY67Hkg,45647
97
97
  supervisely/app/fastapi/templating.py,sha256=JOAW8U-14GD47E286mzFi3mZSPbm_csJGqtXWLRM4rc,2929
98
- supervisely/app/fastapi/utils.py,sha256=GZuTWLcVRGVx8TL3jVEYUOZIT2FawbwIe2kAOBLw9ho,398
98
+ supervisely/app/fastapi/utils.py,sha256=t_UquzlFrdkKtAJmH6eJ279pE8Aa3BaIu4XjX-SEaIE,946
99
99
  supervisely/app/fastapi/websocket.py,sha256=TlRSPOAhRItTv1HGvdukK1ZvhRjMUxRa-lJlsRR9rJw,1308
100
100
  supervisely/app/v1/__init__.py,sha256=OdU0PYv6hLwahYoyaLFO8m3cbJSchvPbqxuG1N3T734,848
101
101
  supervisely/app/v1/app_config.md,sha256=-8GKbiQoX25RhEj3EDJ7TxiYuFw5wL2TO3qV5AJLZTs,2536
@@ -565,7 +565,7 @@ supervisely/collection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
565
565
  supervisely/collection/key_indexed_collection.py,sha256=x2UVlkprspWhhae9oLUzjTWBoIouiWY9UQSS_MozfH0,37643
566
566
  supervisely/collection/str_enum.py,sha256=Zp29yFGvnxC6oJRYNNlXhO2lTSdsriU1wiGHj6ahEJE,1250
567
567
  supervisely/convert/__init__.py,sha256=ropgB1eebG2bfLoJyf2jp8Vv9UkFujaW3jVX-71ho1g,1353
568
- supervisely/convert/base_converter.py,sha256=rRMIxY3h7cX5WAu_qn7w9vzRBcDB_jLZm5u_XQh7QG4,18563
568
+ supervisely/convert/base_converter.py,sha256=O2SP4I_Hd0aSn8kbOUocy8orkc_-iD-TQ-z4ieUqabA,18579
569
569
  supervisely/convert/converter.py,sha256=tWxTDfFv7hwzQhUQrBxzfr6WP8FUGFX_ewg5T2HbUYo,8959
570
570
  supervisely/convert/image/__init__.py,sha256=JEuyaBiiyiYmEUYqdn8Mog5FVXpz0H1zFubKkOOm73I,1395
571
571
  supervisely/convert/image/image_converter.py,sha256=8vak8ZoKTN1ye2ZmCTvCZ605-Rw1AFLIEo7bJMfnR68,10426
@@ -658,11 +658,14 @@ supervisely/convert/video/mot/mot_converter.py,sha256=wXbv-9Psc2uVnhzHuOt5VnRIvS
658
658
  supervisely/convert/video/sly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
659
659
  supervisely/convert/video/sly/sly_video_converter.py,sha256=S2qif7JFxqIi9VN_ez_iBtoJXpG9W6Ky2k5Er3-DtUo,4418
660
660
  supervisely/convert/video/sly/sly_video_helper.py,sha256=D8PgoXpi0y3z-VEqvBLDf_gSUQ2hTL3irrfJyGhaV0Y,6758
661
- supervisely/convert/volume/__init__.py,sha256=ZXV1GwQlvKY7sZroUU-jiMTkgngk1aimh51nw1onzuc,168
661
+ supervisely/convert/volume/__init__.py,sha256=NjVfOa9uH1BdYvB-RynW6L28x0f_tqL9p7tHSIQ6Sso,245
662
662
  supervisely/convert/volume/volume_converter.py,sha256=3jpt2Yn_G4FSP_vHFsJHQfYNQpT7q6ar_sRyr_xrPnA,5335
663
663
  supervisely/convert/volume/dicom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
664
664
  supervisely/convert/volume/dicom/dicom_converter.py,sha256=__QP8fMAaq_BdWFYh1_nAYT2gpY1WwZzdlDj39YwHhw,3195
665
665
  supervisely/convert/volume/dicom/dicom_helper.py,sha256=1EXmxl5Z8Xi3ZkZnfJ4EbiPCVyITSXUc0Cn_oo02pPE,1284
666
+ supervisely/convert/volume/nii/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
667
+ supervisely/convert/volume/nii/nii_volume_converter.py,sha256=kI2JmeFuLfLWgYGCEozoaka1QH4TocnfgyN0em6maa0,5946
668
+ supervisely/convert/volume/nii/nii_volume_helper.py,sha256=kzh20fsdeI8efA0vawW0M6Wh48nMlCLzHBQFuSNVFmc,1136
666
669
  supervisely/convert/volume/sly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
667
670
  supervisely/convert/volume/sly/sly_volume_converter.py,sha256=XmSuxnRqxchG87b244f3h0UHvOt6IkajMquL1drWlCM,5595
668
671
  supervisely/convert/volume/sly/sly_volume_helper.py,sha256=gUY0GW3zDMlO2y-zQQG36uoXMrKkKz4-ErM1CDxFCxE,5620
@@ -976,7 +979,7 @@ supervisely/nn/tracker/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
976
979
  supervisely/nn/tracker/utils/gmc.py,sha256=3JX8979H3NA-YHNaRQyj9Z-xb9qtyMittPEjGw8y2Jo,11557
977
980
  supervisely/nn/tracker/utils/kalman_filter.py,sha256=eSFmCjM0mikHCAFvj-KCVzw-0Jxpoc3Cfc2NWEjJC1Q,17268
978
981
  supervisely/nn/training/__init__.py,sha256=gY4PCykJ-42MWKsqb9kl-skemKa8yB6t_fb5kzqR66U,111
979
- supervisely/nn/training/train_app.py,sha256=yVsMdMlV6OHCRMJ63-hPmTfdsC3Z1-0ohphsMtDMpPw,104944
982
+ supervisely/nn/training/train_app.py,sha256=lFvYxt2Zsd7FrqfeA2C-eNX0tQVLtz3V8om3DwvNFtM,104720
980
983
  supervisely/nn/training/gui/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
981
984
  supervisely/nn/training/gui/classes_selector.py,sha256=8UgzA4aogOAr1s42smwEcDbgaBj_i0JLhjwlZ9bFdIA,3772
982
985
  supervisely/nn/training/gui/gui.py,sha256=CnT_QhihrxdSHKybpI0pXhPLwCaXEana_qdn0DhXByg,25558
@@ -1013,7 +1016,7 @@ supervisely/pointcloud_episodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
1013
1016
  supervisely/pointcloud_episodes/pointcloud_episodes.py,sha256=cRXdtw7bMsbsdVQjxfWxFSESrO-LGiqqsZyyExl2Mbg,3430
1014
1017
  supervisely/project/__init__.py,sha256=hlzdj9Pgy53Q3qdP8LMtGTChvZHQuuShdtui2eRUQeE,2601
1015
1018
  supervisely/project/data_version.py,sha256=6vOz5ovBeCIiMAKUG7lGQ5IXvQnU1GbcnrWxdOvaVlo,19311
1016
- supervisely/project/download.py,sha256=zb8sb4XZ6Qi3CP7fmtLRUAYzaxs_W0WnOfe2x3ZVRMs,24639
1019
+ supervisely/project/download.py,sha256=GQFYN3KCdM_egXDzoyZrzl6Yeg2QshYQNFNlKi8Nh8A,25471
1017
1020
  supervisely/project/pointcloud_episode_project.py,sha256=yiWdNBQiI6f1O9sr1pg8JHW6O-w3XUB1rikJNn3Oung,41866
1018
1021
  supervisely/project/pointcloud_project.py,sha256=Kx1Vaes-krwG3BiRRtHRLQxb9G5m5bTHPN9IzRqmNWo,49399
1019
1022
  supervisely/project/project.py,sha256=nKnnYVrSx_MWh5G_fObaAegkRxLFJg_J074SaduEYGo,205871
@@ -1056,7 +1059,7 @@ supervisely/volume/__init__.py,sha256=EBZBY_5mzabXzMUQh5akusIGd16XnX9n8J0jIi_JmW
1056
1059
  supervisely/volume/nrrd_encoder.py,sha256=1lqwwyqxEvctw1ysQ70x4xPSV1uy1g5YcH5CURwL7-c,4084
1057
1060
  supervisely/volume/nrrd_loader.py,sha256=_yqahKcqSRxunHZ5LtnUWIRA7UvIhPKOhAUwYijSGY4,9065
1058
1061
  supervisely/volume/stl_converter.py,sha256=WIMQgHO_u4JT58QdcMXcb_euF1BFhM7D52IVX_0QTxE,6285
1059
- supervisely/volume/volume.py,sha256=-AAZIducizejhXyZWmaytCPLCcF8_vdnXDSTpJb5jIs,24337
1062
+ supervisely/volume/volume.py,sha256=7ebCIICqZMwRP3ruRy3PtSeiUpBpSlyRH20VJybBQbI,25828
1060
1063
  supervisely/volume_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1061
1064
  supervisely/volume_annotation/constants.py,sha256=BdFIh56fy7vzLIjt0gH8xP01EIU-qgQIwbSHVUcABCU,569
1062
1065
  supervisely/volume_annotation/plane.py,sha256=wyezAcc8tLp38O44CwWY0wjdQxf3VjRdFLWooCrk-Nw,16301
@@ -1078,9 +1081,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
1078
1081
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
1079
1082
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
1080
1083
  supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
1081
- supervisely-6.73.322.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1082
- supervisely-6.73.322.dist-info/METADATA,sha256=tXlMoMRbbXrc18yQVTx6Ti09xSaTCC4TyKgLUoNIC_U,33596
1083
- supervisely-6.73.322.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1084
- supervisely-6.73.322.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1085
- supervisely-6.73.322.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1086
- supervisely-6.73.322.dist-info/RECORD,,
1084
+ supervisely-6.73.324.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1085
+ supervisely-6.73.324.dist-info/METADATA,sha256=mUZAJc6JxtQ7H7I31gf_QWoBAjl4qXsS-CilUCvf8f8,33596
1086
+ supervisely-6.73.324.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1087
+ supervisely-6.73.324.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1088
+ supervisely-6.73.324.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1089
+ supervisely-6.73.324.dist-info/RECORD,,