Skip to content

Commit 9ef9f48

Browse files
committed
assign images by chunk
1 parent 17cccf6 commit 9ef9f48

File tree

2 files changed

+94
-86
lines changed

2 files changed

+94
-86
lines changed

superannotate/db/project_images.py

Lines changed: 44 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,21 @@
2121
)
2222
from .teams import get_team_metadata
2323
from ..mixp.decorators import Trackable
24-
from .utils import _get_upload_auth_token, _get_boto_session_by_credentials, upload_image_array_to_s3, get_image_array_to_upload, __create_image, __copy_images, __move_images, get_project_folder_string
24+
from .utils import _assign_images, _get_upload_auth_token, _get_boto_session_by_credentials, upload_image_array_to_s3, \
25+
get_image_array_to_upload, __create_image, __copy_images, __move_images, get_project_folder_string
2526

2627
logger = logging.getLogger("superannotate-python-sdk")
2728
_api = API.get_instance()
2829

2930

3031
@Trackable
3132
def upload_image_to_project(
32-
project,
33-
img,
34-
image_name=None,
35-
annotation_status="NotStarted",
36-
from_s3_bucket=None,
37-
image_quality_in_editor=None
33+
project,
34+
img,
35+
image_name=None,
36+
annotation_status="NotStarted",
37+
from_s3_bucket=None,
38+
image_quality_in_editor=None
3839
):
3940
"""Uploads image (io.BytesIO() or filepath to image) to project.
4041
Sets status of the uploaded image to set_status if it is not None.
@@ -136,8 +137,8 @@ def upload_image_to_project(
136137

137138

138139
def _copy_images(
139-
source_project, destination_project, image_names, include_annotations,
140-
copy_annotation_status, copy_pin
140+
source_project, destination_project, image_names, include_annotations,
141+
copy_annotation_status, copy_pin
141142
):
142143
NUM_TO_SEND = 500
143144
source_project, source_project_folder = source_project
@@ -166,7 +167,7 @@ def _copy_images(
166167
res['completed'] = []
167168
for start_index in range(0, len(image_names), NUM_TO_SEND):
168169
json_req["image_names"] = image_names[start_index:start_index +
169-
NUM_TO_SEND]
170+
NUM_TO_SEND]
170171
response = _api.send_request(
171172
req_type='POST',
172173
path='/image/copy',
@@ -192,12 +193,12 @@ def _copy_images(
192193

193194
@Trackable
194195
def copy_images(
195-
source_project,
196-
image_names,
197-
destination_project,
198-
include_annotations=True,
199-
copy_annotation_status=True,
200-
copy_pin=True
196+
source_project,
197+
image_names,
198+
destination_project,
199+
include_annotations=True,
200+
copy_annotation_status=True,
201+
copy_pin=True
201202
):
202203
"""Copy images in bulk between folders in a project
203204
@@ -307,12 +308,12 @@ def delete_images(project, image_names):
307308

308309
@Trackable
309310
def move_images(
310-
source_project,
311-
image_names,
312-
destination_project,
313-
include_annotations=True,
314-
copy_annotation_status=True,
315-
copy_pin=True,
311+
source_project,
312+
image_names,
313+
destination_project,
314+
include_annotations=True,
315+
copy_annotation_status=True,
316+
copy_pin=True,
316317
):
317318
"""Move images in bulk between folders in a project
318319
@@ -372,12 +373,12 @@ def move_images(
372373

373374
@Trackable
374375
def copy_image(
375-
source_project,
376-
image_name,
377-
destination_project,
378-
include_annotations=False,
379-
copy_annotation_status=False,
380-
copy_pin=False
376+
source_project,
377+
image_name,
378+
destination_project,
379+
include_annotations=False,
380+
copy_annotation_status=False,
381+
copy_pin=False
381382
):
382383
"""Copy image to a project. The image's project is the same as destination
383384
project then the name will be changed to <image_name>_(<num>).<image_ext>,
@@ -417,10 +418,10 @@ def copy_image(
417418
else:
418419
for m in p.finditer(new_name):
419420
if m.start() + len(m.group()
420-
) + len(extension) - 1 == len(new_name):
421+
) + len(extension) - 1 == len(new_name):
421422
num = int(m.group()[2:-2])
422423
new_name = new_name[:m.start() +
423-
2] + str(num + 1) + ")" + extension
424+
2] + str(num + 1) + ")" + extension
424425
break
425426
else:
426427
new_name = Path(new_name).stem + "_(1)" + extension
@@ -440,9 +441,9 @@ def copy_image(
440441

441442

442443
def _copy_annotations_and_metadata(
443-
source_project, source_project_folder, image_name, destination_project,
444-
destination_project_folder, new_name, include_annotations,
445-
copy_annotation_status, copy_pin
444+
source_project, source_project_folder, image_name, destination_project,
445+
destination_project_folder, new_name, include_annotations,
446+
copy_annotation_status, copy_pin
446447
):
447448
if include_annotations:
448449
annotations = get_image_annotations(
@@ -479,12 +480,12 @@ def _copy_annotations_and_metadata(
479480

480481
@Trackable
481482
def move_image(
482-
source_project,
483-
image_name,
484-
destination_project,
485-
include_annotations=True,
486-
copy_annotation_status=True,
487-
copy_pin=True
483+
source_project,
484+
image_name,
485+
destination_project,
486+
include_annotations=True,
487+
copy_annotation_status=True,
488+
copy_pin=True
488489
):
489490
"""Move image from source_project to destination_project. source_project
490491
and destination_project cannot be the same.
@@ -582,23 +583,10 @@ def assign_images(project, image_names, user):
582583
if folder:
583584
folder_name = folder['name']
584585

585-
params = {"project_id": project['id'], "team_id": project["team_id"]}
586-
json_req = {
587-
"image_names": image_names,
588-
"assign_user_id": user,
589-
"folder_name": folder_name,
590-
}
591-
response = _api.send_request(
592-
req_type='PUT',
593-
path='/images/editAssignment',
594-
params=params,
595-
json_req=json_req
596-
)
597-
598-
if not response.ok:
599-
raise SABaseException(
600-
response.status_code, "Couldn't assign images " + response.text
601-
)
586+
logs = _assign_images(folder_name=folder_name, image_names=image_names, user=user, project_id=project['id'],
587+
team_id=project['team_id'])
588+
for log in logs:
589+
logger.warn(log)
602590

603591

604592
def assign_folder(project, folder_name, users):

superannotate/db/utils.py

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
# Yield successive n-sized
2323
# chunks from l.
2424
def divide_chunks(l, n):
25-
2625
# looping till length l
2726
for i in range(0, len(l), n):
2827
yield l[i:i + n]
@@ -42,7 +41,7 @@ def get_project_folder_string(project):
4241

4342

4443
def __move_images(
45-
source_project, source_folder_id, destination_folder_id, image_names
44+
source_project, source_folder_id, destination_folder_id, image_names
4645
):
4746
"""Move images in bulk between folders in a project
4847
@@ -90,8 +89,8 @@ def __move_images(
9089

9190

9291
def _copy_images_request(
93-
team_id, project_id, image_names, destination_folder_id, source_folder_id,
94-
include_annotations, copy_pin
92+
team_id, project_id, image_names, destination_folder_id, source_folder_id,
93+
include_annotations, copy_pin
9594
):
9695
response = _api.send_request(
9796
req_type='POST',
@@ -161,8 +160,8 @@ def copy_polling(image_names, source_project, poll_id):
161160

162161

163162
def __copy_images(
164-
source_project, source_folder_id, destination_folder_id, image_names,
165-
include_annotations, copy_pin
163+
source_project, source_folder_id, destination_folder_id, image_names,
164+
include_annotations, copy_pin
166165
):
167166
"""Copy images in bulk between folders in a project
168167
@@ -233,8 +232,8 @@ def create_empty_annotation(size, image_name):
233232

234233

235234
def upload_image_array_to_s3(
236-
bucket, img_name, img_name_hash, size, orig_image, lores_image, huge_image,
237-
thumbnail_image, prefix
235+
bucket, img_name, img_name_hash, size, orig_image, lores_image, huge_image,
236+
thumbnail_image, prefix
238237
):
239238
key = prefix + img_name_hash
240239
bucket.put_object(Body=orig_image, Key=key)
@@ -256,7 +255,7 @@ def upload_image_array_to_s3(
256255

257256

258257
def get_image_array_to_upload(
259-
img_name, byte_io_orig, image_quality_in_editor, project_type
258+
img_name, byte_io_orig, image_quality_in_editor, project_type
260259
):
261260
if image_quality_in_editor not in ["original", "compressed"]:
262261
raise SABaseException(0, "NA ImageQuality in get_image_array_to_upload")
@@ -272,8 +271,8 @@ def get_image_array_to_upload(
272271
if resolution > common.MAX_IMAGE_RESOLUTION[project_type]:
273272
raise SABaseException(
274273
0, "Image resolution " + str(resolution) +
275-
" too large. Max supported for " + project_type + " projects is " +
276-
str(common.MAX_IMAGE_RESOLUTION[project_type])
274+
" too large. Max supported for " + project_type + " projects is " +
275+
str(common.MAX_IMAGE_RESOLUTION[project_type])
277276
)
278277

279278
if image_quality_in_editor == "original" and im_format in ['JPEG', 'JPG']:
@@ -317,9 +316,9 @@ def get_image_array_to_upload(
317316

318317

319318
def __upload_images_to_aws_thread(
320-
res, img_paths, project, annotation_status, prefix, thread_id, chunksize,
321-
couldnt_upload, uploaded, tried_upload, image_quality_in_editor,
322-
from_s3_bucket, project_folder_id
319+
res, img_paths, project, annotation_status, prefix, thread_id, chunksize,
320+
couldnt_upload, uploaded, tried_upload, image_quality_in_editor,
321+
from_s3_bucket, project_folder_id
323322
):
324323
len_img_paths = len(img_paths)
325324
start_index = thread_id * chunksize
@@ -405,14 +404,14 @@ def __upload_images_to_aws_thread(
405404

406405

407406
def __create_image(
408-
img_names,
409-
img_paths,
410-
project,
411-
annotation_status,
412-
remote_dir,
413-
sizes,
414-
project_folder_id,
415-
upload_state="Initial"
407+
img_names,
408+
img_paths,
409+
project,
410+
annotation_status,
411+
remote_dir,
412+
sizes,
413+
project_folder_id,
414+
upload_state="Initial"
416415
):
417416
if len(img_paths) == 0:
418417
return
@@ -531,10 +530,9 @@ def get_duplicate_image_names(project_id, team_id, folder_id, image_paths):
531530

532531

533532
def _upload_images(
534-
img_paths, team_id, folder_id, project_id, annotation_status,
535-
from_s3_bucket, image_quality_in_editor, project, folder_name
533+
img_paths, team_id, folder_id, project_id, annotation_status,
534+
from_s3_bucket, image_quality_in_editor, project, folder_name
536535
):
537-
538536
_NUM_THREADS = 10
539537
uploaded = [[] for _ in range(_NUM_THREADS)]
540538
tried_upload = [[] for _ in range(_NUM_THREADS)]
@@ -601,8 +599,8 @@ def _upload_images(
601599

602600

603601
def _attach_urls(
604-
img_names_urls, team_id, folder_id, project_id, annotation_status, project,
605-
folder_name
602+
img_names_urls, team_id, folder_id, project_id, annotation_status, project,
603+
folder_name
606604
):
607605
_NUM_THREADS = 10
608606
params = {'team_id': team_id, 'folder_id': folder_id}
@@ -677,8 +675,8 @@ def _attach_urls(
677675

678676

679677
def __attach_image_urls_to_project_thread(
680-
res, img_names_urls, project, annotation_status, prefix, thread_id,
681-
chunksize, couldnt_upload, uploaded, tried_upload, project_folder_id
678+
res, img_names_urls, project, annotation_status, prefix, thread_id,
679+
chunksize, couldnt_upload, uploaded, tried_upload, project_folder_id
682680
):
683681
len_img_paths = len(img_names_urls)
684682
start_index = thread_id * chunksize
@@ -762,4 +760,26 @@ def get_templates_mapping():
762760
templates_map = {}
763761
for template in templates:
764762
templates_map[template['name']] = template['id']
765-
return templates_map
763+
return templates_map
764+
765+
766+
def _assign_images(folder_name, image_names, user, project_id, team_id):
767+
image_names_lists = divide_chunks(image_names, 500)
768+
params = {"project_id": project_id, "team_id": team_id}
769+
messages = []
770+
for image_name_list in image_names_lists:
771+
json_req = {
772+
"image_names": image_name_list,
773+
"assign_user_id": user,
774+
"folder_name": folder_name,
775+
}
776+
response = _api.send_request(
777+
req_type='PUT',
778+
path='/images/editAssignment',
779+
params=params,
780+
json_req=json_req
781+
)
782+
if not response.ok:
783+
message = "Couldn't assign images " + response.text
784+
messages.append(message)
785+
return messages

0 commit comments

Comments
 (0)