supervisely 6.73.231__py3-none-any.whl → 6.73.232__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/api/api.py CHANGED
@@ -67,6 +67,7 @@ from supervisely._utils import camel_to_snake, is_community, is_development
67
67
  from supervisely.api.module_api import ApiField
68
68
  from supervisely.io.network_exceptions import (
69
69
  process_requests_exception,
70
+ process_requests_exception_async,
70
71
  process_unhandled_request,
71
72
  )
72
73
  from supervisely.project.project_meta import ProjectMeta
@@ -806,10 +807,13 @@ class Api:
806
807
  reason = "Can't get reason"
807
808
 
808
809
  def decode_response_content(response: httpx.Response):
809
- if hasattr(response, "is_stream_consumed"):
810
- return "Content is not acessible for streaming responses"
811
- else:
810
+ try:
812
811
  return response.content.decode("utf-8")
812
+ except Exception as e:
813
+ if hasattr(response, "is_stream_consumed"):
814
+ return f"Stream is consumed. {e}"
815
+ else:
816
+ return f"Can't decode response content: {e}"
813
817
 
814
818
  if 400 <= response.status_code < 500:
815
819
  http_error_msg = "%s Client Error: %s for url: %s (%s)" % (
@@ -1058,7 +1062,15 @@ class Api:
1058
1062
  self._check_version()
1059
1063
  Api._raise_for_status_httpx(response)
1060
1064
  return response
1061
- except httpx.RequestError as exc:
1065
+ except (httpx.RequestError, httpx.HTTPStatusError) as exc:
1066
+ if (
1067
+ isinstance(exc, httpx.HTTPStatusError)
1068
+ and response.status_code == 400
1069
+ and self.token is None
1070
+ ):
1071
+ self.logger.warning(
1072
+ "API_TOKEN env variable is undefined. See more: https://developer.supervisely.com/getting-started/basics-of-authentication"
1073
+ )
1062
1074
  if raise_error:
1063
1075
  raise exc
1064
1076
  else:
@@ -1123,7 +1135,15 @@ class Api:
1123
1135
  if response.status_code != httpx.codes.OK:
1124
1136
  Api._raise_for_status_httpx(response)
1125
1137
  return response
1126
- except httpx.RequestError as exc:
1138
+ except (httpx.RequestError, httpx.HTTPStatusError) as exc:
1139
+ if (
1140
+ isinstance(exc, httpx.HTTPStatusError)
1141
+ and response.status_code == 400
1142
+ and self.token is None
1143
+ ):
1144
+ self.logger.warning(
1145
+ "API_TOKEN env variable is undefined. See more: https://developer.supervisely.com/getting-started/basics-of-authentication"
1146
+ )
1127
1147
  process_requests_exception(
1128
1148
  self.logger,
1129
1149
  exc,
@@ -1260,7 +1280,15 @@ class Api:
1260
1280
  )
1261
1281
  logger.trace(f"Streamed size: {total_streamed}, expected size: {expected_size}")
1262
1282
  return
1263
- except httpx.RequestError as e:
1283
+ except (httpx.RequestError, httpx.HTTPStatusError) as e:
1284
+ if (
1285
+ isinstance(e, httpx.HTTPStatusError)
1286
+ and resp.status_code == 400
1287
+ and self.token is None
1288
+ ):
1289
+ self.logger.warning(
1290
+ "API_TOKEN env variable is undefined. See more: https://developer.supervisely.com/getting-started/basics-of-authentication"
1291
+ )
1264
1292
  retry_range_start = total_streamed + (range_start or 0)
1265
1293
  if total_streamed != 0:
1266
1294
  retry_range_start += 1
@@ -1348,11 +1376,19 @@ class Api:
1348
1376
  self._check_version()
1349
1377
  Api._raise_for_status_httpx(response)
1350
1378
  return response
1351
- except httpx.RequestError as exc:
1379
+ except (httpx.RequestError, httpx.HTTPStatusError) as exc:
1380
+ if (
1381
+ isinstance(exc, httpx.HTTPStatusError)
1382
+ and response.status_code == 400
1383
+ and self.token is None
1384
+ ):
1385
+ self.logger.warning(
1386
+ "API_TOKEN env variable is undefined. See more: https://developer.supervisely.com/getting-started/basics-of-authentication"
1387
+ )
1352
1388
  if raise_error:
1353
1389
  raise exc
1354
1390
  else:
1355
- process_requests_exception(
1391
+ await process_requests_exception_async(
1356
1392
  self.logger,
1357
1393
  exc,
1358
1394
  method,
@@ -1489,13 +1525,21 @@ class Api:
1489
1525
  )
1490
1526
  logger.trace(f"Streamed size: {total_streamed}, expected size: {expected_size}")
1491
1527
  return
1492
- except httpx.RequestError as e:
1528
+ except (httpx.RequestError, httpx.HTTPStatusError) as e:
1529
+ if (
1530
+ isinstance(e, httpx.HTTPStatusError)
1531
+ and resp.status_code == 400
1532
+ and self.token is None
1533
+ ):
1534
+ self.logger.warning(
1535
+ "API_TOKEN env variable is undefined. See more: https://developer.supervisely.com/getting-started/basics-of-authentication"
1536
+ )
1493
1537
  retry_range_start = total_streamed + (range_start or 0)
1494
1538
  if total_streamed != 0:
1495
1539
  retry_range_start += 1
1496
1540
  headers["Range"] = f"bytes={retry_range_start}-{range_end or ''}"
1497
1541
  logger.debug(f"Setting Range header {headers['Range']} for retry")
1498
- process_requests_exception(
1542
+ await process_requests_exception_async(
1499
1543
  self.logger,
1500
1544
  e,
1501
1545
  method,
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
+ import asyncio
3
4
  import time
4
5
  import traceback
5
6
 
@@ -27,6 +28,92 @@ RETRY_STATUS_CODES = {
27
28
  }
28
29
 
29
30
 
31
+ async def process_requests_exception_async(
32
+ external_logger,
33
+ exc,
34
+ api_method_name,
35
+ url,
36
+ verbose=True,
37
+ swallow_exc=False,
38
+ sleep_sec=None,
39
+ response=None,
40
+ retry_info=None,
41
+ ):
42
+ recommended_sleep = None
43
+ try:
44
+ if hasattr(exc, "response") and exc.response.status_code == 429:
45
+ recommended_sleep = exc.response.headers.get("Retry-After")
46
+ elif response is not None and response.status_code == 429:
47
+ recommended_sleep = response.headers.get("Retry-After")
48
+ if recommended_sleep and int(recommended_sleep) > sleep_sec:
49
+ sleep_sec = int(recommended_sleep)
50
+ except Exception:
51
+ pass
52
+
53
+ is_connection_error = isinstance(
54
+ exc,
55
+ (
56
+ requests.exceptions.ConnectionError,
57
+ requests.exceptions.Timeout,
58
+ requests.exceptions.TooManyRedirects,
59
+ requests.exceptions.ChunkedEncodingError,
60
+ httpx.NetworkError,
61
+ httpx.TimeoutException,
62
+ httpx.TooManyRedirects,
63
+ httpx.ProtocolError,
64
+ ),
65
+ )
66
+
67
+ is_server_retryable_error = (
68
+ isinstance(exc, (requests.exceptions.HTTPError, httpx.HTTPStatusError))
69
+ and hasattr(exc, "response")
70
+ and (exc.response.status_code in RETRY_STATUS_CODES)
71
+ )
72
+
73
+ is_need_ping_error = False
74
+ if (
75
+ isinstance(exc, (requests.exceptions.HTTPError, httpx.HTTPStatusError))
76
+ and hasattr(exc, "response")
77
+ and (exc.response.status_code == 400)
78
+ ):
79
+ try:
80
+ server_explanation = exc.response.json()
81
+ is_need_ping_error = server_explanation.get("error", None) == SPECIAL_RECONNECT_ERROR
82
+ except (AttributeError, ValueError):
83
+ pass
84
+
85
+ if is_connection_error or is_server_retryable_error:
86
+ await process_retryable_request_async(
87
+ external_logger,
88
+ exc,
89
+ api_method_name,
90
+ url,
91
+ CONNECTION_ERROR,
92
+ verbose=verbose,
93
+ swallow_exc=swallow_exc,
94
+ sleep_sec=sleep_sec,
95
+ retry_info=retry_info,
96
+ )
97
+ elif is_need_ping_error:
98
+ await process_retryable_request_async(
99
+ external_logger,
100
+ exc,
101
+ api_method_name,
102
+ url,
103
+ AGENT_CONNECTION_ERROR,
104
+ verbose=verbose,
105
+ swallow_exc=swallow_exc,
106
+ sleep_sec=sleep_sec,
107
+ retry_info=retry_info,
108
+ )
109
+ elif response is None:
110
+ process_unhandled_request(external_logger, exc)
111
+ elif isinstance(exc, (requests.exceptions.HTTPError, httpx.HTTPStatusError)):
112
+ process_invalid_request(external_logger, exc, response, verbose)
113
+ else:
114
+ process_unhandled_request(external_logger, exc)
115
+
116
+
30
117
  def process_requests_exception(
31
118
  external_logger,
32
119
  exc,
@@ -38,6 +125,17 @@ def process_requests_exception(
38
125
  response=None,
39
126
  retry_info=None,
40
127
  ):
128
+ recommended_sleep = None
129
+ try:
130
+ if hasattr(exc, "response") and exc.response.status_code == 429:
131
+ recommended_sleep = exc.response.headers.get("Retry-After")
132
+ elif response is not None and response.status_code == 429:
133
+ recommended_sleep = response.headers.get("Retry-After")
134
+ if recommended_sleep and int(recommended_sleep) > sleep_sec:
135
+ sleep_sec = int(recommended_sleep)
136
+ except Exception:
137
+ pass
138
+
41
139
  is_connection_error = isinstance(
42
140
  exc,
43
141
  (
@@ -45,7 +143,7 @@ def process_requests_exception(
45
143
  requests.exceptions.Timeout,
46
144
  requests.exceptions.TooManyRedirects,
47
145
  requests.exceptions.ChunkedEncodingError,
48
- httpx.ConnectError,
146
+ httpx.NetworkError,
49
147
  httpx.TimeoutException,
50
148
  httpx.TooManyRedirects,
51
149
  httpx.ProtocolError,
@@ -102,6 +200,33 @@ def process_requests_exception(
102
200
  process_unhandled_request(external_logger, exc)
103
201
 
104
202
 
203
+ async def process_retryable_request_async(
204
+ external_logger,
205
+ exc,
206
+ api_method_name,
207
+ url,
208
+ user_message,
209
+ verbose=True,
210
+ swallow_exc=False,
211
+ sleep_sec=None,
212
+ retry_info=None,
213
+ ):
214
+ if retry_info is not None:
215
+ retry_idx = retry_info["retry_idx"]
216
+ retry_limit = retry_info["retry_limit"]
217
+ user_message = "{}: Retrying ({}/{}).".format(user_message, retry_idx, retry_limit)
218
+ if verbose:
219
+ external_logger.warn(
220
+ user_message, extra={"method": api_method_name, "url": url, "details": str(exc)}
221
+ )
222
+
223
+ if sleep_sec is not None:
224
+ await asyncio.sleep(sleep_sec)
225
+
226
+ if not swallow_exc:
227
+ raise exc
228
+
229
+
105
230
  def process_retryable_request(
106
231
  external_logger,
107
232
  exc,
@@ -580,7 +580,8 @@ class Inference:
580
580
  continue
581
581
  if "classes_whitelist" in inspect.signature(self._create_label).parameters:
582
582
  # pylint: disable=unexpected-keyword-arg
583
- label = self._create_label(prediction, classes_whitelist) # pylint: disable=too-many-function-args
583
+ # pylint: disable=too-many-function-args
584
+ label = self._create_label(prediction, classes_whitelist)
584
585
  else:
585
586
  label = self._create_label(prediction)
586
587
  if label is None:
@@ -36,6 +36,7 @@ from supervisely.collection.key_indexed_collection import (
36
36
  from supervisely.geometry.bitmap import Bitmap
37
37
  from supervisely.imaging import image as sly_image
38
38
  from supervisely.io.fs import (
39
+ clean_dir,
39
40
  copy_file,
40
41
  copy_file_async,
41
42
  dir_empty,
@@ -3592,7 +3593,14 @@ def _download_project(
3592
3593
  meta = ProjectMeta.from_json(api.project.get_meta(project_id, with_settings=True))
3593
3594
  if os.path.exists(dest_dir) and resume_download:
3594
3595
  dump_json_file(meta.to_json(), os.path.join(dest_dir, "meta.json"))
3595
- project_fs = Project(dest_dir, OpenMode.READ)
3596
+ try:
3597
+ project_fs = Project(dest_dir, OpenMode.READ)
3598
+ except RuntimeError as e:
3599
+ if "Project is empty" in str(e):
3600
+ clean_dir(dest_dir)
3601
+ project_fs = None
3602
+ else:
3603
+ raise
3596
3604
  if project_fs is None:
3597
3605
  project_fs = Project(dest_dir, OpenMode.CREATE)
3598
3606
  project_fs.set_meta(meta)
@@ -4394,7 +4402,14 @@ async def _download_project_async(
4394
4402
  meta = ProjectMeta.from_json(api.project.get_meta(project_id, with_settings=True))
4395
4403
  if os.path.exists(dest_dir) and resume_download:
4396
4404
  dump_json_file(meta.to_json(), os.path.join(dest_dir, "meta.json"))
4397
- project_fs = Project(dest_dir, OpenMode.READ)
4405
+ try:
4406
+ project_fs = Project(dest_dir, OpenMode.READ)
4407
+ except RuntimeError as e:
4408
+ if "Project is empty" in str(e):
4409
+ clean_dir(dest_dir)
4410
+ project_fs = None
4411
+ else:
4412
+ raise
4398
4413
  if project_fs is None:
4399
4414
  project_fs = Project(dest_dir, OpenMode.CREATE)
4400
4415
  project_fs.set_meta(meta)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: supervisely
3
- Version: 6.73.231
3
+ Version: 6.73.232
4
4
  Summary: Supervisely Python SDK.
5
5
  Home-page: https://github.com/supervisely/supervisely
6
6
  Author: Supervisely
@@ -22,7 +22,7 @@ supervisely/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  supervisely/api/advanced_api.py,sha256=Nd5cCnHFWc3PSUrCtENxTGtDjS37_lCHXsgXvUI3Ti8,2054
23
23
  supervisely/api/agent_api.py,sha256=ShWAIlXcWXcyI9fqVuP5GZVCigCMJmjnvdGUfLspD6Y,8890
24
24
  supervisely/api/annotation_api.py,sha256=s9kd1G759R8YSvbDcNXrPa9xv95j1cWE1RgD6XeJe2A,58826
25
- supervisely/api/api.py,sha256=kDx9uE8fiRDnyJVuw4hG0YTuCglhzHQgnTa2-a4YEEM,62424
25
+ supervisely/api/api.py,sha256=SI7DuSi2Jnj5NFS_V9aQ9Sg3CrS97Y5p1pqeeb-4Jb4,64729
26
26
  supervisely/api/app_api.py,sha256=-T4sISQ7POyR2yirf1kEWj4JaJFpJxCyRWqbf_99Jak,67036
27
27
  supervisely/api/dataset_api.py,sha256=2-SQBlgEnIN-0uvDbtPlSXr6ztBeZ3WPryhkOtpBmk4,40786
28
28
  supervisely/api/file_api.py,sha256=WMg80fxqMKOo3ai-IGON2w-IDAySPk90USoVk29JOdE,82415
@@ -689,7 +689,7 @@ supervisely/io/fs_cache.py,sha256=985gvBGzveLcDudgz10E4EWVjP9jxdU1Pa0GFfCBoCA,65
689
689
  supervisely/io/github_utils.py,sha256=jGmvQJ5bjtACuSFABzrxL0jJdh14SezovrHp8T-9y8g,1779
690
690
  supervisely/io/json.py,sha256=VvyqXZl22nb6_DJK3TUOPetd5xq9xwRFKumWqsGs7iI,8679
691
691
  supervisely/io/multipart_stream_decoder.py,sha256=rCheeSCAGdw2tNyaWEYa4dvoIDuldXOxH86RVB82c78,14417
692
- supervisely/io/network_exceptions.py,sha256=eegxgbtkbKpbjPdiATXpvUSMpe6AFPiu0IAKyxPSXms,4777
692
+ supervisely/io/network_exceptions.py,sha256=pEhw0jKw_p-Rl42SMOexVU6SW2Z_xIl1kTryNb3EvIQ,8716
693
693
  supervisely/labeling_jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
694
694
  supervisely/labeling_jobs/constants.py,sha256=GF_pwF9fC9_DGbpD3cAk3llifskAxpDmyuXwxM1f3Hw,104
695
695
  supervisely/labeling_jobs/utils.py,sha256=XOGF2cbnTGbXFdT5jGL1LIPQfiCEJgRkmKNIjTlFois,22656
@@ -817,7 +817,7 @@ supervisely/nn/benchmark/visualization/widgets/table/__init__.py,sha256=47DEQpj8
817
817
  supervisely/nn/benchmark/visualization/widgets/table/table.py,sha256=YiCpt-mdINJnNBWsUTPkRR_9w09Ne2Y0n93DY8vsE8I,4090
818
818
  supervisely/nn/inference/__init__.py,sha256=mtEci4Puu-fRXDnGn8RP47o97rv3VTE0hjbYO34Zwqg,1622
819
819
  supervisely/nn/inference/cache.py,sha256=WylgHgPQRIoA_RDks8FyKgHqeZZ_YFoyddxkVvOX2YQ,25713
820
- supervisely/nn/inference/inference.py,sha256=jqhugSdwrKPyimiSxGvsJYLTjAyrxVmOl2FNql6f4aA,116982
820
+ supervisely/nn/inference/inference.py,sha256=CmQe6QnhZuUV128jcIp2YKsgeggAtmc1NL7PdFnc_hw,116997
821
821
  supervisely/nn/inference/session.py,sha256=jmkkxbe2kH-lEgUU6Afh62jP68dxfhF5v6OGDfLU62E,35757
822
822
  supervisely/nn/inference/video_inference.py,sha256=8Bshjr6rDyLay5Za8IB8Dr6FURMO2R_v7aELasO8pR4,5746
823
823
  supervisely/nn/inference/gui/__init__.py,sha256=e3RKi93bI1r_0Dkvs_gaR1p_jkzkBMNjrcx-RVlm93k,88
@@ -935,7 +935,7 @@ supervisely/project/data_version.py,sha256=nknaWJSUCwoDyNG9_d1KA-GjzidhV9zd9Cn8c
935
935
  supervisely/project/download.py,sha256=qonvHBiKX-leHW9qWJdyBqFNmpI2_t9s54e68h9orq0,23687
936
936
  supervisely/project/pointcloud_episode_project.py,sha256=fcaFAaHVn_VvdiIfHl4IyEFE5-Q3VFGfo7_YoxEma0I,41341
937
937
  supervisely/project/pointcloud_project.py,sha256=Y8Xhi6Hg-KyztwFncezuDfKTt2FILss96EU_LdXzmrA,49172
938
- supervisely/project/project.py,sha256=T2ge_9HXlaDyDziEhr-5lcyUcHskaUIbgwtrWs7PqYo,180929
938
+ supervisely/project/project.py,sha256=byf0WUxIvfoqFwq57Yea0hnljHWVrZMYMH8cGCH_rCM,181356
939
939
  supervisely/project/project_meta.py,sha256=26s8IiHC5Pg8B1AQi6_CrsWteioJP2in00cRNe8QlW0,51423
940
940
  supervisely/project/project_settings.py,sha256=NLThzU_DCynOK6hkHhVdFyezwprn9UqlnrLDe_3qhkY,9347
941
941
  supervisely/project/project_type.py,sha256=_3RqW2CnDBKFOvSIrQT1RJQaiHirs34_jiQS8CkwCpo,530
@@ -997,9 +997,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
997
997
  supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
998
998
  supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
999
999
  supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
1000
- supervisely-6.73.231.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1001
- supervisely-6.73.231.dist-info/METADATA,sha256=6Nn3J-8unL0hd-sYLQcavVvRFWolrgNpy30IxKd6-So,33150
1002
- supervisely-6.73.231.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1003
- supervisely-6.73.231.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1004
- supervisely-6.73.231.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1005
- supervisely-6.73.231.dist-info/RECORD,,
1000
+ supervisely-6.73.232.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1001
+ supervisely-6.73.232.dist-info/METADATA,sha256=xZnrkZw3qSVTsMB9IDC8aQsI6xxhZRlM_9LNc9MBjXY,33150
1002
+ supervisely-6.73.232.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
1003
+ supervisely-6.73.232.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
1004
+ supervisely-6.73.232.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
1005
+ supervisely-6.73.232.dist-info/RECORD,,