Skip to content

Commit 1129b7c

Browse files
Vaghinak BasentsyanVaghinak Basentsyan
authored andcommitted
tod
1 parent c235e0b commit 1129b7c

File tree

4 files changed

+64
-20
lines changed

4 files changed

+64
-20
lines changed

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from lib.app.helpers import reformat_metrics_json
3131
from lib.app.interface.types import AnnotationStatuses
3232
from lib.app.interface.types import AnnotationType
33+
from lib.app.interface.types import ImageQualityChoices
3334
from lib.app.interface.types import NotEmptyStr
3435
from lib.app.interface.types import Status
3536
from lib.app.interface.types import validate_arguments
@@ -2087,7 +2088,9 @@ def move_image(
20872088
image_path = destination_folder + image_name
20882089

20892090
image_entity = controller.upload_image_to_s3(
2090-
project_name=destination_project_name, image_path=image_path, image_bytes=img_bytes
2091+
project_name=destination_project_name,
2092+
image_path=image_path,
2093+
image_bytes=img_bytes,
20912094
).data
20922095

20932096
del img_bytes
@@ -3466,7 +3469,7 @@ def upload_images_to_project(
34663469
img_paths: List[NotEmptyStr],
34673470
annotation_status: Optional[Status] = "NotStarted",
34683471
from_s3_bucket=None,
3469-
image_quality_in_editor: Optional[NotEmptyStr] = None,
3472+
image_quality_in_editor: Optional[ImageQualityChoices] = None,
34703473
):
34713474
"""Uploads all images given in list of path objects in img_paths to the project.
34723475
Sets status of all the uploaded images to set_status if it is not None.

src/superannotate/lib/app/interface/types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ def validate(cls, value: Union[str]) -> Union[str]:
3434
return value
3535

3636

37+
class ImageQualityChoices(StrictStr):
38+
VALID_CHOICES = ["compressed", "original"]
39+
40+
@classmethod
41+
def validate(cls, value: Union[str]) -> Union[str]:
42+
super().validate(value)
43+
if value.lower() not in cls.VALID_CHOICES:
44+
raise TypeError(
45+
f"Image quality should be on of {', '.join(cls.VALID_CHOICES)}."
46+
)
47+
return value.lower()
48+
49+
3750
class AnnotationStatuses(StrictStr):
3851
@classmethod
3952
def validate(cls, value: Union[str]) -> Union[str]:

src/superannotate/lib/core/usecases.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import pandas as pd
2424
import requests
2525
from boto3.exceptions import Boto3Error
26+
from botocore.exceptions import ClientError
2627
from lib.app.analytics.common import aggregate_annotations_as_df
2728
from lib.app.analytics.common import consensus_plot
2829
from lib.app.analytics.common import image_consensus
@@ -2156,14 +2157,19 @@ def __init__(
21562157
self._image_path = image_path
21572158

21582159
def execute(self):
2159-
image = io.BytesIO()
2160-
session = boto3.Session()
2161-
resource = session.resource("s3")
2162-
image_object = resource.Object(self._s3_bucket, self._image_path)
2163-
if image_object.content_length > constances.MAX_IMAGE_SIZE:
2164-
raise AppValidationException(f"File size is {image_object.content_length}")
2165-
image_object.download_fileobj(image)
2166-
self._response.data = image
2160+
try:
2161+
image = io.BytesIO()
2162+
session = boto3.Session()
2163+
resource = session.resource("s3")
2164+
image_object = resource.Object(self._s3_bucket, self._image_path)
2165+
if image_object.content_length > constances.MAX_IMAGE_SIZE:
2166+
raise AppValidationException(
2167+
f"File size is {image_object.content_length}"
2168+
)
2169+
image_object.download_fileobj(image)
2170+
self._response.data = image
2171+
except ClientError as e:
2172+
self._response.errors = str(e)
21672173
return self._response
21682174

21692175

@@ -4845,11 +4851,20 @@ def _upload_image(self, image_path: str):
48454851
"ProcessedImage", ["uploaded", "path", "entity", "name"]
48464852
)
48474853
if self._from_s3_bucket:
4848-
image_bytes = (
4849-
GetS3ImageUseCase(s3_bucket=self._from_s3_bucket, image_path=image_path)
4850-
.execute()
4851-
.data
4852-
)
4854+
response = GetS3ImageUseCase(
4855+
s3_bucket=self._from_s3_bucket, image_path=image_path
4856+
).execute()
4857+
if response.errors:
4858+
logger.warning(
4859+
f"Unable to upload image {image_path} \n{response.errors}"
4860+
)
4861+
return ProcessedImage(
4862+
uploaded=False,
4863+
path=image_path,
4864+
entity=None,
4865+
name=Path(image_path).name,
4866+
)
4867+
image_bytes = response.data
48534868
else:
48544869
try:
48554870
image_bytes = io.BytesIO(open(image_path, "rb").read())
@@ -4926,7 +4941,6 @@ def images_to_upload(self):
49264941
images_to_upload.append(path)
49274942
else:
49284943
duplicated_paths.append(path)
4929-
49304944
self._images_to_upload = list(set(images_to_upload)), duplicated_paths
49314945
return self._images_to_upload
49324946

@@ -4971,7 +4985,8 @@ def execute(self):
49714985
duplications.extend(attach_duplications)
49724986
uploaded = [image["name"] for image in uploaded]
49734987
failed_images = [image.split("/")[-1] for image in failed_images]
4974-
4988+
if duplications:
4989+
logger.info(f"Duplicated images {', '.join(duplications)}")
49754990
self._response.data = uploaded, failed_images, duplications
49764991
return self._response
49774992

tests/integration/test_interface.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
from os.path import dirname
33
import tempfile
4-
import unittest
4+
import boto3
55

66
import src.superannotate as sa
77
from src.superannotate.lib.app.exceptions import AppException
@@ -10,17 +10,21 @@
1010

1111
class TestInterface(BaseTestCase):
1212
PROJECT_NAME = "Interface test"
13-
TEST_FOLDER_PATH = "data_set/sample_project_vector"
13+
TEST_FOLDER_PATH = "sample_project_vector"
1414
TEST_FOLDER_PATH_WITH_MULTIPLE_IMAGERS = "data_set/sample_project_vector"
1515
PROJECT_DESCRIPTION = "desc"
1616
PROJECT_TYPE = "Vector"
1717
TEST_FOLDER_NAME = "folder"
1818
EXAMPLE_IMAGE_1 = "example_image_1.jpg"
1919
EXAMPLE_IMAGE_2 = "example_image_2.jpg"
2020

21+
@property
22+
def data_set_path(self):
23+
return os.path.join(dirname(dirname(__file__)), "data_set")
24+
2125
@property
2226
def folder_path(self):
23-
return os.path.join(dirname(dirname(__file__)), self.TEST_FOLDER_PATH)
27+
return os.path.join(self.data_set_path, self.TEST_FOLDER_PATH)
2428

2529
@property
2630
def folder_path_with_multiple_images(self):
@@ -133,3 +137,12 @@ def test_overlay_fuse(self):
133137
include_overlay=True,
134138
)
135139
self.assertIsNotNone(paths)
140+
141+
def test_upload_images_to_project_image_quality_in_editor(self):
142+
self.assertRaises(
143+
AppException,
144+
sa.upload_images_to_project,
145+
self.PROJECT_NAME,
146+
[self.EXAMPLE_IMAGE_1],
147+
image_quality_in_editor='random_string'
148+
)

0 commit comments

Comments
 (0)