2020from lib .app .helpers import extract_project_folder
2121from lib .app .helpers import get_annotation_paths
2222from lib .app .helpers import get_name_url_duplicated_from_csv
23+ from lib .app .helpers import wrap_error as wrap_validation_errors
2324from lib .app .interface .base_interface import BaseInterfaceFacade
2425from lib .app .interface .base_interface import TrackableMeta
2526from lib .app .interface .types import AnnotationStatuses
4243from lib .core import LIMITED_FUNCTIONS
4344from lib .core .entities import AttachmentEntity
4445from lib .core .entities import SettingEntity
46+ from lib .core .entities .classes import AnnotationClassEntity
47+ from lib .core .entities .classes import AttributeGroup
4548from lib .core .entities .integrations import IntegrationEntity
46- from lib .core .entities .project_entities import AnnotationClassEntity
4749from lib .core .enums import ImageQuality
4850from lib .core .exceptions import AppException
49- from lib .core .types import AttributeGroup
5051from lib .core .types import MLModel
5152from lib .core .types import PriorityScore
5253from lib .core .types import Project
53- from lib .infrastructure .controller import Controller
54+ from lib .infrastructure .validators import wrap_error
5455from pydantic import conlist
5556from pydantic import parse_obj_as
5657from pydantic import StrictBool
@@ -579,8 +580,7 @@ def search_annotation_classes(
579580 """
580581 project_name , folder_name = extract_project_folder (project )
581582 classes = self .controller .search_annotation_classes (project_name , name_contains )
582- classes = [BaseSerializer (attribute ).serialize () for attribute in classes .data ]
583- return classes
583+ return [i .dict (fill_enum_values = True ) for i in classes .data ]
584584
585585 def set_project_default_image_quality_in_editor (
586586 self ,
@@ -1140,31 +1140,94 @@ def create_annotation_class(
11401140
11411141 :param project: project name
11421142 :type project: str
1143+
11431144 :param name: name for the class
11441145 :type name: str
1145- :param color: RGB hex color value, e.g., "#FFFFAA"
1146+
1147+ :param color: RGB hex color value, e.g., "#F9E0FA"
11461148 :type color: str
1147- :param attribute_groups: example:
1148- [ { "name": "tall", "is_multiselect": 0, "attributes": [ { "name": "yes" }, { "name": "no" } ] },
1149- { "name": "age", "is_multiselect": 0, "attributes": [ { "name": "young" }, { "name": "old" } ] } ]
1149+
1150+ :param attribute_groups: list of attribute group dicts.
1151+ The values for the "group_type" key are "radio"|"checklist"|"text"|"numeric".
1152+ Mandatory keys for each attribute group are
1153+ - "name"
11501154 :type attribute_groups: list of dicts
1151- :param class_type: class type
1155+
1156+ :param class_type: class type. Should be either "object" or "tag"
11521157 :type class_type: str
11531158
11541159 :return: new class metadata
11551160 :rtype: dict
1161+
1162+ Request Example:
1163+ ::
1164+ attributes_list = [
1165+ {
1166+ "group_type": "radio",
1167+ "name": "Vehicle",
1168+ "attributes": [
1169+ {
1170+ "name": "Car"
1171+ },
1172+ {
1173+ "name": "Track"
1174+ },
1175+ {
1176+ "name": "Bus"
1177+ }
1178+ ],
1179+ "default_value": "Car"
1180+ },
1181+ {
1182+ "group_type": "checklist",
1183+ "name": "Color",
1184+ "attributes": [
1185+ {
1186+ "name": "Yellow"
1187+ },
1188+ {
1189+ "name": "Black"
1190+ },
1191+ {
1192+ "name": "White"
1193+ }
1194+ ],
1195+ "default_value": ["Yellow", "White"]
1196+ },
1197+ {
1198+ "group_type": "text",
1199+ "name": "Timestamp"
1200+ },
1201+ {
1202+ "group_type": "numeric",
1203+ "name": "Description"
1204+ }
1205+ ]
1206+ client.create_annotation_class(
1207+ project="Image Project",
1208+ name="Example Class",
1209+ color="#F9E0FA",
1210+ attribute_groups=attributes_list
1211+ )
1212+
11561213 """
11571214 if isinstance (project , Project ):
11581215 project = project .dict ()
11591216 attribute_groups = (
11601217 list (map (lambda x : x .dict (), attribute_groups )) if attribute_groups else []
11611218 )
1219+ try :
1220+ annotation_class = AnnotationClassEntity (
1221+ name = name ,
1222+ color = color , # noqa
1223+ attribute_groups = attribute_groups ,
1224+ type = class_type , # noqa
1225+ )
1226+ except ValidationError as e :
1227+ raise AppException (wrap_error (e ))
1228+
11621229 response = self .controller .create_annotation_class (
1163- project_name = project ,
1164- name = name ,
1165- color = color ,
1166- attribute_groups = attribute_groups ,
1167- class_type = class_type ,
1230+ project_name = project , annotation_class = annotation_class
11681231 )
11691232 if response .errors :
11701233 raise AppException (response .errors )
@@ -1237,9 +1300,8 @@ def create_annotation_classes_from_classes_json(
12371300 classes_json = json .load (data )
12381301 try :
12391302 annotation_classes = parse_obj_as (List [AnnotationClassEntity ], classes_json )
1240- except ValidationError :
1303+ except ValidationError as _ :
12411304 raise AppException ("Couldn't validate annotation classes." )
1242- logger .info (f"Creating annotation classes in project { project } ." )
12431305 response = self .controller .create_annotation_classes (
12441306 project_name = project ,
12451307 annotation_classes = annotation_classes ,
@@ -1830,13 +1892,14 @@ def add_annotation_point_to_image(
18301892 annotations ,
18311893 point ,
18321894 annotation_class_name ,
1833- image_name ,
18341895 annotation_class_attributes ,
18351896 error ,
18361897 )
1837- self .controller .upload_image_annotations (
1898+ response = self .controller .upload_image_annotations (
18381899 project_name , folder_name , image_name , annotations
18391900 )
1901+ if response .errors :
1902+ raise AppException (response .errors )
18401903
18411904 def add_annotation_comment_to_image (
18421905 self ,
@@ -2103,7 +2166,9 @@ def delete_annotations(
21032166 raise AppException (response .errors )
21042167
21052168 def validate_annotations (
2106- self , project_type : ProjectTypes , annotations_json : Union [NotEmptyStr , Path ]
2169+ self ,
2170+ project_type : ProjectTypes ,
2171+ annotations_json : Union [NotEmptyStr , Path , dict ],
21072172 ):
21082173 """Validates given annotation JSON.
21092174
@@ -2116,16 +2181,18 @@ def validate_annotations(
21162181 :return: The success of the validation
21172182 :rtype: bool
21182183 """
2119- with open (annotations_json ) as file :
2120- annotation_data = json .loads (file .read ())
2121- response = Controller .validate_annotations (project_type , annotation_data )
2122- if response .errors :
2123- raise AppException (response .errors )
2124- is_valid , _ = response .data
2125- if is_valid :
2126- return True
2127- print (response .report )
2128- return False
2184+ if isinstance (annotations_json , dict ):
2185+ annotation_data = annotations_json
2186+ else :
2187+ annotation_data = json .load (open (annotations_json ))
2188+ response = self .controller .validate_annotations (project_type , annotation_data )
2189+ if response .errors :
2190+ raise AppException (response .errors )
2191+ report = response .data
2192+ if not report :
2193+ return True
2194+ print (wrap_validation_errors (report ))
2195+ return False
21292196
21302197 def add_contributors_to_project (
21312198 self ,
0 commit comments