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 +17 -6
 - supervisely/annotation/annotation.py +1 -1
 - supervisely/api/file_api.py +87 -1
 - supervisely/app/fastapi/utils.py +14 -0
 - supervisely/convert/base_converter.py +1 -0
 - supervisely/convert/volume/__init__.py +1 -0
 - supervisely/convert/volume/nii/__init__.py +0 -0
 - supervisely/convert/volume/nii/nii_volume_converter.py +151 -0
 - supervisely/convert/volume/nii/nii_volume_helper.py +38 -0
 - supervisely/nn/training/train_app.py +19 -24
 - supervisely/project/download.py +29 -1
 - supervisely/volume/volume.py +43 -0
 - {supervisely-6.73.322.dist-info → supervisely-6.73.324.dist-info}/METADATA +1 -1
 - {supervisely-6.73.322.dist-info → supervisely-6.73.324.dist-info}/RECORD +18 -15
 - {supervisely-6.73.322.dist-info → supervisely-6.73.324.dist-info}/LICENSE +0 -0
 - {supervisely-6.73.322.dist-info → supervisely-6.73.324.dist-info}/WHEEL +0 -0
 - {supervisely-6.73.322.dist-info → supervisely-6.73.324.dist-info}/entry_points.txt +0 -0
 - {supervisely-6.73.322.dist-info → supervisely-6.73.324.dist-info}/top_level.txt +0 -0
 
    
        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  
     | 
| 
      
 474 
     | 
    
         
            +
            def run_coroutine(coroutine):
         
     | 
| 
       475 
475 
     | 
    
         
             
                """
         
     | 
| 
       476 
     | 
    
         
            -
                 
     | 
| 
      
 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. 
     | 
| 
      
 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 =  
     | 
| 
      
 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( 
     | 
| 
      
 512 
     | 
    
         
            +
                    future = asyncio.run_coroutine_threadsafe(coroutine, loop=loop)
         
     | 
| 
       502 
513 
     | 
    
         
             
                    return future.result()
         
     | 
| 
       503 
514 
     | 
    
         
             
                else:
         
     | 
| 
       504 
     | 
    
         
            -
                    return loop.run_until_complete( 
     | 
| 
      
 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
         
     | 
    
        supervisely/api/file_api.py
    CHANGED
    
    | 
         @@ -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)
         
     | 
    
        supervisely/app/fastapi/utils.py
    CHANGED
    
    | 
         @@ -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(
         
     | 
| 
         
            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 
     | 
| 
      
 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 
     | 
    
         
            -
                 
     | 
| 
      
 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 
     | 
    
         
            -
                         
     | 
| 
      
 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 =  
     | 
| 
       1623 
     | 
    
         
            -
                            self. 
     | 
| 
       1624 
     | 
    
         
            -
             
     | 
| 
       1625 
     | 
    
         
            -
             
     | 
| 
       1626 
     | 
    
         
            -
             
     | 
| 
       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 =  
     | 
| 
       1737 
     | 
    
         
            -
                            self. 
     | 
| 
       1738 
     | 
    
         
            -
             
     | 
| 
       1739 
     | 
    
         
            -
             
     | 
| 
       1740 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
                         
     | 
| 
       2528 
     | 
    
         
            -
                            self. 
     | 
| 
       2529 
     | 
    
         
            -
             
     | 
| 
       2530 
     | 
    
         
            -
             
     | 
| 
       2531 
     | 
    
         
            -
             
     | 
| 
       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()
         
     | 
    
        supervisely/project/download.py
    CHANGED
    
    | 
         @@ -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 
     | 
    
         
            -
                 
     | 
| 
      
 499 
     | 
    
         
            +
                download_fast(
         
     | 
| 
       472 
500 
     | 
    
         
             
                    api=api,
         
     | 
| 
       473 
501 
     | 
    
         
             
                    project_id=project_id,
         
     | 
| 
       474 
502 
     | 
    
         
             
                    dest_dir=cached_project_dir,
         
     | 
    
        supervisely/volume/volume.py
    CHANGED
    
    | 
         @@ -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,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= 
     | 
| 
      
 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= 
     | 
| 
      
 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= 
     | 
| 
      
 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= 
     | 
| 
      
 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= 
     | 
| 
      
 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= 
     | 
| 
      
 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= 
     | 
| 
      
 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= 
     | 
| 
      
 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 
     | 
| 
      
 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. 
     | 
| 
       1082 
     | 
    
         
            -
            supervisely-6.73. 
     | 
| 
       1083 
     | 
    
         
            -
            supervisely-6.73. 
     | 
| 
       1084 
     | 
    
         
            -
            supervisely-6.73. 
     | 
| 
       1085 
     | 
    
         
            -
            supervisely-6.73. 
     | 
| 
       1086 
     | 
    
         
            -
            supervisely-6.73. 
     | 
| 
      
 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,,
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |