From e96f058768bdda80e3ebba74e9b7d988e3cdca26 Mon Sep 17 00:00:00 2001 From: Narek Mkhitaryan Date: Thu, 10 Jul 2025 12:52:44 +0400 Subject: [PATCH] add categories arg validation --- .../lib/app/interface/sdk_interface.py | 37 +++++++++++++------ .../test_project_categories.py | 20 ++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/superannotate/lib/app/interface/sdk_interface.py b/src/superannotate/lib/app/interface/sdk_interface.py index f6beab25..17c38992 100644 --- a/src/superannotate/lib/app/interface/sdk_interface.py +++ b/src/superannotate/lib/app/interface/sdk_interface.py @@ -867,7 +867,7 @@ def set_contributors_categories( self, project: Union[NotEmptyStr, int], contributors: List[Union[int, str]], - categories: Union[List[str], Literal["*"]], + categories: Union[List[NotEmptyStr], Literal["*"]], ): """ Assign one or more categories to a contributor with an assignable role (Annotator, QA or custom role) @@ -899,6 +899,9 @@ def set_contributors_categories( categories="*" ) """ + if not categories: + AppException("Categories should be a list of strings or '*'.") + project = ( self.controller.get_project_by_id(project).data if isinstance(project, int) @@ -917,7 +920,7 @@ def remove_contributors_categories( self, project: Union[NotEmptyStr, int], contributors: List[Union[int, str]], - categories: Union[List[str], Literal["*"]], + categories: Union[List[NotEmptyStr], Literal["*"]], ): """ Remove one or more categories for a contributor. "*" in the category list will match all categories defined in the project. @@ -946,6 +949,9 @@ def remove_contributors_categories( categories="*" ) """ + if not categories: + AppException("Categories should be a list of strings or '*'.") + project = ( self.controller.get_project_by_id(project).data if isinstance(project, int) @@ -1297,7 +1303,7 @@ def clone_project( return data def create_categories( - self, project: Union[NotEmptyStr, int], categories: List[str] + self, project: Union[NotEmptyStr, int], categories: List[NotEmptyStr] ): """ Create one or more categories in a project. @@ -1316,6 +1322,9 @@ def create_categories( categories=["Shoes", "T-Shirt"] ) """ + if not categories: + raise AppException("Categories should be a list of strings.") + project = ( self.controller.get_project_by_id(project).data if isinstance(project, int) @@ -1387,7 +1396,7 @@ def list_categories(self, project: Union[NotEmptyStr, int]): def remove_categories( self, project: Union[NotEmptyStr, int], - categories: Union[List[str], Literal["*"]], + categories: Union[List[NotEmptyStr], Literal["*"]], ): """ Remove one or more categories in a project. "*" in the category list will match all categories defined in the project. @@ -1413,6 +1422,9 @@ def remove_categories( categories="*" ) """ + if not categories: + AppException("Categories should be a list of strings or '*'.") + project = ( self.controller.get_project_by_id(project).data if isinstance(project, int) @@ -1420,7 +1432,6 @@ def remove_categories( ) self.controller.check_multimodal_project_categorization(project) - categories_to_remove = None query = EmptyQuery() if categories == "*": query &= Filter("id", [0], OperatorEnum.GT) @@ -1432,17 +1443,21 @@ def remove_categories( categories_to_remove = [ c for c in all_categories.data if c.name.lower() in categories ] - query &= Filter("id", [c.id for c in categories_to_remove], OperatorEnum.IN) + if categories_to_remove: + query &= Filter( + "id", [c.id for c in categories_to_remove], OperatorEnum.IN + ) else: raise AppException("Categories should be a list of strings or '*'.") - if categories_to_remove: + if query.condition_set: response = self.controller.service_provider.work_management.remove_project_categories( project_id=project.id, query=query ) - logger.info( - f"{len(response.data)} categories successfully removed from the project." - ) + if response.data: + logger.info( + f"{len(response.data)} categories successfully removed from the project." + ) def create_folder(self, project: NotEmptyStr, folder_name: NotEmptyStr): """ @@ -4497,7 +4512,7 @@ def set_items_category( self, project: Union[NotEmptyStr, Tuple[int, int], Tuple[str, str]], items: List[Union[int, str]], - category: str, + category: NotEmptyStr, ): """ Add categories to one or more items. diff --git a/tests/integration/work_management/test_project_categories.py b/tests/integration/work_management/test_project_categories.py index fbb55ec3..2a63d4c7 100644 --- a/tests/integration/work_management/test_project_categories.py +++ b/tests/integration/work_management/test_project_categories.py @@ -4,6 +4,7 @@ from pathlib import Path from unittest import TestCase +from lib.core.exceptions import AppException from src.superannotate import SAClient sa = SAClient() @@ -144,3 +145,22 @@ def test_delete_all_categories_with_asterisk(self): sa.remove_categories(project=self.PROJECT_NAME, categories="*") categories = sa.list_categories(project=self.PROJECT_NAME) assert len(categories) == 0 + + def test_delete_categories_with_empty_list(self): + with self.assertRaisesRegexp( + AppException, "Categories should be a list of strings or '*'" + ): + sa.remove_categories(project=self.PROJECT_NAME, categories=[]) + + def test_delete_invalid_categories(self): + # silent skip + sa.remove_categories( + project=self.PROJECT_NAME, + categories=["invalid_category_1", "invalid_category_2"], + ) + + def test_create_categories_with_empty_categories(self): + with self.assertRaisesRegexp( + AppException, "Categories should be a list of strings." + ): + sa.create_categories(project=self.PROJECT_NAME, categories=[])