supervisely 6.73.231__py3-none-any.whl → 6.73.233__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 +54 -10
- supervisely/api/video/video_api.py +14 -1
- supervisely/io/network_exceptions.py +126 -1
- supervisely/nn/inference/cache.py +79 -18
- supervisely/nn/inference/inference.py +2 -1
- supervisely/project/project.py +17 -2
- {supervisely-6.73.231.dist-info → supervisely-6.73.233.dist-info}/METADATA +1 -1
- {supervisely-6.73.231.dist-info → supervisely-6.73.233.dist-info}/RECORD +12 -12
- {supervisely-6.73.231.dist-info → supervisely-6.73.233.dist-info}/LICENSE +0 -0
- {supervisely-6.73.231.dist-info → supervisely-6.73.233.dist-info}/WHEEL +0 -0
- {supervisely-6.73.231.dist-info → supervisely-6.73.233.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.231.dist-info → supervisely-6.73.233.dist-info}/top_level.txt +0 -0
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1542
|
+
await process_requests_exception_async(
|
|
1499
1543
|
self.logger,
|
|
1500
1544
|
e,
|
|
1501
1545
|
method,
|
|
@@ -1372,6 +1372,19 @@ class VideoApi(RemoveableBulkModuleApi):
|
|
|
1372
1372
|
},
|
|
1373
1373
|
)
|
|
1374
1374
|
|
|
1375
|
+
def notify_tracking_warning(self, track_id: int, video_id: int, message: str):
|
|
1376
|
+
self._api.post(
|
|
1377
|
+
"videos.notify-annotation-tool",
|
|
1378
|
+
data={
|
|
1379
|
+
"type": "videos:tracking-warning",
|
|
1380
|
+
"data": {
|
|
1381
|
+
ApiField.VIDEO_ID: str(video_id),
|
|
1382
|
+
ApiField.TRACK_ID: str(track_id),
|
|
1383
|
+
ApiField.MESSAGE: message,
|
|
1384
|
+
},
|
|
1385
|
+
},
|
|
1386
|
+
)
|
|
1387
|
+
|
|
1375
1388
|
# def upload(self):
|
|
1376
1389
|
# #"/videos.bulk.upload"
|
|
1377
1390
|
# pass
|
|
@@ -2055,7 +2068,7 @@ class VideoApi(RemoveableBulkModuleApi):
|
|
|
2055
2068
|
hashes=[h],
|
|
2056
2069
|
metas=[meta],
|
|
2057
2070
|
skip_download=skip_download,
|
|
2058
|
-
force_metadata_for_links=force_metadata_for_links
|
|
2071
|
+
force_metadata_for_links=force_metadata_for_links,
|
|
2059
2072
|
)
|
|
2060
2073
|
if len(links) != 1:
|
|
2061
2074
|
raise RuntimeError(
|
|
@@ -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.
|
|
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,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import os
|
|
3
2
|
import shutil
|
|
4
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
5
4
|
from enum import Enum
|
|
6
5
|
from logging import Logger
|
|
7
6
|
from pathlib import Path
|
|
@@ -16,6 +15,7 @@ from cachetools import Cache, LRUCache, TTLCache
|
|
|
16
15
|
from fastapi import BackgroundTasks, FastAPI, Form, Request, UploadFile
|
|
17
16
|
|
|
18
17
|
import supervisely as sly
|
|
18
|
+
from supervisely._utils import batched
|
|
19
19
|
from supervisely.io.fs import silent_remove
|
|
20
20
|
|
|
21
21
|
|
|
@@ -151,6 +151,38 @@ class PersistentImageTTLCache(TTLCache):
|
|
|
151
151
|
def get_project_meta(self, project_meta_name):
|
|
152
152
|
return self[project_meta_name]
|
|
153
153
|
|
|
154
|
+
def copy_to(self, name, path):
|
|
155
|
+
shutil.copyfile(str(self[name]), path)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class VideoFrameReader:
|
|
159
|
+
def __init__(self, video_path: str, frame_indexes: List[int]):
|
|
160
|
+
self.video_path = video_path
|
|
161
|
+
self.frame_indexes = frame_indexes
|
|
162
|
+
self.cap = None
|
|
163
|
+
self.prev_idx = -1
|
|
164
|
+
|
|
165
|
+
def __enter__(self):
|
|
166
|
+
self.cap = cv2.VideoCapture(str(self.video_path))
|
|
167
|
+
return self
|
|
168
|
+
|
|
169
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
170
|
+
if self.cap is not None:
|
|
171
|
+
self.cap.release()
|
|
172
|
+
|
|
173
|
+
def read_frames(self) -> Generator:
|
|
174
|
+
try:
|
|
175
|
+
for frame_index in self.frame_indexes:
|
|
176
|
+
if frame_index != self.prev_idx + 1:
|
|
177
|
+
self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_index)
|
|
178
|
+
ret, frame = self.cap.read()
|
|
179
|
+
if not ret:
|
|
180
|
+
raise KeyError(f"Frame {frame_index} not found in video {self.video_path}")
|
|
181
|
+
yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
182
|
+
self.prev_idx = frame_index
|
|
183
|
+
finally:
|
|
184
|
+
self.cap.release()
|
|
185
|
+
|
|
154
186
|
|
|
155
187
|
class InferenceImageCache:
|
|
156
188
|
class _LoadType(Enum):
|
|
@@ -238,25 +270,18 @@ class InferenceImageCache:
|
|
|
238
270
|
return_images,
|
|
239
271
|
)
|
|
240
272
|
|
|
273
|
+
def _read_frames_from_cached_video_iter(self, video_id, frame_indexes):
|
|
274
|
+
video_path = self._cache.get_video_path(video_id)
|
|
275
|
+
with VideoFrameReader(video_path, frame_indexes) as reader:
|
|
276
|
+
for frame in reader.read_frames():
|
|
277
|
+
yield frame
|
|
278
|
+
|
|
241
279
|
def _read_frames_from_cached_video(
|
|
242
280
|
self, video_id: int, frame_indexes: List[int]
|
|
243
281
|
) -> List[np.ndarray]:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
cap = cv2.VideoCapture(str(video_path))
|
|
248
|
-
frames = []
|
|
249
|
-
prev_idx = -1
|
|
250
|
-
for frame_index in frame_indexes:
|
|
251
|
-
if frame_index != prev_idx + 1:
|
|
252
|
-
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_index)
|
|
253
|
-
ret, frame = cap.read()
|
|
254
|
-
if not ret:
|
|
255
|
-
raise KeyError(f"Frame {frame_index} not found in video {video_id}")
|
|
256
|
-
frames.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
|
257
|
-
prev_idx = frame_index
|
|
258
|
-
cap.release()
|
|
259
|
-
return frames
|
|
282
|
+
return [
|
|
283
|
+
frame for frame in self._read_frames_from_cached_video_iter(video_id, frame_indexes)
|
|
284
|
+
]
|
|
260
285
|
|
|
261
286
|
def get_frame_from_cache(self, video_id: int, frame_index: int) -> np.ndarray:
|
|
262
287
|
name = self._frame_name(video_id, frame_index)
|
|
@@ -664,3 +689,39 @@ class InferenceImageCache:
|
|
|
664
689
|
# TODO: sleep if slowdown
|
|
665
690
|
sleep(0.1)
|
|
666
691
|
continue
|
|
692
|
+
|
|
693
|
+
def download_frames_to_paths(self, api, video_id, frame_indexes, paths, progress_cb=None):
|
|
694
|
+
def _download_frame(frame_index):
|
|
695
|
+
self.download_frame(api, video_id, frame_index)
|
|
696
|
+
name = self._frame_name(video_id, frame_index)
|
|
697
|
+
return frame_index, name
|
|
698
|
+
|
|
699
|
+
def _download_and_save(this_frame_indexes, this_paths):
|
|
700
|
+
if video_id in self._cache:
|
|
701
|
+
for path, frame in zip(
|
|
702
|
+
this_paths,
|
|
703
|
+
self._read_frames_from_cached_video_iter(video_id, this_frame_indexes),
|
|
704
|
+
):
|
|
705
|
+
sly.image.write(path, frame)
|
|
706
|
+
if progress_cb is not None:
|
|
707
|
+
progress_cb()
|
|
708
|
+
return
|
|
709
|
+
|
|
710
|
+
futures = []
|
|
711
|
+
frame_index_to_path = {}
|
|
712
|
+
for frame_index, path in zip(this_frame_indexes[:5], this_paths[:5]):
|
|
713
|
+
frame_index_to_path[frame_index] = path
|
|
714
|
+
futures.append(executor.submit(_download_frame, frame_index))
|
|
715
|
+
for future in as_completed(futures):
|
|
716
|
+
frame_index, name = future.result()
|
|
717
|
+
path = frame_index_to_path[frame_index]
|
|
718
|
+
self._cache.copy_to(name, path)
|
|
719
|
+
if progress_cb is not None:
|
|
720
|
+
progress_cb()
|
|
721
|
+
if len(this_frame_indexes) > 5:
|
|
722
|
+
_download_and_save(this_frame_indexes[5:], this_paths[5:])
|
|
723
|
+
|
|
724
|
+
# optimization for frame read from video file
|
|
725
|
+
frame_indexes, paths = zip(*sorted(zip(frame_indexes, paths), key=lambda x: x[0]))
|
|
726
|
+
executor = ThreadPoolExecutor(max_workers=5)
|
|
727
|
+
_download_and_save(frame_indexes, paths)
|
|
@@ -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
|
-
|
|
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:
|
supervisely/project/project.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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)
|
|
@@ -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=
|
|
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
|
|
@@ -64,7 +64,7 @@ supervisely/api/pointcloud/pointcloud_object_api.py,sha256=bO1USWb9HAywG_CW4CDu1
|
|
|
64
64
|
supervisely/api/pointcloud/pointcloud_tag_api.py,sha256=iShtr052nOElxsyMyZEUT2vypEm6kP00gnP13ABX24A,4691
|
|
65
65
|
supervisely/api/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
66
|
supervisely/api/video/video_annotation_api.py,sha256=Um_7UOJtP_E25X6v41mrZfDbJaJuLMGoZm2IULwyg3w,10977
|
|
67
|
-
supervisely/api/video/video_api.py,sha256=
|
|
67
|
+
supervisely/api/video/video_api.py,sha256=KO_Nfqa4xDWrc7FqOR14PciC0TX8PF0g0peqgPnctEE,94677
|
|
68
68
|
supervisely/api/video/video_figure_api.py,sha256=quksohjhgrK2l2-PtbbNE99fOW6uWXX59-_4xfc-I-k,6244
|
|
69
69
|
supervisely/api/video/video_frame_api.py,sha256=4GwSI4xdCNYEUvTqzKc-Ewd44fw5zqkFoD24jrrN_aY,10214
|
|
70
70
|
supervisely/api/video/video_object_api.py,sha256=IC0NP8EoIT_d3xxDRgz2cA3ixSiuJ5ymy64eS-RfmDM,2227
|
|
@@ -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=
|
|
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
|
|
@@ -816,8 +816,8 @@ supervisely/nn/benchmark/visualization/widgets/sidebar/sidebar.py,sha256=tKPURRS
|
|
|
816
816
|
supervisely/nn/benchmark/visualization/widgets/table/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
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
|
-
supervisely/nn/inference/cache.py,sha256=
|
|
820
|
-
supervisely/nn/inference/inference.py,sha256=
|
|
819
|
+
supervisely/nn/inference/cache.py,sha256=KvzCgMbEBLdiJAxJDLicIPKAlYb52P9_kpNPWfiVY8Y,28194
|
|
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=
|
|
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.
|
|
1001
|
-
supervisely-6.73.
|
|
1002
|
-
supervisely-6.73.
|
|
1003
|
-
supervisely-6.73.
|
|
1004
|
-
supervisely-6.73.
|
|
1005
|
-
supervisely-6.73.
|
|
1000
|
+
supervisely-6.73.233.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1001
|
+
supervisely-6.73.233.dist-info/METADATA,sha256=MJtm60rKHXwewU1uAmNhtaWHuI_g_Y4oGxJbqM-oiFM,33150
|
|
1002
|
+
supervisely-6.73.233.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
1003
|
+
supervisely-6.73.233.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1004
|
+
supervisely-6.73.233.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1005
|
+
supervisely-6.73.233.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|