ddeutil-workflow 0.0.54__py3-none-any.whl → 0.0.56__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ddeutil/workflow/__about__.py +1 -1
- ddeutil/workflow/__init__.py +4 -2
- ddeutil/workflow/__main__.py +30 -0
- ddeutil/workflow/api/__init__.py +170 -1
- ddeutil/workflow/api/routes/job.py +22 -21
- ddeutil/workflow/api/routes/schedules.py +0 -2
- ddeutil/workflow/api/routes/workflows.py +3 -4
- ddeutil/workflow/conf.py +144 -94
- ddeutil/workflow/{cron.py → event.py} +36 -20
- ddeutil/workflow/exceptions.py +10 -1
- ddeutil/workflow/job.py +23 -14
- ddeutil/workflow/result.py +1 -0
- ddeutil/workflow/scheduler.py +33 -74
- ddeutil/workflow/stages.py +169 -116
- ddeutil/workflow/workflow.py +57 -106
- {ddeutil_workflow-0.0.54.dist-info → ddeutil_workflow-0.0.56.dist-info}/METADATA +5 -7
- ddeutil_workflow-0.0.56.dist-info/RECORD +31 -0
- ddeutil_workflow-0.0.56.dist-info/entry_points.txt +2 -0
- ddeutil/workflow/api/api.py +0 -170
- ddeutil_workflow-0.0.54.dist-info/RECORD +0 -31
- {ddeutil_workflow-0.0.54.dist-info → ddeutil_workflow-0.0.56.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.54.dist-info → ddeutil_workflow-0.0.56.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.54.dist-info → ddeutil_workflow-0.0.56.dist-info}/top_level.txt +0 -0
ddeutil/workflow/stages.py
CHANGED
@@ -194,9 +194,8 @@ class BaseStage(BaseModel, ABC):
|
|
194
194
|
object from the current stage ID before release the final result.
|
195
195
|
|
196
196
|
:param params: (DictData) A parameter data.
|
197
|
-
:param run_id: (str) A running stage ID
|
198
|
-
:param parent_run_id: (str) A parent
|
199
|
-
execution.
|
197
|
+
:param run_id: (str) A running stage ID.
|
198
|
+
:param parent_run_id: (str) A parent running ID.
|
200
199
|
:param result: (Result) A result object for keeping context and status
|
201
200
|
data before execution.
|
202
201
|
:param event: (Event) An event manager that pass to the stage execution.
|
@@ -213,19 +212,16 @@ class BaseStage(BaseModel, ABC):
|
|
213
212
|
)
|
214
213
|
|
215
214
|
try:
|
216
|
-
|
217
|
-
return rs
|
215
|
+
return self.execute(params, result=result, event=event)
|
218
216
|
except Exception as e:
|
219
|
-
|
220
|
-
|
221
|
-
)
|
217
|
+
e_name: str = e.__class__.__name__
|
218
|
+
result.trace.error(f"[STAGE]: Handler:{NEWLINE}{e_name}: {e}")
|
222
219
|
if dynamic("stage_raise_error", f=raise_error, extras=self.extras):
|
223
220
|
if isinstance(e, StageException):
|
224
221
|
raise
|
225
222
|
|
226
223
|
raise StageException(
|
227
|
-
f"{self.__class__.__name__}:
|
228
|
-
f"{e.__class__.__name__}: {e}"
|
224
|
+
f"{self.__class__.__name__}: {NEWLINE}{e_name}: {e}"
|
229
225
|
) from e
|
230
226
|
|
231
227
|
return result.catch(status=FAILED, context={"errors": to_dict(e)})
|
@@ -252,6 +248,11 @@ class BaseStage(BaseModel, ABC):
|
|
252
248
|
}
|
253
249
|
}
|
254
250
|
|
251
|
+
The keys that will set to the received context is `outputs`,
|
252
|
+
`errors`, and `skipped` keys. The `errors` and `skipped` keys will
|
253
|
+
extract from the result context if it exists. If it does not found, it
|
254
|
+
will not set on the received context.
|
255
|
+
|
255
256
|
Important:
|
256
257
|
|
257
258
|
This method is use for reconstruct the result context and transfer
|
@@ -431,17 +432,14 @@ class BaseAsyncStage(BaseStage):
|
|
431
432
|
rs: Result = await self.axecute(params, result=result, event=event)
|
432
433
|
return rs
|
433
434
|
except Exception as e: # pragma: no cov
|
434
|
-
|
435
|
-
|
436
|
-
)
|
437
|
-
|
435
|
+
e_name: str = e.__class__.__name__
|
436
|
+
await result.trace.aerror(f"[STAGE]: Handler {e_name}: {e}")
|
438
437
|
if dynamic("stage_raise_error", f=raise_error, extras=self.extras):
|
439
438
|
if isinstance(e, StageException):
|
440
439
|
raise
|
441
440
|
|
442
441
|
raise StageException(
|
443
|
-
f"{self.__class__.__name__}:
|
444
|
-
f"{e.__class__.__name__}: {e}"
|
442
|
+
f"{self.__class__.__name__}: {NEWLINE}{e_name}: {e}"
|
445
443
|
) from None
|
446
444
|
|
447
445
|
return result.catch(status=FAILED, context={"errors": to_dict(e)})
|
@@ -537,11 +535,10 @@ class EmptyStage(BaseAsyncStage):
|
|
537
535
|
|
538
536
|
:rtype: Result
|
539
537
|
"""
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
)
|
538
|
+
result: Result = result or Result(
|
539
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
540
|
+
extras=self.extras,
|
541
|
+
)
|
545
542
|
|
546
543
|
if not self.echo:
|
547
544
|
message: str = "..."
|
@@ -678,11 +675,10 @@ class BashStage(BaseStage):
|
|
678
675
|
|
679
676
|
:rtype: Result
|
680
677
|
"""
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
)
|
678
|
+
result: Result = result or Result(
|
679
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
680
|
+
extras=self.extras,
|
681
|
+
)
|
686
682
|
|
687
683
|
result.trace.info(f"[STAGE]: Shell-Execute: {self.name}")
|
688
684
|
|
@@ -811,11 +807,10 @@ class PyStage(BaseStage):
|
|
811
807
|
|
812
808
|
:rtype: Result
|
813
809
|
"""
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
)
|
810
|
+
result: Result = result or Result(
|
811
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
812
|
+
extras=self.extras,
|
813
|
+
)
|
819
814
|
|
820
815
|
lc: DictData = {}
|
821
816
|
gb: DictData = (
|
@@ -927,11 +922,10 @@ class CallStage(BaseStage):
|
|
927
922
|
|
928
923
|
:rtype: Result
|
929
924
|
"""
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
)
|
925
|
+
result: Result = result or Result(
|
926
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
927
|
+
extras=self.extras,
|
928
|
+
)
|
935
929
|
|
936
930
|
call_func: TagFunc = extract_call(
|
937
931
|
param2template(self.uses, params, extras=self.extras),
|
@@ -1087,11 +1081,10 @@ class TriggerStage(BaseStage):
|
|
1087
1081
|
from .exceptions import WorkflowException
|
1088
1082
|
from .workflow import Workflow
|
1089
1083
|
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
)
|
1084
|
+
result: Result = result or Result(
|
1085
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
1086
|
+
extras=self.extras,
|
1087
|
+
)
|
1095
1088
|
|
1096
1089
|
_trigger: str = param2template(self.trigger, params, extras=self.extras)
|
1097
1090
|
result.trace.info(f"[STAGE]: Trigger-Execute: {_trigger!r}")
|
@@ -1121,10 +1114,10 @@ class TriggerStage(BaseStage):
|
|
1121
1114
|
|
1122
1115
|
class ParallelStage(BaseStage): # pragma: no cov
|
1123
1116
|
"""Parallel stage executor that execute branch stages with multithreading.
|
1124
|
-
This stage let you set the fix branches for running
|
1117
|
+
This stage let you set the fix branches for running child stage inside it on
|
1125
1118
|
multithread pool.
|
1126
1119
|
|
1127
|
-
This stage is not the low-level stage model because it runs
|
1120
|
+
This stage is not the low-level stage model because it runs multi-stages
|
1128
1121
|
in this stage execution.
|
1129
1122
|
|
1130
1123
|
Data Validate:
|
@@ -1170,9 +1163,8 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1170
1163
|
result: Result,
|
1171
1164
|
*,
|
1172
1165
|
event: Event | None = None,
|
1173
|
-
) ->
|
1174
|
-
"""
|
1175
|
-
ID.
|
1166
|
+
) -> Result:
|
1167
|
+
"""Execute all stage with specific branch ID.
|
1176
1168
|
|
1177
1169
|
:param branch: (str) A branch ID.
|
1178
1170
|
:param params: (DictData) A parameter data.
|
@@ -1180,7 +1172,7 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1180
1172
|
:param event: (Event) An Event manager instance that use to cancel this
|
1181
1173
|
execution if it forces stopped by parent execution.
|
1182
1174
|
|
1183
|
-
:rtype:
|
1175
|
+
:rtype: Result
|
1184
1176
|
"""
|
1185
1177
|
result.trace.debug(f"[STAGE]: Execute Branch: {branch!r}")
|
1186
1178
|
context: DictData = copy.deepcopy(params)
|
@@ -1192,14 +1184,14 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1192
1184
|
stage.extras = self.extras
|
1193
1185
|
|
1194
1186
|
if stage.is_skipped(params=context):
|
1195
|
-
result.trace.info(f"
|
1187
|
+
result.trace.info(f"[STAGE]: Skip stage: {stage.iden!r}")
|
1196
1188
|
stage.set_outputs(output={"skipped": True}, to=output)
|
1197
1189
|
continue
|
1198
1190
|
|
1199
1191
|
if event and event.is_set():
|
1200
1192
|
error_msg: str = (
|
1201
1193
|
"Branch-Stage was canceled from event that had set before "
|
1202
|
-
"stage
|
1194
|
+
"stage branch execution."
|
1203
1195
|
)
|
1204
1196
|
return result.catch(
|
1205
1197
|
status=CANCEL,
|
@@ -1223,9 +1215,21 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1223
1215
|
stage.set_outputs(rs.context, to=output)
|
1224
1216
|
stage.set_outputs(stage.get_outputs(output), to=context)
|
1225
1217
|
except (StageException, UtilException) as e: # pragma: no cov
|
1226
|
-
result.trace.error(
|
1218
|
+
result.trace.error(
|
1219
|
+
f"[STAGE]: {e.__class__.__name__}:{NEWLINE}{e}"
|
1220
|
+
)
|
1221
|
+
result.catch(
|
1222
|
+
status=FAILED,
|
1223
|
+
parallel={
|
1224
|
+
branch: {
|
1225
|
+
"branch": branch,
|
1226
|
+
"stages": filter_func(output.pop("stages", {})),
|
1227
|
+
"errors": e.to_dict(),
|
1228
|
+
},
|
1229
|
+
},
|
1230
|
+
)
|
1227
1231
|
raise StageException(
|
1228
|
-
f"Sub-Stage
|
1232
|
+
f"Sub-Stage raise: {e.__class__.__name__}: {e}"
|
1229
1233
|
) from None
|
1230
1234
|
|
1231
1235
|
if rs.status == FAILED:
|
@@ -1233,7 +1237,7 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1233
1237
|
f"Branch-Stage was break because it has a sub stage, "
|
1234
1238
|
f"{stage.iden}, failed without raise error."
|
1235
1239
|
)
|
1236
|
-
|
1240
|
+
result.catch(
|
1237
1241
|
status=FAILED,
|
1238
1242
|
parallel={
|
1239
1243
|
branch: {
|
@@ -1243,6 +1247,7 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1243
1247
|
},
|
1244
1248
|
},
|
1245
1249
|
)
|
1250
|
+
raise StageException(error_msg)
|
1246
1251
|
|
1247
1252
|
return result.catch(
|
1248
1253
|
status=SUCCESS,
|
@@ -1270,19 +1275,28 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1270
1275
|
|
1271
1276
|
:rtype: Result
|
1272
1277
|
"""
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
)
|
1278
|
+
result: Result = result or Result(
|
1279
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
1280
|
+
extras=self.extras,
|
1281
|
+
)
|
1278
1282
|
event: Event = Event() if event is None else event
|
1279
1283
|
result.trace.info(
|
1280
1284
|
f"[STAGE]: Parallel-Execute: {self.max_workers} workers."
|
1281
1285
|
)
|
1282
1286
|
result.catch(status=WAIT, context={"parallel": {}})
|
1287
|
+
if event and event.is_set(): # pragma: no cov
|
1288
|
+
return result.catch(
|
1289
|
+
status=CANCEL,
|
1290
|
+
context={
|
1291
|
+
"errors": StageException(
|
1292
|
+
"Stage was canceled from event that had set "
|
1293
|
+
"before stage parallel execution."
|
1294
|
+
).to_dict()
|
1295
|
+
},
|
1296
|
+
)
|
1297
|
+
|
1283
1298
|
with ThreadPoolExecutor(
|
1284
|
-
max_workers=self.max_workers,
|
1285
|
-
thread_name_prefix="parallel_stage_exec_",
|
1299
|
+
max_workers=self.max_workers, thread_name_prefix="stage_parallel_"
|
1286
1300
|
) as executor:
|
1287
1301
|
|
1288
1302
|
context: DictData = {}
|
@@ -1299,17 +1313,18 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
1299
1313
|
for branch in self.parallel
|
1300
1314
|
)
|
1301
1315
|
|
1302
|
-
|
1303
|
-
for future in done:
|
1316
|
+
for future in as_completed(futures):
|
1304
1317
|
try:
|
1305
1318
|
future.result()
|
1306
1319
|
except StageException as e:
|
1307
1320
|
status = FAILED
|
1308
1321
|
result.trace.error(
|
1309
|
-
f"[STAGE]: {e.__class__.__name__}
|
1322
|
+
f"[STAGE]: {e.__class__.__name__}:{NEWLINE}{e}"
|
1310
1323
|
)
|
1311
|
-
|
1312
|
-
|
1324
|
+
if "errors" in context:
|
1325
|
+
context["errors"].append(e.to_dict())
|
1326
|
+
else:
|
1327
|
+
context["errors"] = [e.to_dict()]
|
1313
1328
|
return result.catch(status=status, context=context)
|
1314
1329
|
|
1315
1330
|
|
@@ -1318,7 +1333,7 @@ class ForEachStage(BaseStage):
|
|
1318
1333
|
foreach list.
|
1319
1334
|
|
1320
1335
|
This stage is not the low-level stage model because it runs
|
1321
|
-
|
1336
|
+
multi-stages in this stage execution.
|
1322
1337
|
|
1323
1338
|
Data Validate:
|
1324
1339
|
>>> stage = {
|
@@ -1363,7 +1378,7 @@ class ForEachStage(BaseStage):
|
|
1363
1378
|
*,
|
1364
1379
|
event: Event | None = None,
|
1365
1380
|
) -> Result:
|
1366
|
-
"""Execute
|
1381
|
+
"""Execute all stage with specific foreach item.
|
1367
1382
|
|
1368
1383
|
:param item: (str | int) An item that want to execution.
|
1369
1384
|
:param params: (DictData) A parameter data.
|
@@ -1385,7 +1400,7 @@ class ForEachStage(BaseStage):
|
|
1385
1400
|
stage.extras = self.extras
|
1386
1401
|
|
1387
1402
|
if stage.is_skipped(params=context):
|
1388
|
-
result.trace.info(f"
|
1403
|
+
result.trace.info(f"[STAGE]: Skip stage: {stage.iden!r}")
|
1389
1404
|
stage.set_outputs(output={"skipped": True}, to=output)
|
1390
1405
|
continue
|
1391
1406
|
|
@@ -1416,7 +1431,9 @@ class ForEachStage(BaseStage):
|
|
1416
1431
|
stage.set_outputs(rs.context, to=output)
|
1417
1432
|
stage.set_outputs(stage.get_outputs(output), to=context)
|
1418
1433
|
except (StageException, UtilException) as e:
|
1419
|
-
result.trace.error(
|
1434
|
+
result.trace.error(
|
1435
|
+
f"[STAGE]: {e.__class__.__name__}:{NEWLINE}{e}"
|
1436
|
+
)
|
1420
1437
|
result.catch(
|
1421
1438
|
status=FAILED,
|
1422
1439
|
foreach={
|
@@ -1436,7 +1453,8 @@ class ForEachStage(BaseStage):
|
|
1436
1453
|
f"Item-Stage was break because it has a sub stage, "
|
1437
1454
|
f"{stage.iden}, failed without raise error."
|
1438
1455
|
)
|
1439
|
-
|
1456
|
+
result.trace.warning(f"[STAGE]: {error_msg}")
|
1457
|
+
result.catch(
|
1440
1458
|
status=FAILED,
|
1441
1459
|
foreach={
|
1442
1460
|
item: {
|
@@ -1446,6 +1464,8 @@ class ForEachStage(BaseStage):
|
|
1446
1464
|
},
|
1447
1465
|
},
|
1448
1466
|
)
|
1467
|
+
raise StageException(error_msg)
|
1468
|
+
|
1449
1469
|
return result.catch(
|
1450
1470
|
status=SUCCESS,
|
1451
1471
|
foreach={
|
@@ -1470,21 +1490,24 @@ class ForEachStage(BaseStage):
|
|
1470
1490
|
:param event: (Event) An Event manager instance that use to cancel this
|
1471
1491
|
execution if it forces stopped by parent execution.
|
1472
1492
|
|
1493
|
+
:raise TypeError: If the foreach does not match with type list.
|
1494
|
+
|
1473
1495
|
:rtype: Result
|
1474
1496
|
"""
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
)
|
1497
|
+
result: Result = result or Result(
|
1498
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
1499
|
+
extras=self.extras,
|
1500
|
+
)
|
1480
1501
|
event: Event = Event() if event is None else event
|
1481
1502
|
foreach: Union[list[str], list[int]] = (
|
1482
1503
|
param2template(self.foreach, params, extras=self.extras)
|
1483
1504
|
if isinstance(self.foreach, str)
|
1484
1505
|
else self.foreach
|
1485
1506
|
)
|
1507
|
+
|
1508
|
+
# [VALIDATE]: Type of the foreach should be `list` type.
|
1486
1509
|
if not isinstance(foreach, list):
|
1487
|
-
raise
|
1510
|
+
raise TypeError(f"Does not support foreach: {foreach!r}")
|
1488
1511
|
|
1489
1512
|
result.trace.info(f"[STAGE]: Foreach-Execute: {foreach!r}.")
|
1490
1513
|
result.catch(status=WAIT, context={"items": foreach, "foreach": {}})
|
@@ -1531,7 +1554,7 @@ class ForEachStage(BaseStage):
|
|
1531
1554
|
for future in done:
|
1532
1555
|
try:
|
1533
1556
|
future.result()
|
1534
|
-
except
|
1557
|
+
except StageException as e:
|
1535
1558
|
status = FAILED
|
1536
1559
|
result.trace.error(
|
1537
1560
|
f"[STAGE]: {e.__class__.__name__}:{NEWLINE}{e}"
|
@@ -1544,6 +1567,9 @@ class UntilStage(BaseStage):
|
|
1544
1567
|
"""Until stage executor that will run stages in each loop until it valid
|
1545
1568
|
with stop loop condition.
|
1546
1569
|
|
1570
|
+
This stage is not the low-level stage model because it runs
|
1571
|
+
multi-stages in this stage execution.
|
1572
|
+
|
1547
1573
|
Data Validate:
|
1548
1574
|
>>> stage = {
|
1549
1575
|
... "name": "Until stage execution",
|
@@ -1582,7 +1608,7 @@ class UntilStage(BaseStage):
|
|
1582
1608
|
alias="max-loop",
|
1583
1609
|
)
|
1584
1610
|
|
1585
|
-
def
|
1611
|
+
def execute_loop(
|
1586
1612
|
self,
|
1587
1613
|
item: T,
|
1588
1614
|
loop: int,
|
@@ -1590,8 +1616,7 @@ class UntilStage(BaseStage):
|
|
1590
1616
|
result: Result,
|
1591
1617
|
event: Event | None = None,
|
1592
1618
|
) -> tuple[Result, T]:
|
1593
|
-
"""Execute
|
1594
|
-
variable.
|
1619
|
+
"""Execute all stage with specific loop and item.
|
1595
1620
|
|
1596
1621
|
:param item: (T) An item that want to execution.
|
1597
1622
|
:param loop: (int) A number of loop.
|
@@ -1601,6 +1626,7 @@ class UntilStage(BaseStage):
|
|
1601
1626
|
execution if it forces stopped by parent execution.
|
1602
1627
|
|
1603
1628
|
:rtype: tuple[Result, T]
|
1629
|
+
:return: Return a pair of Result and changed item.
|
1604
1630
|
"""
|
1605
1631
|
result.trace.debug(f"... Execute until item: {item!r}")
|
1606
1632
|
context: DictData = copy.deepcopy(params)
|
@@ -1613,14 +1639,14 @@ class UntilStage(BaseStage):
|
|
1613
1639
|
stage.extras = self.extras
|
1614
1640
|
|
1615
1641
|
if stage.is_skipped(params=context):
|
1616
|
-
result.trace.info(f"
|
1642
|
+
result.trace.info(f"[STAGE]: Skip stage: {stage.iden!r}")
|
1617
1643
|
stage.set_outputs(output={"skipped": True}, to=output)
|
1618
1644
|
continue
|
1619
1645
|
|
1620
1646
|
if event and event.is_set():
|
1621
1647
|
error_msg: str = (
|
1622
|
-
"
|
1623
|
-
"stage
|
1648
|
+
"Loop-Stage was canceled from event that had set before "
|
1649
|
+
"stage loop execution."
|
1624
1650
|
)
|
1625
1651
|
return (
|
1626
1652
|
result.catch(
|
@@ -1652,11 +1678,42 @@ class UntilStage(BaseStage):
|
|
1652
1678
|
|
1653
1679
|
stage.set_outputs(_output, to=context)
|
1654
1680
|
except (StageException, UtilException) as e:
|
1655
|
-
result.trace.error(
|
1681
|
+
result.trace.error(
|
1682
|
+
f"[STAGE]: {e.__class__.__name__}:{NEWLINE}{e}"
|
1683
|
+
)
|
1684
|
+
result.catch(
|
1685
|
+
status=FAILED,
|
1686
|
+
until={
|
1687
|
+
loop: {
|
1688
|
+
"loop": loop,
|
1689
|
+
"item": item,
|
1690
|
+
"stages": filter_func(output.pop("stages", {})),
|
1691
|
+
"errors": e.to_dict(),
|
1692
|
+
}
|
1693
|
+
},
|
1694
|
+
)
|
1656
1695
|
raise StageException(
|
1657
1696
|
f"Sub-Stage execution error: {e.__class__.__name__}: {e}"
|
1658
1697
|
) from None
|
1659
1698
|
|
1699
|
+
if rs.status == FAILED:
|
1700
|
+
error_msg: str = (
|
1701
|
+
f"Loop-Stage was break because it has a sub stage, "
|
1702
|
+
f"{stage.iden}, failed without raise error."
|
1703
|
+
)
|
1704
|
+
result.catch(
|
1705
|
+
status=FAILED,
|
1706
|
+
until={
|
1707
|
+
loop: {
|
1708
|
+
"loop": loop,
|
1709
|
+
"item": item,
|
1710
|
+
"stages": filter_func(output.pop("stages", {})),
|
1711
|
+
"errors": StageException(error_msg).to_dict(),
|
1712
|
+
}
|
1713
|
+
},
|
1714
|
+
)
|
1715
|
+
raise StageException(error_msg)
|
1716
|
+
|
1660
1717
|
return (
|
1661
1718
|
result.catch(
|
1662
1719
|
status=SUCCESS,
|
@@ -1678,8 +1735,7 @@ class UntilStage(BaseStage):
|
|
1678
1735
|
result: Result | None = None,
|
1679
1736
|
event: Event | None = None,
|
1680
1737
|
) -> Result:
|
1681
|
-
"""Execute
|
1682
|
-
setter step.
|
1738
|
+
"""Execute until loop with checking until condition.
|
1683
1739
|
|
1684
1740
|
:param params: (DictData) A parameter data.
|
1685
1741
|
:param result: (Result) A Result instance for return context and status.
|
@@ -1688,10 +1744,10 @@ class UntilStage(BaseStage):
|
|
1688
1744
|
|
1689
1745
|
:rtype: Result
|
1690
1746
|
"""
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1747
|
+
result: Result = result or Result(
|
1748
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
1749
|
+
extras=self.extras,
|
1750
|
+
)
|
1695
1751
|
|
1696
1752
|
result.trace.info(f"[STAGE]: Until-Execution: {self.until}")
|
1697
1753
|
item: Union[str, int, bool] = param2template(
|
@@ -1709,12 +1765,12 @@ class UntilStage(BaseStage):
|
|
1709
1765
|
context={
|
1710
1766
|
"errors": StageException(
|
1711
1767
|
"Stage was canceled from event that had set "
|
1712
|
-
"before stage
|
1768
|
+
"before stage loop execution."
|
1713
1769
|
).to_dict()
|
1714
1770
|
},
|
1715
1771
|
)
|
1716
1772
|
|
1717
|
-
result, item = self.
|
1773
|
+
result, item = self.execute_loop(
|
1718
1774
|
item=item,
|
1719
1775
|
loop=loop,
|
1720
1776
|
params=params,
|
@@ -1725,10 +1781,10 @@ class UntilStage(BaseStage):
|
|
1725
1781
|
loop += 1
|
1726
1782
|
if item is None:
|
1727
1783
|
result.trace.warning(
|
1728
|
-
"...
|
1729
|
-
"default."
|
1784
|
+
f"... Loop-Execute not set item. It use loop: {loop} by "
|
1785
|
+
f"default."
|
1730
1786
|
)
|
1731
|
-
item = loop
|
1787
|
+
item: int = loop
|
1732
1788
|
|
1733
1789
|
next_track: bool = eval(
|
1734
1790
|
param2template(
|
@@ -1741,8 +1797,8 @@ class UntilStage(BaseStage):
|
|
1741
1797
|
)
|
1742
1798
|
if not isinstance(next_track, bool):
|
1743
1799
|
raise StageException(
|
1744
|
-
"Return type of until condition
|
1745
|
-
f"
|
1800
|
+
"Return type of until condition not be `boolean`, getting"
|
1801
|
+
f": {next_track!r}"
|
1746
1802
|
)
|
1747
1803
|
track: bool = not next_track
|
1748
1804
|
delay(0.025)
|
@@ -1830,7 +1886,6 @@ class CaseStage(BaseStage):
|
|
1830
1886
|
context: DictData = copy.deepcopy(params)
|
1831
1887
|
context.update({"case": case})
|
1832
1888
|
output: DictData = {"case": case, "stages": {}}
|
1833
|
-
|
1834
1889
|
for stage in stages:
|
1835
1890
|
|
1836
1891
|
if self.extras:
|
@@ -1913,11 +1968,10 @@ class CaseStage(BaseStage):
|
|
1913
1968
|
|
1914
1969
|
:rtype: Result
|
1915
1970
|
"""
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
)
|
1971
|
+
result: Result = result or Result(
|
1972
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
1973
|
+
extras=self.extras,
|
1974
|
+
)
|
1921
1975
|
|
1922
1976
|
_case: Optional[str] = param2template(
|
1923
1977
|
self.case, params, extras=self.extras
|
@@ -1973,7 +2027,7 @@ class CaseStage(BaseStage):
|
|
1973
2027
|
|
1974
2028
|
|
1975
2029
|
class RaiseStage(BaseStage): # pragma: no cov
|
1976
|
-
"""Raise error stage
|
2030
|
+
"""Raise error stage executor that raise `StageException` that use a message
|
1977
2031
|
field for making error message before raise.
|
1978
2032
|
|
1979
2033
|
Data Validate:
|
@@ -2005,11 +2059,10 @@ class RaiseStage(BaseStage): # pragma: no cov
|
|
2005
2059
|
:param event: (Event) An Event manager instance that use to cancel this
|
2006
2060
|
execution if it forces stopped by parent execution.
|
2007
2061
|
"""
|
2008
|
-
|
2009
|
-
|
2010
|
-
|
2011
|
-
|
2012
|
-
)
|
2062
|
+
result: Result = result or Result(
|
2063
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
2064
|
+
extras=self.extras,
|
2065
|
+
)
|
2013
2066
|
message: str = param2template(self.message, params, extras=self.extras)
|
2014
2067
|
result.trace.info(f"[STAGE]: Raise-Execute: {message!r}.")
|
2015
2068
|
raise StageException(message)
|
@@ -2163,10 +2216,10 @@ class DockerStage(BaseStage): # pragma: no cov
|
|
2163
2216
|
|
2164
2217
|
:rtype: Result
|
2165
2218
|
"""
|
2166
|
-
|
2167
|
-
|
2168
|
-
|
2169
|
-
|
2219
|
+
result: Result = result or Result(
|
2220
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
2221
|
+
extras=self.extras,
|
2222
|
+
)
|
2170
2223
|
|
2171
2224
|
result.trace.info(f"[STAGE]: Docker-Execute: {self.image}:{self.tag}")
|
2172
2225
|
|
@@ -2258,10 +2311,10 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
2258
2311
|
|
2259
2312
|
:rtype: Result
|
2260
2313
|
"""
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2314
|
+
result: Result = result or Result(
|
2315
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
2316
|
+
extras=self.extras,
|
2317
|
+
)
|
2265
2318
|
|
2266
2319
|
result.trace.info(f"[STAGE]: Py-Virtual-Execute: {self.name}")
|
2267
2320
|
run: str = param2template(dedent(self.run), params, extras=self.extras)
|