1313
1414from labelbox import parser
1515from labelbox import utils
16- from labelbox .exceptions import (
17- InvalidQueryError ,
18- LabelboxError ,
19- ProcessingWaitTimeout ,
20- ResourceConflict ,
21- ResourceNotFoundError
22- )
16+ from labelbox .exceptions import error_message_for_unparsed_graphql_error
17+ from labelbox .exceptions import (InvalidQueryError , LabelboxError ,
18+ ProcessingWaitTimeout , ResourceConflict ,
19+ ResourceNotFoundError )
2320from labelbox .orm import query
2421from labelbox .orm .db_object import DbObject , Deletable , Updateable , experimental
2522from labelbox .orm .model import Entity , Field , Relationship
@@ -122,6 +119,7 @@ class Project(DbObject, Updateable, Deletable):
122119 media_type = Field .Enum (MediaType , "media_type" , "allowedMediaType" )
123120 editor_task_type = Field .Enum (EditorTaskType , "editor_task_type" )
124121 data_row_count = Field .Int ("data_row_count" )
122+ model_setup_complete : Field = Field .Boolean ("model_setup_complete" )
125123
126124 # Relationships
127125 created_by = Relationship .ToOne ("User" , False , "created_by" )
@@ -1271,7 +1269,18 @@ def add_model_config(self, model_config_id: str) -> str:
12711269 "projectId" : self .uid ,
12721270 "modelConfigId" : model_config_id ,
12731271 }
1274- result = self .client .execute (query , params )
1272+ try :
1273+ result = self .client .execute (query , params )
1274+ except LabelboxError as e :
1275+ if e .message .startswith (
1276+ "Unknown error: "
1277+ ): # unfortunate hack to handle unparsed graphql errors
1278+ error_content = error_message_for_unparsed_graphql_error (
1279+ e .message )
1280+ else :
1281+ error_content = e .message
1282+ raise LabelboxError (message = error_content ) from e
1283+
12751284 if not result :
12761285 raise ResourceNotFoundError (ModelConfig , params )
12771286 return result ["createProjectModelConfig" ]["projectModelConfigId" ]
@@ -1299,6 +1308,29 @@ def delete_project_model_config(self, project_model_config_id: str) -> bool:
12991308 raise ResourceNotFoundError (ProjectModelConfig , params )
13001309 return result ["deleteProjectModelConfig" ]["success" ]
13011310
1311+ def set_project_model_setup_complete (self ) -> bool :
1312+ """
1313+ Sets the model setup is complete for this project.
1314+ Once the project is marked as "setup complete", a user can not add / modify delete existing project model configs.
1315+
1316+ Returns:
1317+ bool, indicates if the model setup is complete.
1318+
1319+ NOTE: This method should only be used for live model evaluation projects.
1320+ It will throw exception for all other types of projects.
1321+ User Project is_chat_evaluation() method to check if the project is a live model evaluation project.
1322+ """
1323+ query = """mutation SetProjectModelSetupCompletePyApi($projectId: ID!) {
1324+ setProjectModelSetupComplete(where: {id: $projectId}, data: {modelSetupComplete: true}) {
1325+ modelSetupComplete
1326+ }
1327+ }"""
1328+
1329+ result = self .client .execute (query , {"projectId" : self .uid })
1330+ self .model_setup_complete = result ["setProjectModelSetupComplete" ][
1331+ "modelSetupComplete" ]
1332+ return result ["setProjectModelSetupComplete" ]["modelSetupComplete" ]
1333+
13021334 def set_labeling_parameter_overrides (
13031335 self , data : List [LabelingParameterOverrideInput ]) -> bool :
13041336 """ Adds labeling parameter overrides to this project.
@@ -1752,7 +1784,9 @@ def __check_data_rows_have_been_processed(
17521784 return response ["queryAllDataRowsHaveBeenProcessed" ][
17531785 "allDataRowsHaveBeenProcessed" ]
17541786
1755- def get_overview (self , details = False ) -> Union [ProjectOverview , ProjectOverviewDetailed ]:
1787+ def get_overview (
1788+ self ,
1789+ details = False ) -> Union [ProjectOverview , ProjectOverviewDetailed ]:
17561790 """Return the overview of a project.
17571791
17581792 This method returns the number of data rows per task queue and issues of a project,
@@ -1792,7 +1826,7 @@ def get_overview(self, details=False) -> Union[ProjectOverview, ProjectOverviewD
17921826
17931827 # Must use experimental to access "issues"
17941828 result = self .client .execute (query , {"projectId" : self .uid },
1795- experimental = True )["project" ]
1829+ experimental = True )["project" ]
17961830
17971831 # Reformat category names
17981832 overview = {
@@ -1805,26 +1839,28 @@ def get_overview(self, details=False) -> Union[ProjectOverview, ProjectOverviewD
18051839
18061840 # Rename categories
18071841 overview ["to_label" ] = overview .pop ("unlabeled" )
1808- overview ["total_data_rows" ] = overview .pop ("all" )
1842+ overview ["total_data_rows" ] = overview .pop ("all" )
18091843
18101844 if not details :
18111845 return ProjectOverview (** overview )
18121846 else :
18131847 # Build dictionary for queue details for review and rework queues
18141848 for category in ["rework" , "review" ]:
18151849 queues = [
1816- {tq ["name" ]: tq .get ("dataRowCount" )}
1850+ {
1851+ tq ["name" ]: tq .get ("dataRowCount" )
1852+ }
18171853 for tq in result .get ("taskQueues" )
18181854 if tq .get ("queueType" ) == f"MANUAL_{ category .upper ()} _QUEUE"
18191855 ]
18201856
1821- overview [f"in_{ category } " ] = {
1857+ overview [f"in_{ category } " ] = {
18221858 "data" : queues ,
18231859 "total" : overview [f"in_{ category } " ]
18241860 }
1825-
1861+
18261862 return ProjectOverviewDetailed (** overview )
1827-
1863+
18281864 def clone (self ) -> "Project" :
18291865 """
18301866 Clones the current project.
0 commit comments