From 3edc25eafe83c98ab13f3e33243922619df581eb Mon Sep 17 00:00:00 2001 From: krishav Date: Tue, 14 May 2024 20:09:12 +0530 Subject: [PATCH 1/5] fixed server for duplicate attribute names --- cvat/apps/engine/views.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 28bac7295fde..bb6b6b7ec83e 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2282,7 +2282,14 @@ def perform_update(self, serializer): "Sublabels cannot be modified this way. " "Please send a PATCH request with updated parent label data instead.", code=status.HTTP_400_BAD_REQUEST) - + attributes = self.request.data.get('attributes') + encountered_names = set() + for attribute in attributes: + attr_name = attribute.get('name') + if attr_name in encountered_names: + raise ValidationError('attribute with same name exists') + else: + encountered_names.add(attr_name) return super().perform_update(serializer) def perform_destroy(self, instance: models.Label): From c901746fd3da6add5a073486a39a0ca00aa8b604 Mon Sep 17 00:00:00 2001 From: krishav Date: Tue, 14 May 2024 20:22:48 +0530 Subject: [PATCH 2/5] added changelog.md --- .../20240514_201903_krishavrajsingh_duplicateAttribute.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md diff --git a/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md b/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md new file mode 100644 index 000000000000..b389d96dc0c2 --- /dev/null +++ b/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md @@ -0,0 +1,4 @@ +### Fixed + +- server checks attributes with duplicate names and throws ValidationError if found + () From 517f42a2a6701613ecaf25044d4c4c5844bd1917 Mon Sep 17 00:00:00 2001 From: Krishav <99531396+KrishavRajSingh@users.noreply.github.com> Date: Tue, 14 May 2024 23:08:19 +0530 Subject: [PATCH 3/5] Update changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../20240514_201903_krishavrajsingh_duplicateAttribute.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md b/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md index b389d96dc0c2..84217dacc2fa 100644 --- a/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md +++ b/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md @@ -1,4 +1,4 @@ ### Fixed -- server checks attributes with duplicate names and throws ValidationError if found +the server checks attributes with duplicate names and throws ValidationError if found () From 563a962cd57e4075b66febbbdd42f3d545f914fa Mon Sep 17 00:00:00 2001 From: krishav Date: Wed, 15 May 2024 22:48:37 +0530 Subject: [PATCH 4/5] moved logic to LabelSerializer --- ...4_201903_krishavrajsingh_duplicateAttribute.md | 2 +- cvat/apps/engine/serializers.py | 15 +++++++++++++++ cvat/apps/engine/views.py | 9 +-------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md b/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md index b389d96dc0c2..81fa2bcae8af 100644 --- a/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md +++ b/changelog.d/20240514_201903_krishavrajsingh_duplicateAttribute.md @@ -1,4 +1,4 @@ ### Fixed -- server checks attributes with duplicate names and throws ValidationError if found +- REST API allowed to create several attributes with the same name within one label () diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index 200e4b001126..8c8a9ff8658f 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -335,6 +335,13 @@ def update_label( parent_info, logger = cls._get_parent_info(parent_instance) attributes = validated_data.pop('attributespec_set', []) + encountered_names = set() + for attribute in attributes: + attr_name = attribute.get('name') + if attr_name in encountered_names: + raise exceptions.ValidationError('attribute with same name exists') + else: + encountered_names.add(attr_name) if validated_data.get('id') is not None: try: @@ -450,6 +457,14 @@ def create_labels(cls, for label in labels: attributes = label.pop('attributespec_set') + + encountered_names = set() + for attribute in attributes: + attr_name = attribute.get('name') + if attr_name in encountered_names: + raise exceptions.ValidationError('attribute with same name exists') + else: + encountered_names.add(attr_name) if label.get('id', None): del label['id'] diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index bb6b6b7ec83e..28bac7295fde 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2282,14 +2282,7 @@ def perform_update(self, serializer): "Sublabels cannot be modified this way. " "Please send a PATCH request with updated parent label data instead.", code=status.HTTP_400_BAD_REQUEST) - attributes = self.request.data.get('attributes') - encountered_names = set() - for attribute in attributes: - attr_name = attribute.get('name') - if attr_name in encountered_names: - raise ValidationError('attribute with same name exists') - else: - encountered_names.add(attr_name) + return super().perform_update(serializer) def perform_destroy(self, instance: models.Label): From b52798f4b0cb24049b0ba9395026b740f4dc299f Mon Sep 17 00:00:00 2001 From: krishav Date: Thu, 16 May 2024 17:33:02 +0530 Subject: [PATCH 5/5] created function to check duplicates --- cvat/apps/engine/serializers.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index 8c8a9ff8658f..7a60922b89c0 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -321,6 +321,16 @@ def validate(self, attrs): return attrs + @staticmethod + def check_attribute_names_unique(attrs): + encountered_names = set() + for attribute in attrs: + attr_name = attribute.get('name') + if attr_name in encountered_names: + raise serializers.ValidationError(f"Duplicate attribute with name '{attr_name}' exists") + else: + encountered_names.add(attr_name) + @classmethod @transaction.atomic def update_label( @@ -335,13 +345,8 @@ def update_label( parent_info, logger = cls._get_parent_info(parent_instance) attributes = validated_data.pop('attributespec_set', []) - encountered_names = set() - for attribute in attributes: - attr_name = attribute.get('name') - if attr_name in encountered_names: - raise exceptions.ValidationError('attribute with same name exists') - else: - encountered_names.add(attr_name) + + cls.check_attribute_names_unique(attributes) if validated_data.get('id') is not None: try: @@ -457,14 +462,8 @@ def create_labels(cls, for label in labels: attributes = label.pop('attributespec_set') - - encountered_names = set() - for attribute in attributes: - attr_name = attribute.get('name') - if attr_name in encountered_names: - raise exceptions.ValidationError('attribute with same name exists') - else: - encountered_names.add(attr_name) + + cls.check_attribute_names_unique(attributes) if label.get('id', None): del label['id']