Skip to content

Commit fce0c5d

Browse files
authored
Merge branch 'friday' into sdk_540
2 parents d1942e4 + 3867de7 commit fce0c5d

File tree

13 files changed

+152
-60
lines changed

13 files changed

+152
-60
lines changed

src/superannotate/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@
234234
},
235235
"fileFormatter": {
236236
"format": "SA-PYTHON-SDK - %(levelname)s - %(asctime)s - %(message)s"
237-
}
237+
},
238238
},
239239
"root": { # root logger
240240
"level": "DEBUG",
@@ -258,7 +258,9 @@ def log_version_info():
258258
pip_version = max(pip_version, ver)
259259
if pip_version.major > local_version.major:
260260
logging.warning(
261-
constances.PACKAGE_VERSION_MAJOR_UPGRADE.format(local_version, pip_version)
261+
constances.PACKAGE_VERSION_MAJOR_UPGRADE.format(
262+
local_version, pip_version
263+
)
262264
)
263265
elif pip_version > local_version:
264266
logging.warning(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import copy
22
import json
33
import logging
4+
from dataclasses import dataclass
45
from pathlib import Path
56
from typing import List
67
from typing import Optional
78
from typing import Union
89

910
import lib.core as constances
1011
import pandas as pd
11-
from dataclasses import dataclass
1212
from lib.app.exceptions import AppException
1313
from lib.core import ATTACHED_VIDEO_ANNOTATION_POSTFIX
1414
from lib.core import PIXEL_ANNOTATION_POSTFIX

src/superannotate/lib/app/annotation_helpers.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ def _postprocess_annotation_json(annotation_json, path):
3434

3535

3636
def add_annotation_comment_to_json(
37-
annotation_json, comment_text, comment_coords, comment_author, resolved=False, image_name=""
37+
annotation_json,
38+
comment_text,
39+
comment_coords,
40+
comment_author,
41+
resolved=False,
42+
image_name="",
3843
):
3944
"""Add a comment to SuperAnnotate format annotation JSON
4045
@@ -54,7 +59,9 @@ def add_annotation_comment_to_json(
5459
if len(comment_coords) != 2:
5560
raise AppException("Comment should have two values")
5661

57-
annotation_json, path = _preprocess_annotation_json(annotation_json, image_name=image_name)
62+
annotation_json, path = _preprocess_annotation_json(
63+
annotation_json, image_name=image_name
64+
)
5865

5966
annotation = {
6067
"type": "comment",

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2475,7 +2475,9 @@ def add_annotation_bbox_to_image(
24752475
image_name,
24762476
)
24772477

2478-
controller.upload_image_annotations(*extract_project_folder(project), image_name, annotations)
2478+
controller.upload_image_annotations(
2479+
*extract_project_folder(project), image_name, annotations
2480+
)
24792481

24802482

24812483
@Trackable
@@ -2509,7 +2511,9 @@ def add_annotation_point_to_image(
25092511
annotations = add_annotation_point_to_json(
25102512
annotations, point, annotation_class_name, annotation_class_attributes, error
25112513
)
2512-
controller.upload_image_annotations(*extract_project_folder(project), image_name, annotations)
2514+
controller.upload_image_annotations(
2515+
*extract_project_folder(project), image_name, annotations
2516+
)
25132517

25142518

25152519
@Trackable
@@ -2539,9 +2543,16 @@ def add_annotation_comment_to_image(
25392543
"""
25402544
annotations = get_image_annotations(project, image_name)["annotation_json"]
25412545
annotations = add_annotation_comment_to_json(
2542-
annotations, comment_text, comment_coords, comment_author, resolved=resolved, image_name=image_name
2546+
annotations,
2547+
comment_text,
2548+
comment_coords,
2549+
comment_author,
2550+
resolved=resolved,
2551+
image_name=image_name,
2552+
)
2553+
controller.upload_image_annotations(
2554+
*extract_project_folder(project), image_name, annotations
25432555
)
2544-
controller.upload_image_annotations(*extract_project_folder(project), image_name, annotations)
25452556

25462557

25472558
@Trackable

src/superannotate/lib/app/mixp/utils/parsers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,12 @@ def clone_project(*args, **kwargs):
9797
project_metadata = result.data["project"]
9898
project_type = ProjectType.get_name(project_metadata.project_type)
9999

100-
101100
return {
102101
"event_name": "clone_project",
103102
"properties": {
104-
"External": bool(project_metadata.upload_state == constances.UploadState.EXTERNAL.value),
103+
"External": bool(
104+
project_metadata.upload_state == constances.UploadState.EXTERNAL.value
105+
),
105106
"Project Type": project_type,
106107
"Copy Classes": bool(
107108
args[3:4] or kwargs.get("copy_annotation_classes", None)

src/superannotate/lib/core/entities/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class StringA(BaseModel):
199199

200200

201201
class PointLabels(BaseModel):
202-
__root__: Dict[constr(regex=r"^[0-9]+$"), StrictStr] # noqa F722
202+
__root__: Dict[constr(regex=r"^[0-9]+$"), StrictStr] # noqa F722
203203

204204
@classmethod
205205
def __get_validators__(cls):

src/superannotate/lib/core/entities/video.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class BaseVideoInstance(BaseInstance):
4747

4848

4949
class BboxInstance(BaseVideoInstance):
50-
point_labels: Optional[Dict[constr(regex=r"^[0-9]+$"), NotEmptyStr]] = Field( # noqa F722
50+
point_labels: Optional[
51+
Dict[constr(regex=r"^[0-9]+$"), NotEmptyStr]
52+
] = Field( # noqa F722
5153
None, alias="pointLabels"
5254
)
5355
timeline: Dict[float, BboxTimeStamp]

src/superannotate/lib/core/reporter.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ def __init__(
1111
log_info: bool = True,
1212
log_warning: bool = True,
1313
disable_progress_bar: bool = False,
14+
log_debug: bool = True,
1415
):
1516
self.logger = logging.getLogger("root")
1617
self._log_info = log_info
1718
self._log_warning = log_warning
19+
self._log_debug = log_debug
1820
self._disable_progress_bar = disable_progress_bar
1921
self.info_messages = []
2022
self.warning_messages = []
23+
self.debug_messages = []
2124
self.custom_messages = defaultdict(set)
2225
self.progress_bar = None
2326

@@ -31,6 +34,11 @@ def log_warning(self, value: str):
3134
self.logger.warning(value)
3235
self.warning_messages.append(value)
3336

37+
def log_debug(self, value: str):
38+
if self._log_debug:
39+
self.logger.debug(value)
40+
self.debug_messages.append(value)
41+
3442
def start_progress(
3543
self, iterations: Union[int, range], description: str = "Processing"
3644
):

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ def _upload_annotation(
166166
project=self._project,
167167
folder=self._folder,
168168
team=self._team,
169-
image=ImageEntity(uuid=image_id, name=image_name, team_id=self._project.team_id, project_id=self._project.uuid),
169+
image=ImageEntity(
170+
uuid=image_id,
171+
name=image_name,
172+
team_id=self._project.team_id,
173+
project_id=self._project.uuid,
174+
),
170175
images=self._images,
171176
annotation_classes=self._annotation_classes,
172177
backend_service_provider=self._backend_service,
@@ -209,8 +214,10 @@ def _log_report(self):
209214
if key == "missing_classes":
210215
template = "Could not find annotation classes matching existing classes on the platform: [{}]"
211216
elif key == "missing_attribute_groups":
212-
template = "Could not find attribute groups matching existing attribute groups" \
213-
" on the platform: [{}]"
217+
template = (
218+
"Could not find attribute groups matching existing attribute groups"
219+
" on the platform: [{}]"
220+
)
214221
elif key == "missing_attributes":
215222
template = "Could not find attributes matching existing attributes on the platform: [{}]"
216223
logger.warning(template.format("', '".join(values)))
@@ -465,7 +472,9 @@ def execute(self):
465472
],
466473
Body=self._mask,
467474
)
468-
self._image.annotation_status_code = constances.AnnotationStatus.IN_PROGRESS.value
475+
self._image.annotation_status_code = (
476+
constances.AnnotationStatus.IN_PROGRESS.value
477+
)
469478
self._images.update(self._image)
470479
if self._verbose:
471480
logger.info(

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

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from lib.core.serviceproviders import SuerannotateServiceProvider
2222
from lib.core.usecases.base import BaseReportableUseCae
2323
from lib.core.usecases.base import BaseUseCase
24+
from requests.exceptions import RequestException
2425

2526
logger = logging.getLogger("root")
2627

@@ -418,7 +419,9 @@ def validate_project_name(self):
418419
def get_annotation_classes_repo(self, project: ProjectEntity):
419420
return self._annotation_classes_repo(self._backend_service, project)
420421

421-
def _copy_annotation_classes(self, annotation_classes_entity_mapping: dict, project: ProjectEntity):
422+
def _copy_annotation_classes(
423+
self, annotation_classes_entity_mapping: dict, project: ProjectEntity
424+
):
422425
annotation_classes = self.annotation_classes.get_all()
423426
for annotation_class in annotation_classes:
424427
annotation_class_copy = copy.copy(annotation_class)
@@ -448,42 +451,49 @@ def _copy_settings(self, to_project: ProjectEntity):
448451
setting_copy.project_id = to_project.uuid
449452
new_settings.update(setting_copy)
450453

451-
def _copy_workflow(self, annotation_classes_entity_mapping: dict, to_project: ProjectEntity):
454+
def _copy_workflow(
455+
self, annotation_classes_entity_mapping: dict, to_project: ProjectEntity
456+
):
452457
new_workflows = self._workflows_repo(self._backend_service, to_project)
453458
for workflow in self.workflows.get_all():
454-
existing_workflow_ids = list(
455-
map(lambda i: i.uuid, new_workflows.get_all())
456-
)
459+
existing_workflow_ids = list(map(lambda i: i.uuid, new_workflows.get_all()))
457460
workflow_data = copy.copy(workflow)
458461
workflow_data.project_id = to_project.uuid
459-
workflow_data.class_id = annotation_classes_entity_mapping[workflow.class_id].uuid
462+
workflow_data.class_id = annotation_classes_entity_mapping[
463+
workflow.class_id
464+
].uuid
460465
new_workflows.insert(workflow_data)
461466
workflows = new_workflows.get_all()
462-
new_workflow = next((
463-
work_flow
464-
for work_flow in workflows
465-
if work_flow.uuid not in existing_workflow_ids
466-
), None)
467+
new_workflow = next(
468+
(
469+
work_flow
470+
for work_flow in workflows
471+
if work_flow.uuid not in existing_workflow_ids
472+
),
473+
None,
474+
)
467475
workflow_attributes = []
468476
for attribute in workflow_data.attribute:
469477
for annotation_attribute in annotation_classes_entity_mapping[
470478
workflow.class_id
471479
].attribute_groups:
472480
if (
473-
attribute["attribute"]["attribute_group"]["name"]
474-
== annotation_attribute["name"]
481+
attribute["attribute"]["attribute_group"]["name"]
482+
== annotation_attribute["name"]
475483
):
476484
for annotation_attribute_value in annotation_attribute[
477485
"attributes"
478486
]:
479487
if (
480-
annotation_attribute_value["name"]
481-
== attribute["attribute"]["name"]
488+
annotation_attribute_value["name"]
489+
== attribute["attribute"]["name"]
482490
):
483491
workflow_attributes.append(
484492
{
485493
"workflow_id": new_workflow.uuid,
486-
"attribute_id": annotation_attribute_value["id"]
494+
"attribute_id": annotation_attribute_value[
495+
"id"
496+
],
487497
}
488498
)
489499
break
@@ -501,42 +511,70 @@ def execute(self):
501511
f" {constances.ProjectType.get_name(self._project_to_create.project_type)}."
502512
)
503513
project = self._projects.insert(self._project_to_create)
504-
505514
annotation_classes_entity_mapping = defaultdict(AnnotationClassEntity)
515+
annotation_classes_created = False
506516
if self._include_annotation_classes:
507517
self.reporter.log_info(
508518
f"Cloning annotation classes from {self._project.name} to {self._project_to_create.name}."
509519
)
510-
self._copy_annotation_classes(annotation_classes_entity_mapping, project)
520+
try:
521+
self._copy_annotation_classes(
522+
annotation_classes_entity_mapping, project
523+
)
524+
annotation_classes_created = True
525+
except (AppException, RequestException) as e:
526+
self.reporter.log_warning(
527+
f"Failed to clone annotation classes from {self._project.name} to {self._project_to_create.name}."
528+
)
529+
self.reporter.log_debug(str(e), exc_info=True)
511530

512531
if self._include_settings:
513532
self.reporter.log_info(
514533
f"Cloning settings from {self._project.name} to {self._project_to_create.name}."
515534
)
516-
self._copy_settings(project)
517-
if (
518-
self._include_workflow
519-
and self._project.upload_state != constances.UploadState.EXTERNAL.value
520-
and self._include_annotation_classes
521-
and self._project.project_type not in (
522-
constances.ProjectType.DOCUMENT.value, constances.ProjectType.VIDEO.value
535+
try:
536+
self._copy_settings(project)
537+
except (AppException, RequestException) as e:
538+
self.reporter.log_warning(
539+
f"Failed to clone settings from {self._project.name} to {self._project_to_create.name}."
523540
)
524-
):
525-
self.reporter.log_info(
526-
f"Cloning workflow from {self._project.name} to {self._project_to_create.name}."
527-
)
528-
self._copy_workflow(annotation_classes_entity_mapping, project)
529-
elif self._include_workflow:
530-
self.reporter.log_warning(
531-
"Workflow copy is deprecated for "
532-
f"{constances.ProjectType.get_name(self._project_to_create.project_type)} projects."
533-
)
541+
self.reporter.log_debug(str(e), exc_info=True)
542+
543+
if self._include_workflow and self._include_annotation_classes:
544+
if self._project.project_type in (
545+
constances.ProjectType.DOCUMENT.value,
546+
constances.ProjectType.VIDEO.value,
547+
):
548+
self.reporter.log_warning(
549+
"Workflow copy is deprecated for "
550+
f"{constances.ProjectType.get_name(self._project_to_create.project_type)} projects."
551+
)
552+
elif not annotation_classes_created:
553+
self.reporter.log_info(
554+
f"Skipping the workflow clone from {self._project.name} to {self._project_to_create.name}."
555+
)
556+
else:
557+
self.reporter.log_info(
558+
f"Cloning workflow from {self._project.name} to {self._project_to_create.name}."
559+
)
560+
try:
561+
self._copy_workflow(annotation_classes_entity_mapping, project)
562+
except (AppException, RequestException) as e:
563+
self.reporter.log_warning(
564+
f"Failed to workflow from {self._project.name} to {self._project_to_create.name}."
565+
)
566+
self.reporter.log_debug(str(e), exc_info=True)
534567
if self._include_contributors:
535568
self.reporter.log_info(
536569
f"Cloning contributors from {self._project.name} to {self._project_to_create.name}."
537570
)
538-
self._copy_include_contributors(project)
539-
571+
try:
572+
self._copy_include_contributors(project)
573+
except (AppException, RequestException) as e:
574+
self.reporter.log_warning(
575+
f"Failed to clone contributors from {self._project.name} to {self._project_to_create.name}."
576+
)
577+
self.reporter.log_debug(str(e), exc_info=True)
540578
self._response.data = self._projects.get_one(
541579
uuid=project.uuid, team_id=project.team_id
542580
)
@@ -688,10 +726,12 @@ def validate_image_quality(self):
688726
def validate_project_type(self):
689727
project = self._projects.get_one(uuid=self._project_id, team_id=self._team_id)
690728
for attribute in self._to_update:
691-
if (
692-
attribute.get("attribute", "") == "ImageQuality"
693-
and project.project_type in [constances.ProjectType.VIDEO.value, constances.ProjectType.DOCUMENT.value]
694-
):
729+
if attribute.get(
730+
"attribute", ""
731+
) == "ImageQuality" and project.project_type in [
732+
constances.ProjectType.VIDEO.value,
733+
constances.ProjectType.DOCUMENT.value,
734+
]:
695735
raise AppValidationException(
696736
constances.DEPRICATED_DOCUMENT_VIDEO_MESSAGE
697737
)

0 commit comments

Comments
 (0)