Skip to content

Commit d660e48

Browse files
Vaghinak BasentsyanVaghinak Basentsyan
authored andcommitted
Changed validation message
1 parent 2c8d849 commit d660e48

File tree

14 files changed

+112
-66
lines changed

14 files changed

+112
-66
lines changed

src/superannotate/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,4 @@
299299
logging.config.fileConfig(
300300
os.path.join(WORKING_DIR, "logging.conf"), disable_existing_loggers=False
301301
)
302-
sys.tracebacklimit = 1
302+
sys.tracebacklimit = 0

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ def init(path_to_config_json: str):
7474
@validate_arguments
7575
def set_auth_token(token: str):
7676
controller.set_token(token)
77-
controller.init(controller.config_path)
7877

7978

8079
@Trackable
@@ -566,7 +565,7 @@ def copy_image(
566565

567566
if copy_annotation_status:
568567
res = controller.get_image(
569-
project_name=source_project,
568+
project_name=source_project_name,
570569
image_name=image_name,
571570
folder_path=source_folder_name,
572571
)
@@ -2185,6 +2184,8 @@ def set_image_annotation_status(
21852184
)
21862185
if response.errors:
21872186
raise AppException(response.errors)
2187+
image = controller.get_image_metadata(project_name, folder_name, image_name).data
2188+
return ImageSerializer(image).serialize()
21882189

21892190

21902191
@Trackable

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,29 @@ def validate(cls, value: Union[str]) -> Union[str]:
3434
return value
3535

3636

37+
def to_chunks(t, size=2):
38+
it = iter(t)
39+
return zip(*[it] * size)
40+
41+
3742
def validate_arguments(func):
3843
@wraps(func)
3944
def wrapped(*args, **kwargs):
4045
try:
4146
return pydantic_validate_arguments(func)(*args, **kwargs)
4247
except ValidationError as e:
43-
messages = defaultdict(list)
48+
error_messages = defaultdict(list)
4449
for error in e.errors():
45-
messages[error["loc"][0]].append(f"{error['loc'][-1]} {error['msg']}")
46-
raise AppException(
47-
"\n".join(
48-
[
49-
f"Invalid {message}: {','.join(text)}"
50-
for message, text in messages.items()
51-
]
50+
error_messages[error["loc"][0]].append(
51+
f"{''.join([f' {i[0]} -> {i[1]}' for i in to_chunks(error['loc'])])} {error['loc'][-1]} {error['msg']}"
5252
)
53-
)
53+
texts = ["\n"]
54+
for error, text in error_messages.items():
55+
texts.append(
56+
"{} {}{}".format(
57+
error, " " * (21 - len(error)), f"\n {' ' * 21}".join(text)
58+
)
59+
)
60+
raise AppException("\n".join(texts))
5461

5562
return wrapped

src/superannotate/lib/core/serviceproviders.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def __call__(cls, *args, **kwargs):
1616
SingleInstanceMetaClass._instances[cls] = super().__call__(*args, **kwargs)
1717
return SingleInstanceMetaClass._instances[cls]
1818

19+
def get_instance(cls):
20+
if cls._instances:
21+
return cls._instances[cls]
22+
1923

2024
class SuerannotateServiceProvider(metaclass=SingleInstanceMetaClass):
2125
@abstractmethod

src/superannotate/lib/core/types.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class AttributeGroup(BaseModel):
2222

2323
class ClassesJson(BaseModel):
2424
name: StrictStr
25-
color: Optional[StrictStr]
26-
attribute_groups: Optional[List[AttributeGroup]]
25+
color: StrictStr
26+
attribute_groups: List[AttributeGroup]
2727

2828

2929
class Metadata(BaseModel):

src/superannotate/lib/core/usecases.py

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -380,14 +380,19 @@ def execute(self):
380380

381381
if self._include_workflow:
382382
new_workflows = self._workflows_repo(self._backend_service, project)
383-
workflow_attributes = []
384383
for workflow in self.workflows.get_all():
384+
existing_workflow_ids = list(map(lambda i: i.uuid, new_workflows.get_all()))
385385
workflow_data = copy.copy(workflow)
386386
workflow_data.project_id = project.uuid
387387
workflow_data.class_id = annotation_classes_mapping[
388388
workflow.class_id
389389
].uuid
390-
new_workflow = new_workflows.insert(workflow_data)
390+
new_workflows.insert(workflow_data)
391+
workflows = new_workflows.get_all()
392+
new_workflow = [
393+
work_flow for work_flow in workflows if work_flow.uuid not in existing_workflow_ids
394+
][0]
395+
workflow_attributes = []
391396
for attribute in workflow_data.attribute:
392397
for annotation_attribute in annotation_classes_mapping[
393398
workflow.class_id
@@ -811,13 +816,13 @@ def execute(self):
811816
)
812817
if "error" in response:
813818
raise AppException(response["error"])
814-
folder_str = (
815-
"" if self._folder_names is None else "/".join(self._folder_names)
816-
)
817819

820+
report_message = self._project.name
821+
if self._folder_names:
822+
report_message = f"[{', '.join(self._folder_names)}]"
818823
logger.info(
819824
f"Prepared export {response['name']} for project "
820-
f"{self._project.name}/{folder_str} (project ID {self._project.uuid})."
825+
f"{report_message} (project ID {self._project.uuid})."
821826
)
822827
self._response.data = response
823828

@@ -1018,10 +1023,10 @@ def validate_folder(self):
10181023

10191024
def execute(self):
10201025
if self.is_valid():
1021-
is_updated = self._folders.update(self._folder)
1022-
if not is_updated:
1026+
folder = self._folders.update(self._folder)
1027+
if not folder:
10231028
self._response.errors = AppException("Couldn't rename folder.")
1024-
self._response.data = self._folder
1029+
self._response.data = folder
10251030
return self._response
10261031

10271032

@@ -2281,9 +2286,7 @@ def fill_classes_data(self, annotations: dict):
22812286
for annotation in (
22822287
i for i in annotations["instances"] if i.get("type", None) == "template"
22832288
):
2284-
template_name = templates.get(
2285-
annotation.get("templateId"), None
2286-
)
2289+
template_name = templates.get(annotation.get("templateId"), None)
22872290
if template_name:
22882291
annotation["templateName"] = template_name
22892292

@@ -2292,26 +2295,26 @@ def fill_classes_data(self, annotations: dict):
22922295
if annotation_class_id not in annotation_classes:
22932296
continue
22942297
annotation["className"] = annotation_classes[annotation_class_id]["name"]
2295-
for attribute in annotation["attributes"]:
2298+
for attribute in [i for i in annotation["attributes"] if "groupId" in i]:
22962299
if (
2297-
attribute["groupName"]
2300+
attribute["groupId"]
22982301
not in annotation_classes[annotation_class_id]["attribute_groups"]
22992302
):
23002303
continue
23012304
attribute["groupName"] = annotation_classes[annotation_class_id][
23022305
"attribute_groups"
23032306
][attribute["groupId"]]["name"]
23042307
if (
2305-
attribute["name"]
2308+
attribute["groupId"]
23062309
not in annotation_classes[annotation_class_id]["attribute_groups"][
23072310
attribute["groupId"]
23082311
]["attributes"]
23092312
):
2310-
del attribute["groupName"]
2313+
del attribute["groupId"]
23112314
continue
23122315
attribute["name"] = annotation_classes[annotation_class_id][
23132316
"attribute_groups"
2314-
][attribute["groupId"]]["attributes"]
2317+
][attribute["groupId"]]["name"]
23152318

23162319
def execute(self):
23172320
if self.is_valid():
@@ -3336,7 +3339,7 @@ def fill_classes_data(self, annotations: dict):
33363339
continue
33373340
attribute["id"] = annotation_classes[annotation_class_name][
33383341
"attribute_groups"
3339-
][attribute["groupName"]]["attributes"]
3342+
][attribute["groupName"]]["attributes"][attribute["name"]]
33403343

33413344
def execute(self):
33423345
if self.is_valid():
@@ -3424,6 +3427,8 @@ def __init__(
34243427
self._annotations_to_upload = None
34253428
self._missing_annotations = None
34263429
self.missing_attribute_groups = set()
3430+
self.missing_classes = set()
3431+
self.missing_attributes = set()
34273432

34283433
@property
34293434
def s3_client(self):
@@ -3474,6 +3479,7 @@ def fill_classes_data(self, annotations: dict):
34743479
annotation_class_name = annotation["className"]
34753480
if annotation_class_name not in annotation_classes:
34763481
if annotation_class_name not in unknown_classes:
3482+
self.missing_classes.add(annotation_class_name)
34773483
unknown_classes[annotation_class_name] = {
34783484
"id": -(len(unknown_classes) + 1),
34793485
"attribute_groups": {},
@@ -3516,6 +3522,7 @@ def fill_classes_data(self, annotations: dict):
35163522
][attribute["groupName"]]["attributes"]
35173523
):
35183524
del attribute["groupId"]
3525+
self.missing_attributes.add(attribute["name"])
35193526
continue
35203527
attribute["id"] = annotation_classes[annotation_class_name][
35213528
"attribute_groups"
@@ -3661,10 +3668,7 @@ def execute(self):
36613668
failed_annotations,
36623669
missing_annotations,
36633670
)
3664-
if self.missing_attribute_groups:
3665-
logger.warning(
3666-
f"Couldn't find annotation groups [{', '.join(self.missing_attribute_groups)}]"
3667-
)
3671+
self.report_missing_data()
36683672
return self._response
36693673

