supervisely 6.73.440__py3-none-any.whl → 6.73.442__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/api/api.py CHANGED
@@ -10,6 +10,7 @@ import glob
10
10
  import json
11
11
  import os
12
12
  import shutil
13
+ import threading
13
14
  from logging import Logger
14
15
  from pathlib import Path
15
16
  from typing import (
@@ -392,13 +393,15 @@ class Api:
392
393
  else not self.server_address.startswith("https://")
393
394
  )
394
395
 
395
- if check_instance_version:
396
- self._check_version(None if check_instance_version is True else check_instance_version)
397
-
398
396
  self.async_httpx_client: httpx.AsyncClient = None
399
397
  self.httpx_client: httpx.Client = None
400
398
  self._semaphore = None
401
399
  self._instance_version = None
400
+ self._version_check_completed = False
401
+ self._version_check_lock = threading.Lock()
402
+
403
+ if check_instance_version:
404
+ self._check_version(None if check_instance_version is True else check_instance_version)
402
405
 
403
406
  @classmethod
404
407
  def normalize_server_address(cls, server_address: str) -> str:
@@ -600,38 +603,49 @@ class Api:
600
603
  :type version: Optional[str], e.g. "6.9.13"
601
604
  """
602
605
 
603
- # Since it's a informational message, we don't raise an exception if the check fails
604
- # in any case, we don't want to interrupt the user's workflow.
605
- try:
606
- check_result = self.is_version_supported(version)
607
- if check_result is None:
606
+ # Thread-safe one-time check with double-checked locking pattern
607
+ if self._version_check_completed:
608
+ return
609
+
610
+ with self._version_check_lock:
611
+ # Double-check inside the lock
612
+ if self._version_check_completed:
613
+ return
614
+
615
+ self._version_check_completed = True
616
+
617
+ # Since it's a informational message, we don't raise an exception if the check fails
618
+ # in any case, we don't want to interrupt the user's workflow.
619
+ try:
620
+ check_result = self.is_version_supported(version)
621
+ if check_result is None:
622
+ logger.debug(
623
+ "Failed to check if the instance version meets the minimum requirements "
624
+ "of current SDK version. "
625
+ "Ensure that the MINIMUM_INSTANCE_VERSION_FOR_SDK environment variable is set. "
626
+ "Usually you can ignore this message, but if you're adding new features, "
627
+ "which will require upgrade of the Supervisely instance, you should update "
628
+ "it supervisely.__init__.py file."
629
+ )
630
+ if check_result is False:
631
+ message = (
632
+ "The current version of the Supervisely instance is not supported by the SDK. "
633
+ "Some features may not work correctly."
634
+ )
635
+ if not is_community():
636
+ message += (
637
+ " Please upgrade the Supervisely instance to the latest version (recommended) "
638
+ "or downgrade the SDK to the version that supports the current instance (not recommended). "
639
+ "Refer to this docs for more information: "
640
+ "https://docs.supervisely.com/enterprise-edition/get-supervisely/upgrade "
641
+ "Check out changelog for the latest version of Supervisely: "
642
+ "https://app.supervisely.com/changelog"
643
+ )
644
+ logger.warning(message)
645
+ except Exception as e:
608
646
  logger.debug(
609
- "Failed to check if the instance version meets the minimum requirements "
610
- "of current SDK version. "
611
- "Ensure that the MINIMUM_INSTANCE_VERSION_FOR_SDK environment variable is set. "
612
- "Usually you can ignore this message, but if you're adding new features, "
613
- "which will require upgrade of the Supervisely instance, you should update "
614
- "it supervisely.__init__.py file."
615
- )
616
- if check_result is False:
617
- message = (
618
- "The current version of the Supervisely instance is not supported by the SDK. "
619
- "Some features may not work correctly."
647
+ f"Tried to check version compatibility between SDK and instance, but failed: {e}"
620
648
  )
621
- if not is_community():
622
- message += (
623
- " Please upgrade the Supervisely instance to the latest version (recommended) "
624
- "or downgrade the SDK to the version that supports the current instance (not recommended). "
625
- "Refer to this docs for more information: "
626
- "https://docs.supervisely.com/enterprise-edition/get-supervisely/upgrade "
627
- "Check out changelog for the latest version of Supervisely: "
628
- "https://app.supervisely.com/changelog"
629
- )
630
- logger.warning(message)
631
- except Exception as e:
632
- logger.debug(
633
- f"Tried to check version compatibility between SDK and instance, but failed: {e}"
634
- )
635
649
 
636
650
  def post(
637
651
  self,
@@ -686,7 +700,8 @@ class Api:
686
700
  )
687
701
 
688
702
  if response.status_code != requests.codes.ok: # pylint: disable=no-member
689
- self._check_version()
703
+ if not self._version_check_completed:
704
+ self._check_version()
690
705
  Api._raise_for_status(response)
691
706
  return response
692
707
  except requests.RequestException as exc:
@@ -1103,7 +1118,8 @@ class Api:
1103
1118
  timeout=timeout,
1104
1119
  )
1105
1120
  if response.status_code != httpx.codes.OK:
1106
- self._check_version()
1121
+ if not self._version_check_completed:
1122
+ self._check_version()
1107
1123
  Api._raise_for_status_httpx(response)
1108
1124
  return response
1109
1125
  except (httpx.RequestError, httpx.HTTPStatusError) as exc:
@@ -1319,7 +1335,8 @@ class Api:
1319
1335
  httpx.codes.OK,
1320
1336
  httpx.codes.PARTIAL_CONTENT,
1321
1337
  ]:
1322
- self._check_version()
1338
+ if not self._version_check_completed:
1339
+ self._check_version()
1323
1340
  Api._raise_for_status_httpx(resp)
1324
1341
 
1325
1342
  hhash = resp.headers.get("x-content-checksum-sha256", None)
@@ -1433,7 +1450,8 @@ class Api:
1433
1450
  timeout=timeout,
1434
1451
  )
1435
1452
  if response.status_code != httpx.codes.OK:
1436
- self._check_version()
1453
+ if not self._version_check_completed:
1454
+ self._check_version()
1437
1455
  Api._raise_for_status_httpx(response)
1438
1456
  return response
1439
1457
  except (httpx.RequestError, httpx.HTTPStatusError) as exc:
@@ -1574,7 +1592,8 @@ class Api:
1574
1592
  httpx.codes.OK,
1575
1593
  httpx.codes.PARTIAL_CONTENT,
1576
1594
  ]:
1577
- self._check_version()
1595
+ if not self._version_check_completed:
1596
+ self._check_version()
1578
1597
  Api._raise_for_status_httpx(resp)
1579
1598
 
1580
1599
  # received hash of the content to check integrity of the data stream
@@ -140,7 +140,7 @@ def check_workflow_compatibility(api, min_instance_version: str) -> bool:
140
140
  "instance_version", api.instance_version
141
141
  )
142
142
 
143
- if instance_version == "unknown":
143
+ if instance_version is None or instance_version == "unknown":
144
144
  # to check again on the next call
145
145
  del _workflow_compatibility_version_cache["instance_version"]
146
146
  logger.info(
@@ -70,7 +70,11 @@ from supervisely.api.module_api import (
70
70
  _get_single_item,
71
71
  )
72
72
  from supervisely.imaging import image as sly_image
73
- from supervisely.io.env import app_categories, increment_upload_count, add_uploaded_ids_to_env
73
+ from supervisely.io.env import (
74
+ add_uploaded_ids_to_env,
75
+ app_categories,
76
+ increment_upload_count,
77
+ )
74
78
  from supervisely.io.fs import (
75
79
  OFFSETS_PKL_BATCH_SIZE,
76
80
  OFFSETS_PKL_SUFFIX,
@@ -5519,3 +5523,66 @@ class ImageApi(RemoveableBulkModuleApi):
5519
5523
  method,
5520
5524
  {ApiField.IMAGES: images},
5521
5525
  )
5526
+
5527
+ def get_subsequent_image_ids(
5528
+ self,
5529
+ image_id: int,
5530
+ images_count: Optional[int] = None,
5531
+ job_id: Optional[int] = None,
5532
+ params: Optional[dict] = None,
5533
+ dataset_id: Optional[int] = None,
5534
+ project_id: Optional[int] = None,
5535
+ ) -> List[int]:
5536
+ """
5537
+ Get list of subsequent image IDs after the specified image ID.
5538
+
5539
+ :param image_id: Image ID in Supervisely.
5540
+ :type image_id: int
5541
+ :param images_count: Number of subsequent images to retrieve. If None, retrieves all subsequent images.
5542
+ :type images_count: int, optional
5543
+ :param job_id: Job ID to filter images. If None, does not filter by job ID.
5544
+ :type job_id: int, optional
5545
+ :param params: Additional parameters for filtering and sorting images.
5546
+ :type params: dict, optional
5547
+ :param dataset_id: Dataset ID to filter images.
5548
+ :type dataset_id: int, optional
5549
+ :param project_id: Project ID to filter images. If None, makes a request to retrieve it from the specified image.
5550
+ :type project_id: int, optional
5551
+ """
5552
+ data = {
5553
+ "recursive": True,
5554
+ "projectId": project_id,
5555
+ "filters": [],
5556
+ "sort": "name",
5557
+ "sort_order": "asc",
5558
+ }
5559
+
5560
+ if params is not None:
5561
+ data.update(params)
5562
+
5563
+ if data["projectId"] is None:
5564
+ image_info = self.get_info_by_id(image_id)
5565
+ if image_info is None:
5566
+ raise ValueError(f"Image with ID {image_id} not found.")
5567
+ project_id = self._api.dataset.get_info_by_id(image_info.dataset_id).project_id
5568
+ if job_id is not None:
5569
+ self._api.add_header("x-job-id", str(job_id))
5570
+ if dataset_id is not None:
5571
+ data["datasetId"] = dataset_id
5572
+
5573
+ image_infos = self.get_list_all_pages(
5574
+ "images.list",
5575
+ data,
5576
+ limit=None,
5577
+ return_first_response=False,
5578
+ )
5579
+ self._api.headers.pop("x-job-id", None)
5580
+ image_ids = [img_info.id for img_info in image_infos]
5581
+ if len(image_ids) == 0:
5582
+ raise ValueError("No images found with the specified criteria.")
5583
+ elif image_id not in image_ids:
5584
+ raise ValueError(f"Image with ID {image_id} not found in the specified entity.")
5585
+
5586
+ target_idx = image_ids.index(image_id) + 1
5587
+ to_idx = target_idx + images_count if images_count is not None else len(image_ids)
5588
+ return image_ids[target_idx:to_idx]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.440
3
+ Version: 6.73.442
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -23,15 +23,15 @@ supervisely/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  supervisely/api/advanced_api.py,sha256=Nd5cCnHFWc3PSUrCtENxTGtDjS37_lCHXsgXvUI3Ti8,2054
24
24
  supervisely/api/agent_api.py,sha256=8EQBwD6v7KLS0-xKcZ12B7mtzKwG7RRgq1fk1vaN144,8893
25
25
  supervisely/api/annotation_api.py,sha256=TNOqVGE94FqDc7WDLBZiDY3aSIiyTQwn_bZv5_CIXBw,82970
26
- supervisely/api/api.py,sha256=gRItQzO6Xj7k_pJIpVUS2dV1vkTTHV25_1Uia6xxZSc,67930
27
- supervisely/api/app_api.py,sha256=Q6XxLxp3D_Vc3PIVyBmP7wJtTLbgYCPNOLND5UvJhMw,79010
26
+ supervisely/api/api.py,sha256=_ZiC1R2lu2eHXw_vBMUiylr-jQcU9-nZZvH5jJHVqoc,68828
27
+ supervisely/api/app_api.py,sha256=OMgmZM7I5nmTn7P9J0F6fpNwWnFE-UO3wzlL1Rciqh4,79038
28
28
  supervisely/api/constants.py,sha256=WfqIcEpRnU4Mcfb6q0njeRs2VVSoTAJaIyrqBkBjP8I,253
29
29
  supervisely/api/dataset_api.py,sha256=BD6kG2lj826ajWjHxmiKEsyWb2Ov6CyTQlItzAxADbo,48955
30
30
  supervisely/api/entities_collection_api.py,sha256=Be13HsfMFLmq9XpiOfQog0Y569kbUn52hXv6x5vX3Vg,22624
31
31
  supervisely/api/file_api.py,sha256=gNXNsikocSYRojoZrVmXIqXycqXm0e320piAwaLN6JI,92978
32
32
  supervisely/api/github_api.py,sha256=NIexNjEer9H5rf5sw2LEZd7C1WR-tK4t6IZzsgeAAwQ,623
33
33
  supervisely/api/image_annotation_tool_api.py,sha256=YcUo78jRDBJYvIjrd-Y6FJAasLta54nnxhyaGyanovA,5237
34
- supervisely/api/image_api.py,sha256=5GBlY_7hYI7RXkBrwjkxGe3YkJktoytA1o9wdeHdIA4,232938
34
+ supervisely/api/image_api.py,sha256=iDxY_PupkZ5CqnFkegcyLohGohE-6PEa6iiClkLIsC8,235489
35
35
  supervisely/api/import_storage_api.py,sha256=BDCgmR0Hv6OoiRHLCVPKt3iDxSVlQp1WrnKhAK_Zl84,460
36
36
  supervisely/api/issues_api.py,sha256=BqDJXmNoTzwc3xe6_-mA7FDFC5QQ-ahGbXk_HmpkSeQ,17925
37
37
  supervisely/api/labeling_job_api.py,sha256=G2_BV_WtA2lAhfw_nAQmWmv1P-pwimD0ba9GVKoGjiA,55537
@@ -1127,9 +1127,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
1127
1127
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
1128
1128
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
1129
1129
  supervisely_lib/__init__.py,sha256=yRwzEQmVwSd6lUQoAUdBngKEOlnoQ6hA9ZcoZGJRNC4,331
1130
- supervisely-6.73.440.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1131
- supervisely-6.73.440.dist-info/METADATA,sha256=IkMNY-vAbGbAjZcZ63wwsWqEcsZQeJH2Zn3NgghAZ5g,35480
1132
- supervisely-6.73.440.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1133
- supervisely-6.73.440.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1134
- supervisely-6.73.440.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1135
- supervisely-6.73.440.dist-info/RECORD,,
1130
+ supervisely-6.73.442.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1131
+ supervisely-6.73.442.dist-info/METADATA,sha256=QnoEurAbF56kquhG3igJuoDl4p4SO571wv2ngekr6Fk,35480
1132
+ supervisely-6.73.442.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
1133
+ supervisely-6.73.442.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1134
+ supervisely-6.73.442.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1135
+ supervisely-6.73.442.dist-info/RECORD,,