Skip to content

Commit 56a8457

Browse files
authored
Merge pull request #341 from superannotateai/591
591
2 parents a26d17e + b1c0c3c commit 56a8457

File tree

6 files changed

+141
-11
lines changed

6 files changed

+141
-11
lines changed

src/superannotate/lib/app/annotation_helpers.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""SuperAnnotate format annotation JSON helpers"""
2+
import datetime
23
import json
34

45
from superannotate.lib.app.exceptions import AppException
@@ -33,6 +34,18 @@ def _postprocess_annotation_json(annotation_json, path):
3334
return annotation_json
3435

3536

37+
def _add_created_updated(annotation):
38+
created_at = (
39+
datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[
40+
:-3
41+
]
42+
+ "Z"
43+
)
44+
annotation["createdAt"] = created_at
45+
annotation["updatedAt"] = created_at
46+
return annotation
47+
48+
3649
def add_annotation_comment_to_json(
3750
annotation_json,
3851
comment_text,
@@ -63,13 +76,17 @@ def add_annotation_comment_to_json(
6376
annotation_json, image_name=image_name
6477
)
6578

79+
user_action = {"email": comment_author, "role": "Admin"}
80+
6681
annotation = {
67-
"type": "comment",
6882
"x": comment_coords[0],
6983
"y": comment_coords[1],
7084
"correspondence": [{"text": comment_text, "email": comment_author}],
7185
"resolved": resolved,
86+
"createdBy": user_action,
87+
"updatedBy": user_action,
7288
}
89+
annotation = _add_created_updated(annotation)
7390
annotation_json["comments"].append(annotation)
7491

7592
return _postprocess_annotation_json(annotation_json, path)
@@ -118,6 +135,7 @@ def add_annotation_bbox_to_json(
118135
else annotation_class_attributes,
119136
}
120137

138+
annotation = _add_created_updated(annotation)
121139
annotation_json["instances"].append(annotation)
122140

123141
return _postprocess_annotation_json(annotation_json, path)
@@ -127,6 +145,7 @@ def add_annotation_point_to_json(
127145
annotation_json,
128146
point,
129147
annotation_class_name,
148+
image_name,
130149
annotation_class_attributes=None,
131150
error=None,
132151
):
@@ -148,7 +167,7 @@ def add_annotation_point_to_json(
148167
if len(point) != 2:
149168
raise AppException("Point should be 2 element float list.")
150169

151-
annotation_json, path = _preprocess_annotation_json(annotation_json)
170+
annotation_json, path = _preprocess_annotation_json(annotation_json, image_name)
152171

153172
annotation = {
154173
"type": "point",
@@ -165,6 +184,7 @@ def add_annotation_point_to_json(
165184
else annotation_class_attributes,
166185
}
167186

187+
annotation = _add_created_updated(annotation)
168188
annotation_json["instances"].append(annotation)
169189

170190
return _postprocess_annotation_json(annotation_json, path)

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,7 +2461,11 @@ def add_annotation_bbox_to_image(
24612461
:param error: if not None, marks annotation as error (True) or no-error (False)
24622462
:type error: bool
24632463
"""
2464-
annotations = get_image_annotations(project, image_name)["annotation_json"]
2464+
project_name, folder_name = extract_project_folder(project)
2465+
response = controller.get_image_annotations(
2466+
project_name=project_name, folder_name=folder_name, image_name=image_name
2467+
)
2468+
annotations = response.data["annotation_json"]
24652469
annotations = add_annotation_bbox_to_json(
24662470
annotations,
24672471
bbox,
@@ -2503,9 +2507,18 @@ def add_annotation_point_to_image(
25032507
:param error: if not None, marks annotation as error (True) or no-error (False)
25042508
:type error: bool
25052509
"""
2506-
annotations = get_image_annotations(project, image_name)["annotation_json"]
2510+
project_name, folder_name = extract_project_folder(project)
2511+
response = controller.get_image_annotations(
2512+
project_name=project_name, folder_name=folder_name, image_name=image_name
2513+
)
2514+
annotations = response.data["annotation_json"]
25072515
annotations = add_annotation_point_to_json(
2508-
annotations, point, annotation_class_name, annotation_class_attributes, error
2516+
annotations,
2517+
point,
2518+
annotation_class_name,
2519+
image_name,
2520+
annotation_class_attributes,
2521+
error,
25092522
)
25102523
controller.upload_image_annotations(
25112524
*extract_project_folder(project), image_name, annotations
@@ -2537,7 +2550,11 @@ def add_annotation_comment_to_image(
25372550
:param resolved: comment resolve status
25382551
:type resolved: bool
25392552
"""
2540-
annotations = get_image_annotations(project, image_name)["annotation_json"]
2553+
project_name, folder_name = extract_project_folder(project)
2554+
response = controller.get_image_annotations(
2555+
project_name=project_name, folder_name=folder_name, image_name=image_name
2556+
)
2557+
annotations = response.data["annotation_json"]
25412558
annotations = add_annotation_comment_to_json(
25422559
annotations,
25432560
comment_text,

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@
3535
from lib.core.exceptions import ImageProcessingException
3636
from lib.core.plugin import ImagePlugin
3737
from lib.core.plugin import VideoPlugin
38+
from lib.core.reporter import Reporter
3839
from lib.core.repositories import BaseManageableRepository
3940
from lib.core.repositories import BaseReadOnlyRepository
4041
from lib.core.response import Response
4142
from lib.core.serviceproviders import SuerannotateServiceProvider
4243
from lib.core.usecases.base import BaseInteractiveUseCase
44+
from lib.core.usecases.base import BaseReportableUseCae
4345
from lib.core.usecases.base import BaseUseCase
4446
from lib.core.usecases.projects import GetAnnotationClassesUseCase
4547
from lib.core.validators import BaseAnnotationValidator
@@ -2463,16 +2465,17 @@ def execute(self):
24632465
return self._response
24642466

24652467

2466-
class GetImageAnnotationsUseCase(BaseUseCase):
2468+
class GetImageAnnotationsUseCase(BaseReportableUseCae):
24672469
def __init__(
24682470
self,
2471+
reporter: Reporter,
24692472
service: SuerannotateServiceProvider,
24702473
project: ProjectEntity,
24712474
folder: FolderEntity,
24722475
image_name: str,
24732476
images: BaseManageableRepository,
24742477
):
2475-
super().__init__()
2478+
super().__init__(reporter)
24762479
self._service = service
24772480
self._project = project
24782481
self._folder = folder
@@ -2524,7 +2527,7 @@ def execute(self):
25242527
headers=credentials["annotation_json_path"]["headers"],
25252528
)
25262529
if not response.ok:
2527-
logger.warning("Couldn't load annotations.")
2530+
self.reporter.log_warning("Couldn't load annotations.")
25282531
self._response.data = data
25292532
return self._response
25302533
data["annotation_json"] = response.json()

src/superannotate/lib/infrastructure/controller.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,7 @@ def get_image_annotations(
991991
folder=folder,
992992
image_name=image_name,
993993
images=ImageRepository(service=self._backend_client),
994+
reporter=Reporter(log_info=False, log_warning=False),
994995
)
995996
return use_case.execute()
996997

tests/integration/annotations/test_annotation_adding.py

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,97 @@ def test_upload_annotations(self):
4747
self.PROJECT_NAME, self.folder_path
4848
)
4949

50+
51+
def test_add_point_to_empty_image(self):
52+
sa.upload_images_from_folder_to_project(
53+
self.PROJECT_NAME, self.folder_path, annotation_status="InProgress"
54+
)
55+
56+
sa.add_annotation_point_to_image(
57+
self.PROJECT_NAME, self.EXAMPLE_IMAGE_1, [250, 250], "test_add"
58+
)
59+
annotations_new = sa.get_image_annotations(
60+
self.PROJECT_NAME, self.EXAMPLE_IMAGE_1
61+
)["annotation_json"]
62+
63+
annotations_new["instances"][0]['createdAt'] = ''
64+
annotations_new["instances"][0]['updatedAt'] = ''
65+
66+
self.assertEqual(
67+
annotations_new["instances"][0], {
68+
'x': 250.0,
69+
'y': 250.0,
70+
'creationType': 'Preannotation',
71+
'className': 'test_add',
72+
'visible': True,
73+
'locked': False,
74+
'probability': 100,
75+
'attributes': [],
76+
'type': 'point',
77+
'pointLabels': {},
78+
'groupId': 0,
79+
'classId': -1,
80+
'createdAt': '',
81+
'updatedAt': ''
82+
})
83+
84+
def test_add_bbox_to_empty_annotation(self):
85+
sa.upload_images_from_folder_to_project(
86+
self.PROJECT_NAME, self.folder_path, annotation_status="InProgress"
87+
)
88+
89+
sa.add_annotation_bbox_to_image(
90+
self.PROJECT_NAME, self.EXAMPLE_IMAGE_1, [10, 10, 500, 100], "test_add"
91+
)
92+
93+
annotations_new = sa.get_image_annotations(
94+
self.PROJECT_NAME, self.EXAMPLE_IMAGE_1
95+
)["annotation_json"]
96+
97+
annotations_new["instances"][0]['createdAt'] = ''
98+
annotations_new["instances"][0]['updatedAt'] = ''
99+
100+
self.assertEqual(annotations_new['instances'][0], {
101+
'creationType': 'Preannotation',
102+
'className': 'test_add', 'visible': True,
103+
'locked': False, 'probability': 100,
104+
'attributes': [],
105+
'type': 'bbox',
106+
'pointLabels': {},
107+
'groupId': 0,
108+
'points': {'x1': 10.0, 'x2': 500.0, 'y1': 10.0, 'y2': 100.0},
109+
'classId': -1,
110+
'createdAt': '',
111+
'updatedAt': ''
112+
})
113+
114+
115+
def test_add_comment_to_empty_annotation(self):
116+
sa.upload_images_from_folder_to_project(
117+
self.PROJECT_NAME, self.folder_path, annotation_status="InProgress"
118+
)
119+
120+
sa.add_annotation_comment_to_image(self.PROJECT_NAME, self.EXAMPLE_IMAGE_1, "some comment", [1, 2], "abc@abc.com")
121+
122+
annotations_new = sa.get_image_annotations(
123+
self.PROJECT_NAME, self.EXAMPLE_IMAGE_1
124+
)["annotation_json"]
125+
126+
annotations_new['comments'][0]['createdAt'] = ""
127+
annotations_new['comments'][0]['updatedAt'] = ""
128+
129+
self.assertEqual(annotations_new['comments'][0],
130+
{'createdBy': {'email': 'abc@abc.com', 'role': 'Admin'},
131+
'updatedBy': {'email': 'abc@abc.com', 'role': 'Admin'},
132+
'creationType': 'Preannotation',
133+
'createdAt': '',
134+
'updatedAt': '',
135+
'x': 1.0, 'y': 2.0,
136+
'resolved': False,
137+
'correspondence': [{'text': 'some comment', 'email': 'abc@abc.com'}]
138+
})
139+
140+
50141
def test_add_bbox(self):
51142
sa.upload_images_from_folder_to_project(
52143
self.PROJECT_NAME, self.folder_path, annotation_status="InProgress"
@@ -92,8 +183,6 @@ def test_add_bbox(self):
92183
len(annotations["instances"]) + len(annotations["comments"]) + 3,
93184
)
94185

95-
export = sa.prepare_export(self.PROJECT_NAME, include_fuse=True)
96-
sa.download_export(self.PROJECT_NAME, export["name"], tmpdir_name)
97186

98187
def test_add_bbox_no_init(self):
99188
sa.upload_images_from_folder_to_project(

tests/unit/test_s3_no_contents.py

Whitespace-only changes.

0 commit comments

Comments
 (0)