36703674
def upload_to_s3(
@@ -3706,6 +3710,18 @@ def upload_to_s3(
37063710
bucket.put_object(Key=image_info["annotation_bluemap_path"], Body=file)
37073711
return image_id_name_map[image_id], True
37083712

3713+
def report_missing_data(self):
3714+
if self.missing_classes:
3715+
logger.warning(f"Couldn't find classes [{', '.join(self.missing_classes)}]")
3716+
if self.missing_attribute_groups:
3717+
logger.warning(
3718+
f"Couldn't find annotation groups [{', '.join(self.missing_attribute_groups)}]"
3719+
)
3720+
if self.missing_attributes:
3721+
logger.warning(
3722+
f"Couldn't find attributes [{', '.join(self.missing_attributes)}]"
3723+
)
3724+
37093725

37103726
class CreateModelUseCase(BaseUseCase):
37113727
def __init__(
@@ -4295,6 +4311,7 @@ def execute(self):
42954311
image_ids=image_ids,
42964312
)
42974313
if not res.ok:
4314+
# todo add error message in the response
42984315
return self._response
42994316

43004317
success_images = []
@@ -4782,24 +4799,14 @@ def images_to_upload(self):
47824799
duplicated_paths.append(path)
47834800
filtered_paths = [
47844801
path
4785-
for path in filtered_paths
4802+
for path in paths
47864803
if not any(
4787-
[
4788-
path.endswith(extension)
4789-
for extension in self.exclude_file_patterns
4790-
]
4791-
)
4792-
]
4793-
duplicated_paths = [
4794-
path
4795-
for path in duplicated_paths
4796-
if not any(
4797-
[
4798-
path.endswith(extension)
4799-
for extension in self.exclude_file_patterns
4800-
]
4804+
[extension in path for extension in self.exclude_file_patterns]
48014805
)
48024806
]
4807+
excluded_paths = [path for path in paths if path not in filtered_paths]
4808+
if excluded_paths:
4809+
logger.info(f"Excluded paths {', '.join(excluded_paths)}")
48034810

48044811
image_entities = (
48054812
GetBulkImages(

src/superannotate/lib/infrastructure/controller.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def init(self, config_path):
8989
else:
9090
self._backend_client.api_url = main_endpoint
9191
self._backend_client._auth_token = token
92+
self._backend_client.get_session.cache_clear()
9293
self._team_id = int(self.configs.get_one("token").value.split("=")[-1])
9394
self._team = None
9495

@@ -108,13 +109,21 @@ def team_name(self):
108109
_, self._team_name = self.get_team()
109110
return self._team_name
110111

112+
@staticmethod
113+
def _validate_token(token: str):
114+
try:
115+
int(token.split("=")[-1])
116+
except ValueError:
117+
raise AppException("Invalid token.")
118+
111119
def set_token(self, token):
120+
self._validate_token(token)
121+
self._team_id = int(token.split("=")[-1])
112122
self.configs.insert(ConfigEntity("token", token))
113-
self._backend_client = SuperannotateBackendService(
114-
api_url=self.configs.get_one("main_endpoint").value,
115-
auth_token=self.configs.get_one("token").value,
116-
logger=self._logger,
117-
)
123+
self._backend_client = SuperannotateBackendService.get_instance()
124+
self._backend_client._api_url = self.configs.get_one("main_endpoint").value
125+
self._backend_client._auth_token = self.configs.get_one("token").value
126+
self._backend_client.get_session.cache_clear()
118127

119128
@property
120129
def projects(self):

src/superannotate/lib/infrastructure/helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def wrapper_cache(func):
1212

1313
@wraps(func)
1414
def wrapped_func(*args, **kwargs):
15+
wrapped_func.cache_clear = func.cache_clear
1516
if datetime.utcnow() >= func.expiration:
1617
func.cache_clear()
1718
func.expiration = datetime.utcnow() + func.lifetime

src/superannotate/lib/infrastructure/repositories.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,9 @@ def insert(self, entity: FolderEntity) -> FolderEntity:
269269
def update(self, entity: FolderEntity):
270270
project_id = entity.project_id
271271
team_id = entity.team_id
272-
return self._service.update_folder(project_id, team_id, entity.to_dict())
272+
response = self._service.update_folder(project_id, team_id, entity.to_dict())
273+
if response:
274+
return self.dict2entity(response)
273275

274276
def delete(self, entity: FolderEntity):
275277
return self._service.delete_folders(

src/superannotate/lib/infrastructure/services.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ def update_folder(self, project_id: int, team_id: int, folder_data: dict):
346346
)
347347
params = {"project_id": project_id, "team_id": team_id}
348348
res = self._request(update_folder_url, "put", data=folder_data, params=params)
349-
return res.ok
349+
if res.ok:
350+
return res.json()
350351

351352
def get_project_settings(self, project_id: int, team_id: int):
352353
get_settings_url = urljoin(

0 commit comments

Comments
 (0)