Skip to content

Commit 13c8e75

Browse files
committed
annotations upload updated
1 parent a009561 commit 13c8e75

File tree

8 files changed

+52
-32
lines changed

8 files changed

+52
-32
lines changed

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ minversion = 3.7
33
log_cli=true
44
python_files = test_*.py
55
;pytest_plugins = ['pytest_profiling']
6-
addopts = -n auto --dist=loadscope
6+
;addopts = -n auto --dist=loadscope

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ email-validator>=1.0.3
2020
nest-asyncio==1.5.4
2121
jsonschema==3.2.0
2222
pandas>=1.1.4
23+
aiofiles==0.8.0
24+

src/superannotate/lib/app/analytics/aggregators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ def aggregate_video_annotations_as_df(self, annotation_paths: List[str]):
257257
)
258258
if not timestamps:
259259
raws.append(parameter_raw)
260-
if not parameters and instance_type != 'tag':
260+
if not parameters and instance_type != "tag":
261261
raws.append(instance_raw)
262262
if not instances:
263263
raws.append(raw_data)

src/superannotate/lib/core/usecases/annotations.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from typing import Set
2121
from typing import Tuple
2222

23+
import aiofiles
2324
import boto3
2425
import jsonschema.validators
2526
import lib.core as constants
@@ -188,28 +189,28 @@ def prepare_annotation(self, annotation: dict, size) -> dict:
188189
)
189190
return annotation
190191

