@@ -474,7 +474,7 @@ def list_users(
474474 self ,
475475 * ,
476476 project : Union [int , str ] = None ,
477- include : List [Literal ["custom_fields" ]] = None ,
477+ include : List [Literal ["custom_fields" , "categories" ]] = None ,
478478 ** filters ,
479479 ):
480480 """
@@ -488,7 +488,10 @@ def list_users(
488488
489489 Possible values are
490490
491- - "custom_fields": Includes custom fields and scores assigned to each user.
491+ - "custom_fields": Includes custom fields and scores assigned to each user.
492+ - "categories": Includes a list of categories assigned to each project contributor.
493+ Note: 'project' parameter must be specified when including 'categories'.
494+ :type include: list of str, optional
492495
493496 :param filters: Specifies filtering criteria, with all conditions combined using logical AND.
494497
@@ -860,6 +863,103 @@ def set_user_scores(
860863 )
861864 logger .info ("Scores successfully set." )
862865
866+ def set_contributors_categories (
867+ self ,
868+ project : Union [NotEmptyStr , int ],
869+ contributors : List [Union [int , str ]],
870+ categories : Union [List [str ], Literal ["*" ]],
871+ ):
872+ """
873+ Assign one or more categories to a contributor with an assignable role (Annotator, QA or custom role)
874+ in a Multimodal project. Project Admins are not eligible for category assignments. "*" in the category
875+ list will match all categories defined in the project.
876+
877+
878+ :param project: The name or ID of the project.
879+ :type project: Union[NotEmptyStr, int]
880+
881+ :param contributors: A list of emails or IDs of the contributor.
882+ :type contributors: List[Union[int, str]]
883+
884+ :param categories: A list of category names to assign. Accepts "*" to indicate all available categories in the project.
885+ :type categories: Union[List[str], Literal["*"]]
886+
887+ Request Example:
888+ ::
889+
890+ client.set_contributor_categories(
891+ project="product-review-mm",
892+ contributors=["test@superannotate.com","contributor@superannotate.com"],
893+ categories=["Shoes", "T-Shirt"]
894+ )
895+
896+ client.set_contributor_categories(
897+ project="product-review-mm",
898+ contributors=["test@superannotate.com","contributor@superannotate.com"]
899+ categories="*"
900+ )
901+ """
902+ project = (
903+ self .controller .get_project_by_id (project ).data
904+ if isinstance (project , int )
905+ else self .controller .get_project (project )
906+ )
907+ self .controller .check_multimodal_project_categorization (project )
908+
909+ self .controller .work_management .set_remove_contributor_categories (
910+ project = project ,
911+ contributors = contributors ,
912+ categories = categories ,
913+ operation = "set" ,
914+ )
915+
916+ def remove_contributors_categories (
917+ self ,
918+ project : Union [NotEmptyStr , int ],
919+ contributors : List [Union [int , str ]],
920+ categories : Union [List [str ], Literal ["*" ]],
921+ ):
922+ """
923+ Remove one or more categories for a contributor. "*" in the category list will match all categories defined in the project.
924+
925+ :param project: The name or ID of the project.
926+ :type project: Union[NotEmptyStr, int]
927+
928+ :param contributors: A list of emails or IDs of the contributor.
929+ :type contributors: List[Union[int, str]]
930+
931+ :param categories: A list of category names to remove. Accepts "*" to indicate all available categories in the project.
932+ :type categories: Union[List[str], Literal["*"]]
933+
934+ Request Example:
935+ ::
936+
937+ client.remove_contributor_categories(
938+ project="product-review-mm",
939+ contributors=["test@superannotate.com","contributor@superannotate.com"],
940+ categories=["Shoes", "T-Shirt", "Jeans"]
941+ )
942+
943+ client.remove_contributor_categories(
944+ project="product-review-mm",
945+ contributors=["test@superannotate.com","contributor@superannotate.com"]
946+ categories="*"
947+ )
948+ """
949+ project = (
950+ self .controller .get_project_by_id (project ).data
951+ if isinstance (project , int )
952+ else self .controller .get_project (project )
953+ )
954+ self .controller .check_multimodal_project_categorization (project )
955+
956+ self .controller .work_management .set_remove_contributor_categories (
957+ project = project ,
958+ contributors = contributors ,
959+ categories = categories ,
960+ operation = "remove" ,
961+ )
962+
863963 def get_component_config (self , project : Union [NotEmptyStr , int ], component_id : str ):
864964 """
865965 Retrieves the configuration for a given project and component ID.
@@ -1320,6 +1420,7 @@ def remove_categories(
13201420 )
13211421 self .controller .check_multimodal_project_categorization (project )
13221422
1423+ categories_to_remove = None
13231424 query = EmptyQuery ()
13241425 if categories == "*" :
13251426 query &= Filter ("id" , [0 ], OperatorEnum .GT )
@@ -1335,14 +1436,13 @@ def remove_categories(
13351436 else :
13361437 raise AppException ("Categories should be a list of strings or '*'." )
13371438
1338- response = (
1339- self .controller .service_provider .work_management .remove_project_categories (
1439+ if categories_to_remove :
1440+ response = self .controller .service_provider .work_management .remove_project_categories (
13401441 project_id = project .id , query = query
13411442 )
1342- )
1343- logger .info (
1344- f"{ len (response .data )} categories successfully removed from the project."
1345- )
1443+ logger .info (
1444+ f"{ len (response .data )} categories successfully removed from the project."
1445+ )
13461446
13471447 def create_folder (self , project : NotEmptyStr , folder_name : NotEmptyStr ):
13481448 """
0 commit comments