supervisely 6.73.225__py3-none-any.whl → 6.73.227__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

supervisely/__init__.py CHANGED
@@ -55,7 +55,7 @@ from supervisely.task.progress import (
55
55
 
56
56
  import supervisely.project as project
57
57
  from supervisely.project import read_project, get_project_class
58
- from supervisely.project.download import download
58
+ from supervisely.project.download import download, download_async
59
59
  from supervisely.project.upload import upload
60
60
  from supervisely.project.project import (
61
61
  Project,
supervisely/_utils.py CHANGED
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
+ import asyncio
3
4
  import base64
4
5
  import copy
5
6
  import hashlib
@@ -382,3 +383,25 @@ def add_callback(func, callback):
382
383
  return res
383
384
 
384
385
  return wrapper
386
+
387
+
388
+ def get_or_create_event_loop() -> asyncio.AbstractEventLoop:
389
+ """
390
+ Get the current event loop or create a new one if it doesn't exist.
391
+ Works for different Python versions and contexts.
392
+
393
+ :return: Event loop
394
+ :rtype: asyncio.AbstractEventLoop
395
+ """
396
+ try:
397
+ # Preferred method for asynchronous context (Python 3.7+)
398
+ return asyncio.get_running_loop()
399
+ except RuntimeError:
400
+ # If the loop is not running, get the current one or create a new one (Python 3.8 and 3.9)
401
+ try:
402
+ return asyncio.get_event_loop()
403
+ except RuntimeError:
404
+ # For Python 3.10+ or if the call occurs outside of an active loop context
405
+ loop = asyncio.new_event_loop()
406
+ asyncio.set_event_loop(loop)
407
+ return loop
@@ -4,10 +4,11 @@
4
4
  # docs
5
5
  from __future__ import annotations
6
6
 
7
+ import asyncio
7
8
  import json
8
9
  from collections import defaultdict
9
10
  from copy import deepcopy
10
- from typing import Any, Callable, Dict, List, NamedTuple, Optional, Union
11
+ from typing import Any, Callable, Dict, List, Literal, NamedTuple, Optional, Union
11
12
 
12
13
  from tqdm import tqdm
13
14
 
@@ -1307,36 +1308,36 @@ class AnnotationApi(ModuleApi):
1307
1308
  Priority increases with the number: a higher number indicates a higher priority.
1308
1309
  The higher priority means that the label will be displayed on top of the others.
1309
1310
  The lower priority means that the label will be displayed below the others.
1310
-
1311
+
1311
1312
  :param label_id: ID of the label to update
1312
1313
  :type label_id: int
1313
1314
  :param priority: New priority of the label
1314
1315
  :type priority: int
1315
-
1316
- :Usage example:
1317
-
1316
+
1317
+ :Usage example:
1318
+
1318
1319
  .. code-block:: python
1319
-
1320
+
1320
1321
  import os
1321
1322
  from dotenv import load_dotenv
1322
-
1323
+
1323
1324
  import supervisely as sly
1324
-
1325
+
1325
1326
  # Load secrets and create API object from .env file (recommended)
1326
1327
  # Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
1327
1328
  load_dotenv(os.path.expanduser("~/supervisely.env"))
1328
-
1329
+
1329
1330
  api = sly.Api.from_env()
1330
-
1331
+
1331
1332
  label_ids = [123, 456, 789]
1332
1333
  priorities = [1, 2, 3]
1333
-
1334
+
1334
1335
  for label_id, priority in zip(label_ids, priorities):
1335
1336
  api.annotation.update_label_priority(label_id, priority)
1336
-
1337
+
1337
1338
  # The label with ID 789 will be displayed on top of the others.
1338
1339
  # The label with ID 123 will be displayed below the others.
1339
-
1340
+
1340
1341
  """
1341
1342
  self._api.post(
1342
1343
  "figures.priority.update",
@@ -1344,4 +1345,173 @@ class AnnotationApi(ModuleApi):
1344
1345
  ApiField.ID: label_id,
1345
1346
  ApiField.PRIORITY: priority,
1346
1347
  },
1347
- )
1348
+ )
1349
+
1350
+ async def download_async(
1351
+ self,
1352
+ image_id: int,
1353
+ semaphore: Optional[asyncio.Semaphore] = None,
1354
+ with_custom_data: Optional[bool] = False,
1355
+ force_metadata_for_links: Optional[bool] = True,
1356
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
1357
+ progress_cb_type: Literal["number", "size"] = "number",
1358
+ ) -> AnnotationInfo:
1359
+ """
1360
+ Download AnnotationInfo by image ID from API.
1361
+
1362
+ :param image_id: Image ID in Supervisely.
1363
+ :type image_id: int
1364
+ :param semaphore: Semaphore for limiting the number of simultaneous downloads.
1365
+ :type semaphore: asyncio.Semaphore, optional
1366
+ :param with_custom_data: Include custom data in the response.
1367
+ :type with_custom_data: bool, optional
1368
+ :param force_metadata_for_links: Force metadata for links.
1369
+ :type force_metadata_for_links: bool, optional
1370
+ :param progress_cb: Function for tracking download progress.
1371
+ :type progress_cb: tqdm or callable, optional
1372
+ :param progress_cb_type: Type of progress callback. Can be "number" or "size". Default is "number".
1373
+ :type progress_cb_type: str, optional
1374
+ :return: Information about Annotation. See :class:`info_sequence<info_sequence>`
1375
+ :rtype: :class:`AnnotationInfo`
1376
+ :Usage example:
1377
+
1378
+ .. code-block:: python
1379
+
1380
+ import supervisely as sly
1381
+
1382
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
1383
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
1384
+ api = sly.Api.from_env()
1385
+
1386
+ image_id = 121236918
1387
+ loop = sly.utils.get_or_create_event_loop()
1388
+ ann_info = loop.run_until_complete(api.annotation.download_async(image_id))
1389
+ """
1390
+ if semaphore is None:
1391
+ semaphore = self._api._get_default_semaphore()
1392
+ async with semaphore:
1393
+ response = await self._api.post_async(
1394
+ "annotations.info",
1395
+ {
1396
+ ApiField.IMAGE_ID: image_id,
1397
+ ApiField.WITH_CUSTOM_DATA: with_custom_data,
1398
+ ApiField.FORCE_METADATA_FOR_LINKS: force_metadata_for_links,
1399
+ ApiField.INTEGER_COORDS: False,
1400
+ },
1401
+ )
1402
+ if progress_cb is not None and progress_cb_type == "size":
1403
+ progress_cb(len(response.content))
1404
+
1405
+ result = response.json()
1406
+ # Convert annotation to pixel coordinate system
1407
+ result[ApiField.ANNOTATION] = Annotation._to_pixel_coordinate_system_json(
1408
+ result[ApiField.ANNOTATION]
1409
+ )
1410
+ # check if there are any AlphaMask geometries in the batch
1411
+ additonal_geometries = defaultdict(int)
1412
+ labels = result[ApiField.ANNOTATION][AnnotationJsonFields.LABELS]
1413
+ for idx, label in enumerate(labels):
1414
+ if label[LabelJsonFields.GEOMETRY_TYPE] == AlphaMask.geometry_name():
1415
+ figure_id = label[LabelJsonFields.ID]
1416
+ additonal_geometries[figure_id] = idx
1417
+
1418
+ # if so, download them separately and update the annotation
1419
+ if len(additonal_geometries) > 0:
1420
+ figure_ids = list(additonal_geometries.keys())
1421
+ figures = self._api.image.figure.download_geometries_batch(
1422
+ figure_ids,
1423
+ (
1424
+ progress_cb
1425
+ if progress_cb is not None and progress_cb_type == "size"
1426
+ else None
1427
+ ),
1428
+ )
1429
+ for figure_id, geometry in zip(figure_ids, figures):
1430
+ label_idx = additonal_geometries[figure_id]
1431
+ labels[label_idx].update({BITMAP: geometry})
1432
+ ann_info = self._convert_json_info(result)
1433
+ if progress_cb is not None and progress_cb_type == "number":
1434
+ progress_cb(1)
1435
+ return ann_info
1436
+
1437
+ async def download_batch_async(
1438
+ self,
1439
+ dataset_id: int,
1440
+ image_ids: List[int],
1441
+ semaphore: Optional[asyncio.Semaphore] = None,
1442
+ with_custom_data: Optional[bool] = False,
1443
+ force_metadata_for_links: Optional[bool] = True,
1444
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
1445
+ progress_cb_type: Literal["number", "size"] = "number",
1446
+ ) -> List[AnnotationInfo]:
1447
+ """
1448
+ Get list of AnnotationInfos for given dataset ID from API.
1449
+
1450
+ :param dataset_id: Dataset ID in Supervisely.
1451
+ :type dataset_id: int
1452
+ :param image_ids: List of integers.
1453
+ :type image_ids: List[int]
1454
+ :param semaphore: Semaphore for limiting the number of simultaneous downloads.
1455
+ :type semaphore: asyncio.Semaphore, optional
1456
+ :param with_custom_data: Include custom data in the response.
1457
+ :type with_custom_data: bool, optional
1458
+ :param force_metadata_for_links: Force metadata for links.
1459
+ :type force_metadata_for_links: bool, optional
1460
+ :param progress_cb: Function for tracking download progress. Total should be equal to len(image_ids) or None.
1461
+ :type progress_cb: tqdm or callable, optional
1462
+ :param progress_cb_type: Type of progress callback. Can be "number" or "size". Default is "number".
1463
+ :type progress_cb_type: str, optional
1464
+ :return: Information about Annotations. See :class:`info_sequence<info_sequence>`
1465
+ :rtype: :class:`List[AnnotationInfo]`
1466
+
1467
+ :Usage example:
1468
+
1469
+ .. code-block:: python
1470
+
1471
+ import supervisely as sly
1472
+
1473
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
1474
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
1475
+ api = sly.Api.from_env()
1476
+
1477
+ dataset_id = 254737
1478
+ image_ids = [121236918, 121236919]
1479
+ pbar = tqdm(desc="Download annotations", total=len(image_ids))
1480
+
1481
+ loop = sly.utils.get_or_create_event_loop()
1482
+ ann_infos = loop.run_until_complete(
1483
+ api.annotation.download_batch_async(dataset_id, image_ids, progress_cb=pbar)
1484
+ )
1485
+ """
1486
+
1487
+ # use context to avoid redundant API calls
1488
+ context = self._api.optimization_context
1489
+ context_dataset_id = context.get("dataset_id")
1490
+ project_meta = context.get("project_meta")
1491
+ project_id = context.get("project_id")
1492
+ if dataset_id != context_dataset_id:
1493
+ context["dataset_id"] = dataset_id
1494
+ project_id, project_meta = None, None
1495
+
1496
+ if not isinstance(project_meta, ProjectMeta):
1497
+ if project_id is None:
1498
+ project_id = self._api.dataset.get_info_by_id(dataset_id).project_id
1499
+ context["project_id"] = project_id
1500
+ project_meta = ProjectMeta.from_json(self._api.project.get_meta(project_id))
1501
+ context["project_meta"] = project_meta
1502
+
1503
+ if semaphore is None:
1504
+ semaphore = self._api._get_default_semaphore()
1505
+ tasks = []
1506
+ for image in image_ids:
1507
+ task = self.download_async(
1508
+ image_id=image,
1509
+ semaphore=semaphore,
1510
+ with_custom_data=with_custom_data,
1511
+ force_metadata_for_links=force_metadata_for_links,
1512
+ progress_cb=progress_cb,
1513
+ progress_cb_type=progress_cb_type,
1514
+ )
1515
+ tasks.append(task)
1516
+ ann_infos = await asyncio.gather(*tasks)
1517
+ return ann_infos
supervisely/api/api.py CHANGED
@@ -1248,7 +1248,7 @@ class Api:
1248
1248
  raise ValueError(
1249
1249
  f"Streamed size does not match the expected: {total_streamed} != {expected_size}"
1250
1250
  )
1251
- logger.debug(f"Streamed size: {total_streamed}, expected size: {expected_size}")
1251
+ logger.trace(f"Streamed size: {total_streamed}, expected size: {expected_size}")
1252
1252
  return
1253
1253
  except httpx.RequestError as e:
1254
1254
  retry_range_start = total_streamed + (range_start or 0)
@@ -1478,7 +1478,7 @@ class Api:
1478
1478
  raise ValueError(
1479
1479
  f"Streamed size does not match the expected: {total_streamed} != {expected_size}"
1480
1480
  )
1481
- logger.debug(f"Streamed size: {total_streamed}, expected size: {expected_size}")
1481
+ logger.trace(f"Streamed size: {total_streamed}, expected size: {expected_size}")
1482
1482
  return
1483
1483
  except httpx.RequestError as e:
1484
1484
  retry_range_start = total_streamed + (range_start or 0)
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import json
5
+ import time
5
6
  from dataclasses import dataclass
6
7
  from time import sleep
7
8
  from typing import Any, Dict, List, NamedTuple, Optional, Union
@@ -536,10 +537,7 @@ class AppApi(TaskApi):
536
537
  self._enabled = True
537
538
  if is_development():
538
539
  self._enabled = False
539
- logger.warning(
540
- "Workflow is disabled in development mode. "
541
- "To enable it, use `api.app.workflow.enable()` right after Api initialization."
542
- )
540
+ self.__last_warning_time = None
543
541
 
544
542
  def enable(self):
545
543
  """Enable the workflow functionality."""
@@ -574,10 +572,18 @@ class AppApi(TaskApi):
574
572
  if min_instance_version is not None
575
573
  else self._min_instance_version
576
574
  )
577
- if (
578
- not check_workflow_compatibility(self._api, version_to_check)
579
- or not self._enabled
580
- ):
575
+ if not self.is_enabled():
576
+ if (
577
+ self.__last_warning_time is None
578
+ or time.monotonic() - self.__last_warning_time > 60
579
+ ):
580
+ self.__last_warning_time = time.monotonic()
581
+ logger.warning(
582
+ "Workflow is disabled in development mode. "
583
+ "To enable it, use `api.app.workflow.enable()` right after Api initialization."
584
+ )
585
+ return
586
+ if not check_workflow_compatibility(self._api, version_to_check):
581
587
  logger.info(f"Workflow method `{func.__name__}` is disabled.")
582
588
  return
583
589
  return func(self, *args, **kwargs)
@@ -6,10 +6,11 @@ from __future__ import annotations
6
6
  import json
7
7
  import re
8
8
  from collections import defaultdict
9
- from typing import Dict, Generator, List, NamedTuple, Optional, Tuple
9
+ from typing import Callable, Dict, Generator, List, NamedTuple, Optional, Tuple, Union
10
10
 
11
11
  import numpy as np
12
12
  from requests_toolbelt import MultipartDecoder, MultipartEncoder
13
+ from tqdm import tqdm
13
14
 
14
15
  from supervisely._utils import batched
15
16
  from supervisely.api.module_api import ApiField, ModuleApi, RemoveableBulkModuleApi
@@ -540,17 +541,25 @@ class FigureApi(RemoveableBulkModuleApi):
540
541
  """
541
542
  return self.download_geometries_batch([figure_id])
542
543
 
543
- def download_geometries_batch(self, ids: List[int]) -> List[dict]:
544
+ def download_geometries_batch(
545
+ self,
546
+ ids: List[int],
547
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
548
+ ) -> List[dict]:
544
549
  """
545
550
  Download figure geometries with given IDs from storage.
546
551
 
547
552
  :param ids: List of figure IDs in Supervisely.
548
553
  :type ids: List[int]
554
+ :param progress_cb: Progress bar to show the download progress. Shows the number of bytes downloaded.
555
+ :type progress_cb: Union[tqdm, Callable], optional
549
556
  :return: List of figure geometries in Supervisely JSON format.
550
557
  :rtype: List[dict]
551
558
  """
552
559
  geometries = {}
553
560
  for idx, part in self._download_geometries_generator(ids):
561
+ if progress_cb is not None:
562
+ progress_cb(len(part.content))
554
563
  geometry_json = json.loads(part.content)
555
564
  geometries[idx] = geometry_json
556
565
 
@@ -14,6 +14,7 @@ from time import time
14
14
  from typing import Callable, Dict, List, NamedTuple, Optional, Union
15
15
 
16
16
  import aiofiles
17
+ import httpx
17
18
  import requests
18
19
  from dotenv import load_dotenv
19
20
  from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
@@ -1641,8 +1642,7 @@ class FileApi(ModuleApiBase):
1641
1642
 
1642
1643
  path_to_file = "/999_App_Test/ds1/01587.json"
1643
1644
  local_save_path = "/path/to/save/999_App_Test/ds1/01587.json"
1644
- loop = asyncio.new_event_loop()
1645
- asyncio.set_event_loop(loop)
1645
+ loop = sly.utils.get_or_create_event_loop()
1646
1646
  loop.run_until_complete(api.file.download_async(8, path_to_file, local_save_path))
1647
1647
  """
1648
1648
  if semaphore is None:
@@ -1756,8 +1756,7 @@ class FileApi(ModuleApiBase):
1756
1756
  "/path/to/save/999_App_Test/ds1/01588.json",
1757
1757
  "/path/to/save/999_App_Test/ds1/01587.json"
1758
1758
  ]
1759
- loop = asyncio.new_event_loop()
1760
- asyncio.set_event_loop(loop)
1759
+ loop = sly.utils.get_or_create_event_loop()
1761
1760
  loop.run_until_complete(
1762
1761
  api.file.download_bulk_async(8, paths_to_files, local_paths)
1763
1762
  )
@@ -1830,8 +1829,7 @@ class FileApi(ModuleApiBase):
1830
1829
  path_to_dir = "/files/folder"
1831
1830
  local_path = "path/to/local/folder"
1832
1831
 
1833
- loop = asyncio.new_event_loop()
1834
- asyncio.set_event_loop(loop)
1832
+ loop = sly.utils.get_or_create_event_loop()
1835
1833
  loop.run_until_complete(
1836
1834
  api.file.download_directory_async(9, path_to_dir, local_path)
1837
1835
  )
@@ -1918,8 +1916,7 @@ class FileApi(ModuleApiBase):
1918
1916
 
1919
1917
  # Application is started...
1920
1918
  save_path = "/my_app_data"
1921
- loop = asyncio.new_event_loop()
1922
- asyncio.set_event_loop(loop)
1919
+ loop = sly.utils.get_or_create_event_loop()
1923
1920
  loop.run_until_complete(
1924
1921
  api.file.download_input_async(save_path)
1925
1922
  )
@@ -2008,3 +2005,142 @@ class FileApi(ModuleApiBase):
2008
2005
  semaphore=semaphore,
2009
2006
  show_progress=show_progress,
2010
2007
  )
2008
+
2009
+ async def upload_async(
2010
+ self,
2011
+ team_id: int,
2012
+ src: str,
2013
+ dst: str,
2014
+ semaphore: Optional[asyncio.Semaphore] = None,
2015
+ # chunk_size: int = 1024 * 1024, #TODO add with resumaple api
2016
+ # check_hash: bool = True, #TODO add with resumaple api
2017
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
2018
+ progress_cb_type: Literal["number", "size"] = "size",
2019
+ ) -> httpx.Response:
2020
+ """
2021
+ Upload file from local path to Team Files asynchronously.
2022
+
2023
+ :param team_id: Team ID in Supervisely.
2024
+ :type team_id: int
2025
+ :param src: Local path to file.
2026
+ :type src: str
2027
+ :param dst: Path to save file in Team Files.
2028
+ :type dst: str
2029
+ :param semaphore: Semaphore for limiting the number of simultaneous uploads.
2030
+ :type semaphore: asyncio.Semaphore, optional
2031
+ :param progress_cb: Function for tracking download progress.
2032
+ :type progress_cb: tqdm or callable, optional
2033
+ :param progress_cb_type: Type of progress callback. Can be "number" or "size". Default is "size".
2034
+ :type progress_cb_type: Literal["number", "size"], optional
2035
+ :return: Response from API.
2036
+ :rtype: :class:`httpx.Response`
2037
+ :Usage example:
2038
+
2039
+ .. code-block:: python
2040
+
2041
+ import supervisely as sly
2042
+ import asyncio
2043
+
2044
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
2045
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
2046
+ api = sly.Api.from_env()
2047
+
2048
+ path_to_file = "/path/to/local/file/01587.json"
2049
+ path_to_save = "/files/01587.json"
2050
+ loop = sly.utils.get_or_create_event_loop()
2051
+ loop.run_until_complete(
2052
+ api.file.upload_async(8, path_to_file, path_to_save)
2053
+ )
2054
+ """
2055
+ api_method = "file-storage.upload"
2056
+ headers = {"Content-Type": "application/octet-stream"}
2057
+ # sha256 = await get_file_hash_async(src) #TODO add with resumaple api
2058
+ json_body = {
2059
+ ApiField.TEAM_ID: team_id,
2060
+ ApiField.PATH: dst,
2061
+ # "sha256": sha256, #TODO add with resumaple api
2062
+ }
2063
+ if semaphore is None:
2064
+ semaphore = self._api._get_default_semaphore()
2065
+ async with semaphore:
2066
+ async with aiofiles.open(src, "rb") as fd:
2067
+ item = await fd.read()
2068
+ response = await self._api.post_async(
2069
+ api_method, content=item, params=json_body, headers=headers
2070
+ )
2071
+ if progress_cb is not None and progress_cb_type == "size":
2072
+ progress_cb(len(item))
2073
+ if progress_cb is not None and progress_cb_type == "number":
2074
+ progress_cb(1)
2075
+ return response
2076
+
2077
+ async def upload_bulk_async(
2078
+ self,
2079
+ team_id: int,
2080
+ src_paths: List[str],
2081
+ dst_paths: List[str],
2082
+ semaphore: Optional[asyncio.Semaphore] = None,
2083
+ # chunk_size: int = 1024 * 1024, #TODO add with resumaple api
2084
+ # check_hash: bool = True, #TODO add with resumaple api
2085
+ progress_cb: Optional[Union[tqdm, Callable]] = None,
2086
+ progress_cb_type: Literal["number", "size"] = "size",
2087
+ ) -> None:
2088
+ """
2089
+ Upload multiple files from local paths to Team Files asynchronously.
2090
+
2091
+ :param team_id: Team ID in Supervisely.
2092
+ :type team_id: int
2093
+ :param src_paths: List of local paths to files.
2094
+ :type src_paths: List[str]
2095
+ :param dst_paths: List of paths to save files in Team Files.
2096
+ :type dst_paths: List[str]
2097
+ :param semaphore: Semaphore for limiting the number of simultaneous uploads.
2098
+ :type semaphore: asyncio.Semaphore, optional
2099
+ :param progress_cb: Function for tracking download progress.
2100
+ :type progress_cb: tqdm or callable, optional
2101
+ :param progress_cb_type: Type of progress callback. Can be "number" or "size". Default is "size".
2102
+ :type progress_cb_type: Literal["number", "size"], optional
2103
+ :return: None
2104
+ :rtype: :class:`NoneType`
2105
+ :Usage example:
2106
+
2107
+ .. code-block:: python
2108
+
2109
+ import supervisely as sly
2110
+ import asyncio
2111
+
2112
+ os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
2113
+ os.environ['API_TOKEN'] = 'Your Supervisely API Token'
2114
+ api = sly.Api.from_env()
2115
+
2116
+ paths_to_files = [
2117
+ "/path/to/local/file/01587.json",
2118
+ "/path/to/local/file/01588.json",
2119
+ "/path/to/local/file/01589.json"
2120
+ ]
2121
+ paths_to_save = [
2122
+ "/files/01587.json",
2123
+ "/files/01588.json",
2124
+ "/files/01589.json"
2125
+ ]
2126
+ loop = sly.utils.get_or_create_event_loop()
2127
+ loop.run_until_complete(
2128
+ api.file.upload_bulk_async(8, paths_to_files, paths_to_save)
2129
+ )
2130
+ """
2131
+ if semaphore is None:
2132
+ semaphore = self._api._get_default_semaphore()
2133
+ tasks = []
2134
+ for s, d in zip(src_paths, dst_paths):
2135
+ task = self.upload_async(
2136
+ team_id,
2137
+ s,
2138
+ d,
2139
+ semaphore=semaphore,
2140
+ # chunk_size=chunk_size, #TODO add with resumaple api
2141
+ # check_hash=check_hash, #TODO add with resumaple api
2142
+ progress_cb=progress_cb,
2143
+ progress_cb_type=progress_cb_type,
2144
+ )
2145
+ tasks.append(task)
2146
+ await asyncio.gather(*tasks)
@@ -3604,8 +3604,7 @@ class ImageApi(RemoveableBulkModuleApi):
3604
3604
  semaphore = asyncio.Semaphore(100)
3605
3605
  images = api.image.get_list(DATASET_ID)
3606
3606
  img_ids = [image.id for image in images]
3607
- loop = asyncio.new_event_loop()
3608
- asyncio.set_event_loop(loop)
3607
+ loop = sly.utils.get_or_create_event_loop()
3609
3608
  results = loop.run_until_complete(
3610
3609
  api.image.download_nps_async(img_ids, semaphore)
3611
3610
  )
@@ -3671,8 +3670,7 @@ class ImageApi(RemoveableBulkModuleApi):
3671
3670
  save_path = os.path.join("/path/to/save/", img_info.name)
3672
3671
 
3673
3672
  semaphore = asyncio.Semaphore(100)
3674
- loop = asyncio.new_event_loop()
3675
- asyncio.set_event_loop(loop)
3673
+ loop = sly.utils.get_or_create_event_loop()
3676
3674
  loop.run_until_complete(
3677
3675
  api.image.download_path_async(img_info.id, save_path, semaphore)
3678
3676
  )
@@ -3756,8 +3754,7 @@ class ImageApi(RemoveableBulkModuleApi):
3756
3754
 
3757
3755
  ids = [770918, 770919]
3758
3756
  paths = ["/path/to/save/image1.png", "/path/to/save/image2.png"]
3759
- loop = asyncio.new_event_loop()
3760
- asyncio.set_event_loop(loop)
3757
+ loop = sly.utils.get_or_create_event_loop()
3761
3758
  loop.run_until_complete(api.image.download_paths_async(ids, paths))
3762
3759
  """
3763
3760
  if len(ids) == 0:
@@ -3828,8 +3825,7 @@ class ImageApi(RemoveableBulkModuleApi):
3828
3825
  api = sly.Api.from_env()
3829
3826
 
3830
3827
  img_id = 770918
3831
- loop = asyncio.new_event_loop()
3832
- asyncio.set_event_loop(loop)
3828
+ loop = sly.utils.get_or_create_event_loop()
3833
3829
  img_bytes = loop.run_until_complete(api.image.download_bytes_async(img_id))
3834
3830
 
3835
3831
  """
@@ -3906,8 +3902,7 @@ class ImageApi(RemoveableBulkModuleApi):
3906
3902
  os.environ['API_TOKEN
3907
3903
  api = sly.Api.from_env()
3908
3904
 
3909
- loop = asyncio.new_event_loop()
3910
- asyncio.set_event_loop(loop)
3905
+ loop = sly.utils.get_or_create_event_loop()
3911
3906
  semaphore = asyncio.Semaphore(100)
3912
3907
  img_bytes_list = loop.run_until_complete(api.image.download_bytes_imgs_async(ids, semaphore))
3913
3908
  """
@@ -1149,8 +1149,7 @@ class PointcloudApi(RemoveableBulkModuleApi):
1149
1149
  save_path = os.path.join("/path/to/save/", pcd_info.name)
1150
1150
 
1151
1151
  semaphore = asyncio.Semaphore(100)
1152
- loop = asyncio.new_event_loop()
1153
- asyncio.set_event_loop(loop)
1152
+ loop = sly.utils.get_or_create_event_loop()
1154
1153
  loop.run_until_complete(
1155
1154
  api.pointcloud.download_path_async(pcd_info.id, save_path, semaphore)
1156
1155
  )
@@ -1241,8 +1240,7 @@ class PointcloudApi(RemoveableBulkModuleApi):
1241
1240
 
1242
1241
  ids = [19373403, 19373404]
1243
1242
  paths = ["/path/to/save/000063.pcd", "/path/to/save/000064.pcd"]
1244
- loop = asyncio.new_event_loop()
1245
- asyncio.set_event_loop(loop)
1243
+ loop = sly.utils.get_or_create_event_loop()
1246
1244
  loop.run_until_complete(api.pointcloud.download_paths_async(ids, paths))
1247
1245
  """
1248
1246
  if len(ids) == 0:
@@ -1313,8 +1311,7 @@ class PointcloudApi(RemoveableBulkModuleApi):
1313
1311
  save_path = os.path.join("/path/to/save/", img_info.name)
1314
1312
 
1315
1313
  semaphore = asyncio.Semaphore(100)
1316
- loop = asyncio.new_event_loop()
1317
- asyncio.set_event_loop(loop)
1314
+ loop = sly.utils.get_or_create_event_loop()
1318
1315
  loop.run_until_complete(
1319
1316
  api.pointcloud.download_related_image_async(19373403, save_path, semaphore)
1320
1317
  )
@@ -1395,8 +1392,7 @@ class PointcloudApi(RemoveableBulkModuleApi):
1395
1392
  save_paths = [os.path.join("/path/to/save/", img_info.name) for img_info in img_infos]
1396
1393
 
1397
1394
  semaphore = asyncio.Semaphore(100)
1398
- loop = asyncio.new_event_loop()
1399
- asyncio.set_event_loop(loop)
1395
+ loop = sly.utils.get_or_create_event_loop()
1400
1396
  loop.run_until_complete(
1401
1397
  api.pointcloud.download_related_images_async(ids, save_paths, semaphore)
1402
1398
  )