From f117d5d1937d6b2ce9a35a4f2ce0e0e5092b0784 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Wed, 10 Mar 2021 15:25:25 +0300 Subject: [PATCH 1/4] Add label check on import --- cvat/apps/dataset_manager/bindings.py | 54 +++++++++++++++------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index 38444d4d18bc..09cc4efe8445 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -626,6 +626,8 @@ def find_dataset_root(dm_dataset, task_data): prefix = prefix[:-1] return prefix +class CvatImportError(Exception): + pass def import_dm_annotations(dm_dataset, task_data): shapes = { @@ -662,26 +664,32 @@ def import_dm_annotations(dm_dataset, task_data): if 1 < s and group_map[g]} group_map = {g: i for i, g in enumerate([0] + sorted(group_map))} - for ann in item.annotations: - if ann.type in shapes: - task_data.add_shape(task_data.LabeledShape( - type=shapes[ann.type], - frame=frame_number, - label=label_cat.items[ann.label].name, - points=ann.points, - occluded=ann.attributes.get('occluded') == True, - z_order=ann.z_order, - group=group_map.get(ann.group, 0), - source='manual', - attributes=[task_data.Attribute(name=n, value=str(v)) - for n, v in ann.attributes.items()], - )) - elif ann.type == datumaro.AnnotationType.label: - task_data.add_tag(task_data.Tag( - frame=frame_number, - label=label_cat.items[ann.label].name, - group=group_map.get(ann.group, 0), - source='manual', - attributes=[task_data.Attribute(name=n, value=str(v)) - for n, v in ann.attributes.items()], - )) + for idx, ann in enumerate(item.annotations): + try: + if hasattr(ann, 'label') and ann.label is None: + raise CvatImportError("annotation has no label") + if ann.type in shapes: + task_data.add_shape(task_data.LabeledShape( + type=shapes[ann.type], + frame=frame_number, + label=label_cat.items[ann.label].name, + points=ann.points, + occluded=ann.attributes.get('occluded') == True, + z_order=ann.z_order, + group=group_map.get(ann.group, 0), + source='manual', + attributes=[task_data.Attribute(name=n, value=str(v)) + for n, v in ann.attributes.items()], + )) + elif ann.type == datumaro.AnnotationType.label: + task_data.add_tag(task_data.Tag( + frame=frame_number, + label=label_cat.items[ann.label].name, + group=group_map.get(ann.group, 0), + source='manual', + attributes=[task_data.Attribute(name=n, value=str(v)) + for n, v in ann.attributes.items()], + )) + except Exception as e: + raise CvatImportError("Image {}: can't import annotation " + "#{}: {}".format(item.id, idx, e)) \ No newline at end of file From 08a6936704d0414ee7408c008aaa2b529f99f58e Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Wed, 10 Mar 2021 15:28:43 +0300 Subject: [PATCH 2/4] include annotation type --- cvat/apps/dataset_manager/bindings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index 09cc4efe8445..23c101bbc0b1 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -692,4 +692,4 @@ def import_dm_annotations(dm_dataset, task_data): )) except Exception as e: raise CvatImportError("Image {}: can't import annotation " - "#{}: {}".format(item.id, idx, e)) \ No newline at end of file + "#{} ({}): {}".format(item.id, idx, type(ann), e)) \ No newline at end of file From 7acfb04846308c9451c7519a73093c8684822f0b Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Wed, 10 Mar 2021 15:29:46 +0300 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 272042f77e71..eb53fc7eba8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - All methods for interative segmentation accept negative points as well - Persistent queue added to logstash () - Improved maintanance of popups visibility () +- Improved error messages for annotation import () ### Deprecated From 0d413b52df06d7280d0b3d99c1a3852fe25dbfeb Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Wed, 10 Mar 2021 16:07:04 +0300 Subject: [PATCH 4/4] Make the message prettier --- cvat/apps/dataset_manager/bindings.py | 12 ++++++------ cvat/apps/engine/views.py | 13 ++++++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index 23c101bbc0b1..50fe21cce437 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -596,6 +596,9 @@ def convert_attrs(label, cvat_attrs): return item_anno +class CvatImportError(Exception): + pass + def match_dm_item(item, task_data, root_hint=None): is_video = task_data.meta['task']['mode'] == 'interpolation' @@ -610,8 +613,8 @@ def match_dm_item(item, task_data, root_hint=None): frame_number = cast(osp.basename(item.id)[len('frame_'):], int) if not frame_number in task_data.frame_info: - raise Exception("Could not match item id: '%s' with any task frame" % - item.id) + raise CvatImportError("Could not match item id: " + "'%s' with any task frame" % item.id) return frame_number def find_dataset_root(dm_dataset, task_data): @@ -626,9 +629,6 @@ def find_dataset_root(dm_dataset, task_data): prefix = prefix[:-1] return prefix -class CvatImportError(Exception): - pass - def import_dm_annotations(dm_dataset, task_data): shapes = { datumaro.AnnotationType.bbox: ShapeType.RECTANGLE, @@ -692,4 +692,4 @@ def import_dm_annotations(dm_dataset, task_data): )) except Exception as e: raise CvatImportError("Image {}: can't import annotation " - "#{} ({}): {}".format(item.id, idx, type(ann), e)) \ No newline at end of file + "#{} ({}): {}".format(item.id, idx, ann.type.name, e)) \ No newline at end of file diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 11a1750ec52f..5ab76673b72e 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -37,6 +37,7 @@ import cvat.apps.dataset_manager as dm import cvat.apps.dataset_manager.views # pylint: disable=unused-import from cvat.apps.authentication import auth +from cvat.apps.dataset_manager.bindings import CvatImportError from cvat.apps.dataset_manager.serializers import DatasetFormatsSerializer from cvat.apps.engine.frame_provider import FrameProvider from cvat.apps.engine.models import ( @@ -1030,7 +1031,17 @@ def _import_annotations(request, rq_id, rq_func, pk, format_name): os.remove(rq_job.meta['tmp_file']) exc_info = str(rq_job.exc_info) rq_job.delete() - return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + # RQ adds a prefix with exception class name + import_error_prefix = '{}.{}'.format( + CvatImportError.__module__, CvatImportError.__name__) + if exc_info.startswith(import_error_prefix): + exc_info = exc_info.replace(import_error_prefix + ': ', '') + return Response(data=exc_info, + status=status.HTTP_400_BAD_REQUEST) + else: + return Response(data=exc_info, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response(status=status.HTTP_202_ACCEPTED)