191-
def get_annotation(
192+
async def get_annotation(
192193
self, path: str
193194
) -> (Optional[Tuple[io.StringIO]], Optional[io.BytesIO]):
194195
mask = None
195-
196196
if self._client_s3_bucket:
197-
file = self.get_annotation_from_s3(self._client_s3_bucket, path)
198-
197+
content = self.get_annotation_from_s3(self._client_s3_bucket, path).read()
199198
else:
200-
file = open(path)
199+
async with aiofiles.open(path) as file:
200+
content = await file.read()
201201
if self._project.type == constants.ProjectType.PIXEL.value:
202-
mask = open(
202+
async with aiofiles.open(
203203
path.replace(
204204
constants.PIXEL_ANNOTATION_POSTFIX,
205205
constants.ANNOTATION_MASK_POSTFIX,
206206
),
207207
"rb",
208-
)
209-
_tmp = file.read()
210-
if not isinstance(_tmp, bytes):
211-
_tmp = _tmp.encode("utf8")
212-
file = io.BytesIO(_tmp)
208+
) as mask:
209+
mask = await mask.read()
210+
211+
if not isinstance(content, bytes):
212+
content = content.encode("utf8")
213+
file = io.BytesIO(content)
213214
file.seek(0)
214215
size = file.getbuffer().nbytes
215216
annotation = json.load(file)
@@ -393,7 +394,7 @@ async def upload_big_annotations(self):
393394
if item:
394395
await self._upload_big_annotation(item)
395396
else:
396-
await self._big_files_queue.put(None)
397+
await self._big_files_queue.put_nowait(None)
397398
break
398399

399400
async def distribute_queues(self, items_to_upload: list):
@@ -403,28 +404,32 @@ async def distribute_queues(self, items_to_upload: list):
403404
for idx, (item, processed) in enumerate(data):
404405
if not processed:
405406
try:
406-
annotation, mask, size = self.get_annotation(item.path)
407+
annotation, mask, size = await self.get_annotation(item.path)
407408
t_item = copy.copy(item)
408409
annotation_file = io.StringIO()
409410
json.dump(annotation, annotation_file)
410411
annotation_file.seek(0)
411-
del annotation
412412
t_item.data = annotation_file
413413
t_item.mask = mask
414-
if size > BIG_FILE_THRESHOLD:
415-
if self._big_files_queue.qsize() > 4:
416-
continue
417-
else:
414+
while True:
415+
if size > BIG_FILE_THRESHOLD:
416+
if self._big_files_queue.qsize() > 32:
417+
await asyncio.sleep(3)
418+
continue
418419
self._big_files_queue.put_nowait(t_item)
419-
else:
420-
self._small_files_queue.put_nowait(t_item)
420+
break
421+
else:
422+
self._small_files_queue.put_nowait(t_item)
423+
break
421424
except Exception as e:
422425
self.reporter.log_debug(str(e))
423426
self._report.failed_annotations.append(item.name)
424-
finally:
425427
self.reporter.update_progress()
426428
data[idx][1] = True
427429
processed_count += 1
430+
self.reporter.update_progress()
431+
data[idx][1] = True
432+
processed_count += 1
428433
self._big_files_queue.put_nowait(None)
429434
self._small_files_queue.put_nowait(None)
430435

@@ -434,12 +439,12 @@ async def run_workers(self, items_to_upload):
434439
self._small_files_queue = asyncio.Queue()
435440
await asyncio.gather(
436441
self.distribute_queues(items_to_upload),
437-
self.upload_small_annotations(),
438442
self.upload_big_annotations(),
439443
self.upload_big_annotations(),
440444
self.upload_big_annotations(),
441445
return_exceptions=True,
442446
)
447+
await asyncio.gather(self.upload_small_annotations())
443448
except Exception as e:
444449
self.reporter.log_error(f"Error {str(e)}")
445450

src/superannotate/lib/infrastructure/services.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(
8383
def assets_provider_url(self):
8484
if self.api_url != constance.BACKEND_URL:
8585
return "https://assets-provider.devsuperannotate.com/api/v1.01/"
86+
# return "https://e53a-178-160-196-42.ngrok.io/api/v1.01/"
8687
return "https://assets-provider.superannotate.com/api/v1/"
8788

8889
@lru_cache(maxsize=32)
@@ -1418,10 +1419,8 @@ async def upload_big_annotation(
14181419
data: io.StringIO,
14191420
chunk_size: int,
14201421
) -> bool:
1421-
headers = self.default_headers
1422-
headers["Content-Type"] = "application/x-www-form-urlencoded"
14231422
async with aiohttp.ClientSession(
1424-
connector=aiohttp.TCPConnector(ssl=False),
1423+
connector=aiohttp.TCPConnector(ssl=False), headers=self.default_headers
14251424
) as session:
14261425
params = {
14271426
"team_id": team_id,
@@ -1438,12 +1437,12 @@ async def upload_big_annotation(
14381437
"project_id": project_id,
14391438
"folder_id": folder_id,
14401439
},
1441-
headers=headers,
14421440
)
14431441
if not start_response.ok:
14441442
raise AppException(str(await start_response.text()))
14451443
process_info = await start_response.json()
14461444
params["path"] = process_info["path"]
1445+
headers = copy.copy(self.default_headers)
14471446
headers["upload_id"] = process_info["upload_id"]
14481447
chunk_id = 1
14491448
data_sent = False
@@ -1459,7 +1458,7 @@ async def upload_big_annotation(
14591458
),
14601459
params=params,
14611460
headers=headers,
1462-
data={"data_chunk": chunk},
1461+
data=json.dumps({"data_chunk": chunk}),
14631462
)
14641463
if not response.ok:
14651464
raise AppException(str(await response.text()))
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
1-
{"metadata":{"name":"aearth_mov_008.jpg","projectId":1290,"isPredicted":false,"status":"InProgress","pinned":false,"annotatorEmail":null,"qaEmail":null},"instances":[],"tags":[],"comments":[]}
1+
{
2+
"metadata": {
3+
"name": "aearth_mov_008.jpg",
4+
"projectId": 1290,
5+
"isPredicted": false,
6+
"status": "InProgress",
7+
"pinned": false,
8+
"annotatorEmail": null,
9+
"qaEmail": null
10+
},
11+
"instances": [],
12+
"tags": [],
13+
"comments": []
14+
}

tests/integration/annotations/test_upload_annotations_from_folder_to_project.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def test_4_annotation_folder_upload_download(self):
5858
def test_upload_big_annotations(self):
5959
sa.attach_items(
6060
self.PROJECT_NAME,
61-
[{"name": f"aearth_mov_00{i}.jpg", "url": f"url_{i}"} for i in range(1, 2)] # noqa
61+
[{"name": f"aearth_mov_00{i}.jpg", "url": f"url_{i}"} for i in range(1, 6)] # noqa
6262
)
6363
sa.create_annotation_classes_from_classes_json(
6464
self.PROJECT_NAME, f"{self.big_annotations_folder_path}/classes/classes.json"
@@ -68,4 +68,4 @@ def test_upload_big_annotations(self):
6868
)
6969
assert len(uploaded) == 5
7070
annotations = sa.get_annotations(self.PROJECT_NAME)
71-
assert all([len(annotation["instances"]) > 1 for annotation in annotations])
71+
assert [len(annotation["instances"]) > 1 for annotation in annotations].count(True) == 4

tests/integration/annotations/validations/test_vector_annotation_validation.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ def test_should_be_valid(self):
6969
"instances": [
7070
{
7171
"type": "bbox",
72+
"createdAt": '2021-11-18T13.36.53.293Z',
7273
"createdBy": {'email': 'arturn@superannotate.com', 'role': 'dmin'},
7374
"points": {
7475
"x1": 437.16,

0 commit comments

Comments
 (0)