63
63
"VOLUME_MESH" : "VolumeMesher" ,
64
64
}
65
65
66
+ TERMINAL_ERRORS = {
67
+ "validate_fail" ,
68
+ "error" ,
69
+ "diverged" ,
70
+ "blocked" ,
71
+ "aborting" ,
72
+ "aborted" ,
73
+ }
74
+
75
+ RUN_STATUSES = [
76
+ "draft" ,
77
+ "preprocess" ,
78
+ "validating" ,
79
+ "validate" ,
80
+ "running" ,
81
+ "postprocess" ,
82
+ "success" ,
83
+ ]
84
+
66
85
67
86
def _get_url (task_id : str ) -> str :
68
87
"""Get the URL for a task on our server."""
@@ -1070,21 +1089,13 @@ def _status_to_stage(status: str) -> tuple[str, int]:
1070
1089
1071
1090
# Non-verbose path: poll without progress bars then return
1072
1091
if not verbose :
1073
- terminal_errors = {
1074
- "validate_fail" ,
1075
- "error" ,
1076
- "diverged" ,
1077
- "blocked" ,
1078
- "aborting" ,
1079
- "aborted" ,
1080
- }
1081
1092
# Run phase
1082
1093
while True :
1083
1094
d = _batch_detail (batch_id )
1084
1095
s = d .totalStatus .value
1085
1096
total = d .totalTask or 0
1086
1097
r = d .runSuccess or 0
1087
- if s in terminal_errors :
1098
+ if s in TERMINAL_ERRORS :
1088
1099
raise WebError (f"Batch { batch_id } terminated: { s } " )
1089
1100
if total and r >= total :
1090
1101
break
@@ -1096,7 +1107,7 @@ def _status_to_stage(status: str) -> tuple[str, int]:
1096
1107
postprocess_status = d .postprocessStatus
1097
1108
if postprocess_status == "success" :
1098
1109
break
1099
- elif postprocess_status in terminal_errors :
1110
+ elif postprocess_status in TERMINAL_ERRORS :
1100
1111
raise WebError (
1101
1112
f"Batch { batch_id } terminated. Please contact customer support and provide this Component Modeler batch ID: '{ batch_id } '"
1102
1113
)
@@ -1110,20 +1121,9 @@ def _status_to_stage(status: str) -> tuple[str, int]:
1110
1121
TimeElapsedColumn (),
1111
1122
)
1112
1123
with Progress (* progress_columns , console = console , transient = False ) as progress :
1113
- terminal_errors = {"validate_fail" , "error" , "diverged" , "blocked" , "aborting" , "aborted" }
1114
-
1115
1124
# Phase: Run (aggregate + per-task)
1116
1125
p_run = progress .add_task ("Run Total" , total = 1.0 )
1117
1126
task_bars : dict [str , int ] = {}
1118
- run_statuses = [
1119
- "draft" ,
1120
- "preprocess" ,
1121
- "validating" ,
1122
- "validate" ,
1123
- "running" ,
1124
- "postprocess" ,
1125
- "success" ,
1126
- ]
1127
1127
1128
1128
while True :
1129
1129
detail = _batch_detail (batch_id )
@@ -1140,8 +1140,8 @@ def _status_to_stage(status: str) -> tuple[str, int]:
1140
1140
_ , idx = _status_to_stage (tstatus )
1141
1141
pbar = progress .add_task (
1142
1142
f" { name } " ,
1143
- total = len (run_statuses ) - 1 ,
1144
- completed = min (idx , len (run_statuses ) - 1 ),
1143
+ total = len (RUN_STATUSES ) - 1 ,
1144
+ completed = min (idx , len (RUN_STATUSES ) - 1 ),
1145
1145
)
1146
1146
task_bars [name ] = pbar
1147
1147
@@ -1174,7 +1174,7 @@ def _status_to_stage(status: str) -> tuple[str, int]:
1174
1174
1175
1175
if total and r >= total :
1176
1176
break
1177
- if status in terminal_errors :
1177
+ if status in TERMINAL_ERRORS :
1178
1178
raise WebError (f"Batch { batch_id } terminated: { status } " )
1179
1179
progress .refresh ()
1180
1180
time .sleep (REFRESH_TIME )
@@ -1195,7 +1195,7 @@ def _status_to_stage(status: str) -> tuple[str, int]:
1195
1195
progress .update (p_post , completed = 0.33 )
1196
1196
elif postprocess_status == "running" :
1197
1197
progress .update (p_post , completed = 0.55 )
1198
- elif postprocess_status in terminal_errors :
1198
+ elif postprocess_status in TERMINAL_ERRORS :
1199
1199
raise WebError (
1200
1200
f"Batch { batch_id } terminated. Please contact customer support and provide this Component Modeler batch ID: '{ batch_id } '"
1201
1201
)
@@ -1355,22 +1355,40 @@ def estimate_cost(
1355
1355
console = get_logging_console () if verbose else None
1356
1356
1357
1357
if _is_modeler_batch (task_id ):
1358
- status = _batch_detail (task_id ).totalStatus .value
1358
+ d = _batch_detail (task_id )
1359
+ status = d .totalStatus .value
1359
1360
1360
1361
# Wait for a termination status
1361
1362
while status not in ["validate_success" , "success" , "error" , "failed" ]:
1362
1363
time .sleep (REFRESH_TIME )
1363
- status = _batch_detail (task_id ).totalStatus .value
1364
+ d = _batch_detail (task_id )
1365
+ status = d .totalStatus .value
1364
1366
1365
- if status in ["validate_success" , "success" ]:
1366
- est_flex_unit = _batch_detail (task_id ).estFlexUnit
1367
- if verbose :
1368
- console .log (
1369
- f"Maximum FlexCredit cost: { est_flex_unit :1.3f} . Minimum cost depends on "
1370
- "task execution details. Use 'web.real_cost(task_id)' to get the billed FlexCredit "
1371
- "cost after a simulation run."
1372
- )
1373
- return est_flex_unit
1367
+ if status in ["validate_success" , "success" ]:
1368
+ est_flex_unit = _batch_detail (task_id ).estFlexUnit
1369
+ if verbose :
1370
+ console .log (
1371
+ f"Maximum FlexCredit cost: { est_flex_unit :1.3f} . Minimum cost depends on "
1372
+ "task execution details. Use 'web.real_cost(task_id)' to get the billed FlexCredit "
1373
+ "cost after a simulation run."
1374
+ )
1375
+ return est_flex_unit
1376
+ elif status in TERMINAL_ERRORS :
1377
+ log .error (f"The ComponentModeler '{ task_id } ' has failed: { status } " )
1378
+
1379
+ if status == "validate_fail" :
1380
+ assert d .validateErrors is not None
1381
+ for key , error in d .validateErrors .items ():
1382
+ # I don't like this ideally but would like to control the endpoint to make this better
1383
+ error_dict = json .loads (error )
1384
+ validation_error = error_dict ["validation_error" ]
1385
+ log .error (
1386
+ f"Subtask '{ key } ' has failed to validate:"
1387
+ f" \n { validation_error } \n "
1388
+ f"Fix your component modeler configuration. "
1389
+ f"Generate subtask simulations locally using `ComponentModelerType.sim_dict`."
1390
+ )
1391
+ break
1374
1392
else :
1375
1393
task = SimulationTask .get (task_id )
1376
1394
0 commit comments