ddeutil-workflow 0.0.57__py3-none-any.whl → 0.0.59__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/__cron.py +3 -3
- ddeutil/workflow/conf.py +7 -5
- ddeutil/workflow/event.py +12 -12
- ddeutil/workflow/exceptions.py +3 -3
- ddeutil/workflow/job.py +44 -36
- ddeutil/workflow/logs.py +123 -82
- ddeutil/workflow/params.py +13 -5
- ddeutil/workflow/result.py +18 -18
- ddeutil/workflow/reusables.py +9 -9
- ddeutil/workflow/scheduler.py +17 -15
- ddeutil/workflow/stages.py +149 -102
- ddeutil/workflow/utils.py +6 -6
- ddeutil/workflow/workflow.py +48 -48
- {ddeutil_workflow-0.0.57.dist-info → ddeutil_workflow-0.0.59.dist-info}/METADATA +6 -3
- ddeutil_workflow-0.0.59.dist-info/RECORD +31 -0
- {ddeutil_workflow-0.0.57.dist-info → ddeutil_workflow-0.0.59.dist-info}/WHEEL +1 -1
- ddeutil_workflow-0.0.57.dist-info/RECORD +0 -31
- {ddeutil_workflow-0.0.57.dist-info → ddeutil_workflow-0.0.59.dist-info}/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.57.dist-info → ddeutil_workflow-0.0.59.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.57.dist-info → ddeutil_workflow-0.0.59.dist-info}/top_level.txt +0 -0
ddeutil/workflow/stages.py
CHANGED
@@ -141,8 +141,8 @@ class BaseStage(BaseModel, ABC):
|
|
141
141
|
self,
|
142
142
|
params: DictData,
|
143
143
|
*,
|
144
|
-
result: Result
|
145
|
-
event: Event
|
144
|
+
result: Optional[Result] = None,
|
145
|
+
event: Optional[Event] = None,
|
146
146
|
) -> Result:
|
147
147
|
"""Execute abstraction method that action something by sub-model class.
|
148
148
|
This is important method that make this class is able to be the stage.
|
@@ -162,12 +162,12 @@ class BaseStage(BaseModel, ABC):
|
|
162
162
|
self,
|
163
163
|
params: DictData,
|
164
164
|
*,
|
165
|
-
run_id: str
|
166
|
-
parent_run_id: str
|
167
|
-
result: Result
|
168
|
-
event: Event
|
169
|
-
raise_error: bool
|
170
|
-
) -> Result
|
165
|
+
run_id: Optional[str] = None,
|
166
|
+
parent_run_id: Optional[str] = None,
|
167
|
+
result: Optional[Result] = None,
|
168
|
+
event: Optional[Event] = None,
|
169
|
+
raise_error: Optional[bool] = None,
|
170
|
+
) -> Union[Result, DictData]:
|
171
171
|
"""Handler stage execution result from the stage `execute` method.
|
172
172
|
|
173
173
|
This stage exception handler still use ok-error concept, but it
|
@@ -376,8 +376,8 @@ class BaseAsyncStage(BaseStage):
|
|
376
376
|
self,
|
377
377
|
params: DictData,
|
378
378
|
*,
|
379
|
-
result: Result
|
380
|
-
event: Event
|
379
|
+
result: Optional[Result] = None,
|
380
|
+
event: Optional[Event] = None,
|
381
381
|
) -> Result:
|
382
382
|
raise NotImplementedError(
|
383
383
|
"Async Stage should implement `execute` method."
|
@@ -388,8 +388,8 @@ class BaseAsyncStage(BaseStage):
|
|
388
388
|
self,
|
389
389
|
params: DictData,
|
390
390
|
*,
|
391
|
-
result: Result
|
392
|
-
event: Event
|
391
|
+
result: Optional[Result] = None,
|
392
|
+
event: Optional[Event] = None,
|
393
393
|
) -> Result:
|
394
394
|
"""Async execution method for this Empty stage that only logging out to
|
395
395
|
stdout.
|
@@ -411,11 +411,11 @@ class BaseAsyncStage(BaseStage):
|
|
411
411
|
self,
|
412
412
|
params: DictData,
|
413
413
|
*,
|
414
|
-
run_id: str
|
415
|
-
parent_run_id: str
|
416
|
-
result: Result
|
417
|
-
event: Event
|
418
|
-
raise_error: bool
|
414
|
+
run_id: Optional[str] = None,
|
415
|
+
parent_run_id: Optional[str] = None,
|
416
|
+
result: Optional[Result] = None,
|
417
|
+
event: Optional[Event] = None,
|
418
|
+
raise_error: Optional[bool] = None,
|
419
419
|
) -> Result:
|
420
420
|
"""Async Handler stage execution result from the stage `execute` method.
|
421
421
|
|
@@ -487,8 +487,8 @@ class EmptyStage(BaseAsyncStage):
|
|
487
487
|
self,
|
488
488
|
params: DictData,
|
489
489
|
*,
|
490
|
-
result: Result
|
491
|
-
event: Event
|
490
|
+
result: Optional[Result] = None,
|
491
|
+
event: Optional[Event] = None,
|
492
492
|
) -> Result:
|
493
493
|
"""Execution method for the Empty stage that do only logging out to
|
494
494
|
stdout.
|
@@ -507,13 +507,13 @@ class EmptyStage(BaseAsyncStage):
|
|
507
507
|
run_id=gen_id(self.name + (self.id or ""), unique=True),
|
508
508
|
extras=self.extras,
|
509
509
|
)
|
510
|
-
|
511
|
-
|
512
|
-
message: str = "..."
|
513
|
-
else:
|
514
|
-
message: str = param2template(
|
510
|
+
message: str = (
|
511
|
+
param2template(
|
515
512
|
dedent(self.echo.strip("\n")), params, extras=self.extras
|
516
513
|
)
|
514
|
+
if self.echo
|
515
|
+
else "..."
|
516
|
+
)
|
517
517
|
|
518
518
|
result.trace.info(
|
519
519
|
f"[STAGE]: Execute Empty-Stage: {self.name!r}: ( {message} )"
|
@@ -528,8 +528,8 @@ class EmptyStage(BaseAsyncStage):
|
|
528
528
|
self,
|
529
529
|
params: DictData,
|
530
530
|
*,
|
531
|
-
result: Result
|
532
|
-
event: Event
|
531
|
+
result: Optional[Result] = None,
|
532
|
+
event: Optional[Event] = None,
|
533
533
|
) -> Result:
|
534
534
|
"""Async execution method for this Empty stage that only logging out to
|
535
535
|
stdout.
|
@@ -546,12 +546,13 @@ class EmptyStage(BaseAsyncStage):
|
|
546
546
|
extras=self.extras,
|
547
547
|
)
|
548
548
|
|
549
|
-
|
550
|
-
|
551
|
-
else:
|
552
|
-
message: str = param2template(
|
549
|
+
message: str = (
|
550
|
+
param2template(
|
553
551
|
dedent(self.echo.strip("\n")), params, extras=self.extras
|
554
552
|
)
|
553
|
+
if self.echo
|
554
|
+
else "..."
|
555
|
+
)
|
555
556
|
|
556
557
|
result.trace.info(f"[STAGE]: Empty-Stage: {self.name!r}: ( {message} )")
|
557
558
|
if self.sleep > 0:
|
@@ -598,13 +599,13 @@ class BashStage(BaseAsyncStage):
|
|
598
599
|
|
599
600
|
@contextlib.asynccontextmanager
|
600
601
|
async def acreate_sh_file(
|
601
|
-
self, bash: str, env: DictStr, run_id: str
|
602
|
+
self, bash: str, env: DictStr, run_id: Optional[str] = None
|
602
603
|
) -> AsyncIterator[TupleStr]:
|
603
604
|
"""Async create and write `.sh` file with the `aiofiles` package.
|
604
605
|
|
605
606
|
:param bash: (str) A bash statement.
|
606
607
|
:param env: (DictStr) An environment variable that set before run bash.
|
607
|
-
:param run_id: (str
|
608
|
+
:param run_id: (Optional[str]) A running stage ID that use for writing sh
|
608
609
|
file instead generate by UUID4.
|
609
610
|
|
610
611
|
:rtype: AsyncIterator[TupleStr]
|
@@ -634,14 +635,14 @@ class BashStage(BaseAsyncStage):
|
|
634
635
|
|
635
636
|
@contextlib.contextmanager
|
636
637
|
def create_sh_file(
|
637
|
-
self, bash: str, env: DictStr, run_id: str
|
638
|
+
self, bash: str, env: DictStr, run_id: Optional[str] = None
|
638
639
|
) -> Iterator[TupleStr]:
|
639
640
|
"""Create and write the `.sh` file before giving this file name to
|
640
641
|
context. After that, it will auto delete this file automatic.
|
641
642
|
|
642
643
|
:param bash: (str) A bash statement.
|
643
644
|
:param env: (DictStr) An environment variable that set before run bash.
|
644
|
-
:param run_id: (str
|
645
|
+
:param run_id: (Optional[str]) A running stage ID that use for writing sh
|
645
646
|
file instead generate by UUID4.
|
646
647
|
|
647
648
|
:rtype: Iterator[TupleStr]
|
@@ -672,8 +673,8 @@ class BashStage(BaseAsyncStage):
|
|
672
673
|
self,
|
673
674
|
params: DictData,
|
674
675
|
*,
|
675
|
-
result: Result
|
676
|
-
event: Event
|
676
|
+
result: Optional[Result] = None,
|
677
|
+
event: Optional[Event] = None,
|
677
678
|
) -> Result:
|
678
679
|
"""Execute bash statement with the Python build-in `subprocess` package.
|
679
680
|
It will catch result from the `subprocess.run` returning output like
|
@@ -729,8 +730,8 @@ class BashStage(BaseAsyncStage):
|
|
729
730
|
self,
|
730
731
|
params: DictData,
|
731
732
|
*,
|
732
|
-
result: Result
|
733
|
-
event: Event
|
733
|
+
result: Optional[Result] = None,
|
734
|
+
event: Optional[Event] = None,
|
734
735
|
) -> Result:
|
735
736
|
"""Async execution method for this Bash stage that only logging out to
|
736
737
|
stdout.
|
@@ -857,8 +858,8 @@ class PyStage(BaseAsyncStage):
|
|
857
858
|
self,
|
858
859
|
params: DictData,
|
859
860
|
*,
|
860
|
-
result: Result
|
861
|
-
event: Event
|
861
|
+
result: Optional[Result] = None,
|
862
|
+
event: Optional[Event] = None,
|
862
863
|
) -> Result:
|
863
864
|
"""Execute the Python statement that pass all globals and input params
|
864
865
|
to globals argument on `exec` build-in function.
|
@@ -915,8 +916,8 @@ class PyStage(BaseAsyncStage):
|
|
915
916
|
self,
|
916
917
|
params: DictData,
|
917
918
|
*,
|
918
|
-
result: Result
|
919
|
-
event: Event
|
919
|
+
result: Optional[Result] = None,
|
920
|
+
event: Optional[Event] = None,
|
920
921
|
) -> Result:
|
921
922
|
"""Async execution method for this Bash stage that only logging out to
|
922
923
|
stdout.
|
@@ -1017,8 +1018,8 @@ class CallStage(BaseAsyncStage):
|
|
1017
1018
|
self,
|
1018
1019
|
params: DictData,
|
1019
1020
|
*,
|
1020
|
-
result: Result
|
1021
|
-
event: Event
|
1021
|
+
result: Optional[Result] = None,
|
1022
|
+
event: Optional[Event] = None,
|
1022
1023
|
) -> Result:
|
1023
1024
|
"""Execute this caller function with its argument parameter.
|
1024
1025
|
|
@@ -1107,8 +1108,8 @@ class CallStage(BaseAsyncStage):
|
|
1107
1108
|
self,
|
1108
1109
|
params: DictData,
|
1109
1110
|
*,
|
1110
|
-
result: Result
|
1111
|
-
event: Event
|
1111
|
+
result: Optional[Result] = None,
|
1112
|
+
event: Optional[Event] = None,
|
1112
1113
|
) -> Result:
|
1113
1114
|
"""Async execution method for this Bash stage that only logging out to
|
1114
1115
|
stdout.
|
@@ -1265,8 +1266,8 @@ class TriggerStage(BaseStage):
|
|
1265
1266
|
self,
|
1266
1267
|
params: DictData,
|
1267
1268
|
*,
|
1268
|
-
result: Result
|
1269
|
-
event: Event
|
1269
|
+
result: Optional[Result] = None,
|
1270
|
+
event: Optional[Event] = None,
|
1270
1271
|
) -> Result:
|
1271
1272
|
"""Trigger another workflow execution. It will wait the trigger
|
1272
1273
|
workflow running complete before catching its result.
|
@@ -1297,18 +1298,49 @@ class TriggerStage(BaseStage):
|
|
1297
1298
|
event=event,
|
1298
1299
|
)
|
1299
1300
|
if rs.status == FAILED:
|
1300
|
-
err_msg: str
|
1301
|
+
err_msg: Optional[str] = (
|
1301
1302
|
f" with:\n{msg}"
|
1302
1303
|
if (msg := rs.context.get("errors", {}).get("message"))
|
1303
1304
|
else "."
|
1304
1305
|
)
|
1305
1306
|
raise StageException(
|
1306
|
-
f"Trigger workflow return
|
1307
|
+
f"Trigger workflow return `FAILED` status{err_msg}"
|
1307
1308
|
)
|
1308
1309
|
return rs
|
1309
1310
|
|
1310
1311
|
|
1311
|
-
class
|
1312
|
+
class BaseNestedStage(BaseStage):
|
1313
|
+
"""Base Nested Stage model. This model is use for checking the child stage
|
1314
|
+
is the nested stage or not.
|
1315
|
+
"""
|
1316
|
+
|
1317
|
+
@abstractmethod
|
1318
|
+
def execute(
|
1319
|
+
self,
|
1320
|
+
params: DictData,
|
1321
|
+
*,
|
1322
|
+
result: Optional[Result] = None,
|
1323
|
+
event: Optional[Event] = None,
|
1324
|
+
) -> Result:
|
1325
|
+
"""Execute abstraction method that action something by sub-model class.
|
1326
|
+
This is important method that make this class is able to be the nested
|
1327
|
+
stage.
|
1328
|
+
|
1329
|
+
:param params: (DictData) A parameter data that want to use in this
|
1330
|
+
execution.
|
1331
|
+
:param result: (Result) A result object for keeping context and status
|
1332
|
+
data.
|
1333
|
+
:param event: (Event) An event manager that use to track parent execute
|
1334
|
+
was not force stopped.
|
1335
|
+
|
1336
|
+
:rtype: Result
|
1337
|
+
"""
|
1338
|
+
raise NotImplementedError(
|
1339
|
+
"Nested-Stage should implement `execute` method."
|
1340
|
+
)
|
1341
|
+
|
1342
|
+
|
1343
|
+
class ParallelStage(BaseNestedStage):
|
1312
1344
|
"""Parallel stage executor that execute branch stages with multithreading.
|
1313
1345
|
This stage let you set the fix branches for running child stage inside it on
|
1314
1346
|
multithread pool.
|
@@ -1358,7 +1390,7 @@ class ParallelStage(BaseStage):
|
|
1358
1390
|
params: DictData,
|
1359
1391
|
result: Result,
|
1360
1392
|
*,
|
1361
|
-
event: Event
|
1393
|
+
event: Optional[Event] = None,
|
1362
1394
|
) -> Result:
|
1363
1395
|
"""Execute all stage with specific branch ID.
|
1364
1396
|
|
@@ -1455,8 +1487,8 @@ class ParallelStage(BaseStage):
|
|
1455
1487
|
self,
|
1456
1488
|
params: DictData,
|
1457
1489
|
*,
|
1458
|
-
result: Result
|
1459
|
-
event: Event
|
1490
|
+
result: Optional[Result] = None,
|
1491
|
+
event: Optional[Event] = None,
|
1460
1492
|
) -> Result:
|
1461
1493
|
"""Execute parallel each branch via multi-threading pool.
|
1462
1494
|
|
@@ -1494,7 +1526,7 @@ class ParallelStage(BaseStage):
|
|
1494
1526
|
context: DictData = {}
|
1495
1527
|
status: Status = SUCCESS
|
1496
1528
|
|
1497
|
-
futures: list[Future] =
|
1529
|
+
futures: list[Future] = [
|
1498
1530
|
executor.submit(
|
1499
1531
|
self.execute_branch,
|
1500
1532
|
branch=branch,
|
@@ -1503,26 +1535,21 @@ class ParallelStage(BaseStage):
|
|
1503
1535
|
event=event,
|
1504
1536
|
)
|
1505
1537
|
for branch in self.parallel
|
1506
|
-
|
1538
|
+
]
|
1507
1539
|
|
1508
1540
|
for future in as_completed(futures):
|
1509
1541
|
try:
|
1510
1542
|
future.result()
|
1511
1543
|
except StageException as e:
|
1512
1544
|
status = FAILED
|
1513
|
-
result.trace.error(
|
1514
|
-
f"[STAGE]: Error Handler:||{e.__class__.__name__}:||{e}"
|
1515
|
-
)
|
1516
1545
|
if "errors" in context:
|
1517
1546
|
context["errors"][e.refs] = e.to_dict()
|
1518
1547
|
else:
|
1519
1548
|
context["errors"] = e.to_dict(with_refs=True)
|
1520
|
-
except CancelledError:
|
1521
|
-
pass
|
1522
1549
|
return result.catch(status=status, context=context)
|
1523
1550
|
|
1524
1551
|
|
1525
|
-
class ForEachStage(
|
1552
|
+
class ForEachStage(BaseNestedStage):
|
1526
1553
|
"""For-Each stage executor that execute all stages with each item in the
|
1527
1554
|
foreach list.
|
1528
1555
|
|
@@ -1563,18 +1590,27 @@ class ForEachStage(BaseStage):
|
|
1563
1590
|
"will be sequential mode if this value equal 1."
|
1564
1591
|
),
|
1565
1592
|
)
|
1593
|
+
use_index_as_key: bool = Field(
|
1594
|
+
default=False,
|
1595
|
+
description=(
|
1596
|
+
"A flag for using the loop index as a key instead item value. "
|
1597
|
+
"This flag allow to skip checking duplicate item step."
|
1598
|
+
),
|
1599
|
+
)
|
1566
1600
|
|
1567
1601
|
def execute_item(
|
1568
1602
|
self,
|
1603
|
+
index: int,
|
1569
1604
|
item: StrOrInt,
|
1570
1605
|
params: DictData,
|
1571
1606
|
result: Result,
|
1572
1607
|
*,
|
1573
|
-
event: Event
|
1608
|
+
event: Optional[Event] = None,
|
1574
1609
|
) -> Result:
|
1575
1610
|
"""Execute all nested stage that set on this stage with specific foreach
|
1576
1611
|
item parameter.
|
1577
1612
|
|
1613
|
+
:param index: (int) An index value of foreach loop.
|
1578
1614
|
:param item: (str | int) An item that want to execution.
|
1579
1615
|
:param params: (DictData) A parameter data.
|
1580
1616
|
:param result: (Result) A Result instance for return context and status.
|
@@ -1588,8 +1624,9 @@ class ForEachStage(BaseStage):
|
|
1588
1624
|
:rtype: Result
|
1589
1625
|
"""
|
1590
1626
|
result.trace.debug(f"[STAGE]: Execute Item: {item!r}")
|
1627
|
+
key: StrOrInt = index if self.use_index_as_key else item
|
1591
1628
|
context: DictData = copy.deepcopy(params)
|
1592
|
-
context.update({"item": item})
|
1629
|
+
context.update({"item": item, "loop": index})
|
1593
1630
|
output: DictData = {"item": item, "stages": {}}
|
1594
1631
|
for stage in self.stages:
|
1595
1632
|
|
@@ -1608,14 +1645,14 @@ class ForEachStage(BaseStage):
|
|
1608
1645
|
result.catch(
|
1609
1646
|
status=CANCEL,
|
1610
1647
|
foreach={
|
1611
|
-
|
1648
|
+
key: {
|
1612
1649
|
"item": item,
|
1613
1650
|
"stages": filter_func(output.pop("stages", {})),
|
1614
1651
|
"errors": StageException(error_msg).to_dict(),
|
1615
1652
|
}
|
1616
1653
|
},
|
1617
1654
|
)
|
1618
|
-
raise StageException(error_msg, refs=
|
1655
|
+
raise StageException(error_msg, refs=key)
|
1619
1656
|
|
1620
1657
|
try:
|
1621
1658
|
rs: Result = stage.handler_execute(
|
@@ -1631,14 +1668,14 @@ class ForEachStage(BaseStage):
|
|
1631
1668
|
result.catch(
|
1632
1669
|
status=FAILED,
|
1633
1670
|
foreach={
|
1634
|
-
|
1671
|
+
key: {
|
1635
1672
|
"item": item,
|
1636
1673
|
"stages": filter_func(output.pop("stages", {})),
|
1637
1674
|
"errors": e.to_dict(),
|
1638
1675
|
},
|
1639
1676
|
},
|
1640
1677
|
)
|
1641
|
-
raise StageException(str(e), refs=
|
1678
|
+
raise StageException(str(e), refs=key) from e
|
1642
1679
|
|
1643
1680
|
if rs.status == FAILED:
|
1644
1681
|
error_msg: str = (
|
@@ -1649,19 +1686,19 @@ class ForEachStage(BaseStage):
|
|
1649
1686
|
result.catch(
|
1650
1687
|
status=FAILED,
|
1651
1688
|
foreach={
|
1652
|
-
|
1689
|
+
key: {
|
1653
1690
|
"item": item,
|
1654
1691
|
"stages": filter_func(output.pop("stages", {})),
|
1655
1692
|
"errors": StageException(error_msg).to_dict(),
|
1656
1693
|
},
|
1657
1694
|
},
|
1658
1695
|
)
|
1659
|
-
raise StageException(error_msg, refs=
|
1696
|
+
raise StageException(error_msg, refs=key)
|
1660
1697
|
|
1661
1698
|
return result.catch(
|
1662
1699
|
status=SUCCESS,
|
1663
1700
|
foreach={
|
1664
|
-
|
1701
|
+
key: {
|
1665
1702
|
"item": item,
|
1666
1703
|
"stages": filter_func(output.pop("stages", {})),
|
1667
1704
|
},
|
@@ -1672,8 +1709,8 @@ class ForEachStage(BaseStage):
|
|
1672
1709
|
self,
|
1673
1710
|
params: DictData,
|
1674
1711
|
*,
|
1675
|
-
result: Result
|
1676
|
-
event: Event
|
1712
|
+
result: Optional[Result] = None,
|
1713
|
+
event: Optional[Event] = None,
|
1677
1714
|
) -> Result:
|
1678
1715
|
"""Execute the stages that pass each item form the foreach field.
|
1679
1716
|
|
@@ -1700,6 +1737,11 @@ class ForEachStage(BaseStage):
|
|
1700
1737
|
# [VALIDATE]: Type of the foreach should be `list` type.
|
1701
1738
|
if not isinstance(foreach, list):
|
1702
1739
|
raise TypeError(f"Does not support foreach: {foreach!r}")
|
1740
|
+
elif len(set(foreach)) != len(foreach) and not self.use_index_as_key:
|
1741
|
+
raise ValueError(
|
1742
|
+
"Foreach item should not duplicate. If this stage must to pass "
|
1743
|
+
"duplicate item, it should set `use_index_as_key: true`."
|
1744
|
+
)
|
1703
1745
|
|
1704
1746
|
result.trace.info(f"[STAGE]: Execute Foreach-Stage: {foreach!r}.")
|
1705
1747
|
result.catch(status=WAIT, context={"items": foreach, "foreach": {}})
|
@@ -1721,18 +1763,19 @@ class ForEachStage(BaseStage):
|
|
1721
1763
|
futures: list[Future] = [
|
1722
1764
|
executor.submit(
|
1723
1765
|
self.execute_item,
|
1766
|
+
index=i,
|
1724
1767
|
item=item,
|
1725
1768
|
params=params,
|
1726
1769
|
result=result,
|
1727
1770
|
event=event,
|
1728
1771
|
)
|
1729
|
-
for item in foreach
|
1772
|
+
for i, item in enumerate(foreach, start=0)
|
1730
1773
|
]
|
1731
1774
|
context: DictData = {}
|
1732
1775
|
status: Status = SUCCESS
|
1733
1776
|
|
1734
1777
|
done, not_done = wait(futures, return_when=FIRST_EXCEPTION)
|
1735
|
-
if len(done) != len(futures):
|
1778
|
+
if len(list(done)) != len(futures):
|
1736
1779
|
result.trace.warning(
|
1737
1780
|
"[STAGE]: Set event for stop pending for-each stage."
|
1738
1781
|
)
|
@@ -1741,20 +1784,24 @@ class ForEachStage(BaseStage):
|
|
1741
1784
|
future.cancel()
|
1742
1785
|
time.sleep(0.075)
|
1743
1786
|
|
1744
|
-
nd: str =
|
1787
|
+
nd: str = (
|
1788
|
+
(
|
1789
|
+
f", {len(not_done)} item"
|
1790
|
+
f"{'s' if len(not_done) > 1 else ''} not run!!!"
|
1791
|
+
)
|
1792
|
+
if not_done
|
1793
|
+
else ""
|
1794
|
+
)
|
1745
1795
|
result.trace.debug(
|
1746
1796
|
f"[STAGE]: ... Foreach-Stage set failed event{nd}"
|
1747
1797
|
)
|
1748
|
-
done:
|
1798
|
+
done: Iterator[Future] = as_completed(futures)
|
1749
1799
|
|
1750
1800
|
for future in done:
|
1751
1801
|
try:
|
1752
1802
|
future.result()
|
1753
1803
|
except StageException as e:
|
1754
1804
|
status = FAILED
|
1755
|
-
result.trace.error(
|
1756
|
-
f"[STAGE]: Error Handler:||{e.__class__.__name__}:||{e}"
|
1757
|
-
)
|
1758
1805
|
if "errors" in context:
|
1759
1806
|
context["errors"][e.refs] = e.to_dict()
|
1760
1807
|
else:
|
@@ -1764,7 +1811,7 @@ class ForEachStage(BaseStage):
|
|
1764
1811
|
return result.catch(status=status, context=context)
|
1765
1812
|
|
1766
1813
|
|
1767
|
-
class UntilStage(
|
1814
|
+
class UntilStage(BaseNestedStage):
|
1768
1815
|
"""Until stage executor that will run stages in each loop until it valid
|
1769
1816
|
with stop loop condition.
|
1770
1817
|
|
@@ -1815,7 +1862,7 @@ class UntilStage(BaseStage):
|
|
1815
1862
|
loop: int,
|
1816
1863
|
params: DictData,
|
1817
1864
|
result: Result,
|
1818
|
-
event: Event
|
1865
|
+
event: Optional[Event] = None,
|
1819
1866
|
) -> tuple[Result, T]:
|
1820
1867
|
"""Execute all stage with specific loop and item.
|
1821
1868
|
|
@@ -1928,8 +1975,8 @@ class UntilStage(BaseStage):
|
|
1928
1975
|
self,
|
1929
1976
|
params: DictData,
|
1930
1977
|
*,
|
1931
|
-
result: Result
|
1932
|
-
event: Event
|
1978
|
+
result: Optional[Result] = None,
|
1979
|
+
event: Optional[Event] = None,
|
1933
1980
|
) -> Result:
|
1934
1981
|
"""Execute until loop with checking until condition.
|
1935
1982
|
|
@@ -2015,7 +2062,7 @@ class Match(BaseModel):
|
|
2015
2062
|
)
|
2016
2063
|
|
2017
2064
|
|
2018
|
-
class CaseStage(
|
2065
|
+
class CaseStage(BaseNestedStage):
|
2019
2066
|
"""Case stage executor that execute all stages if the condition was matched.
|
2020
2067
|
|
2021
2068
|
Data Validate:
|
@@ -2066,7 +2113,7 @@ class CaseStage(BaseStage):
|
|
2066
2113
|
params: DictData,
|
2067
2114
|
result: Result,
|
2068
2115
|
*,
|
2069
|
-
event: Event
|
2116
|
+
event: Optional[Event] = None,
|
2070
2117
|
) -> Result:
|
2071
2118
|
"""Execute case.
|
2072
2119
|
|
@@ -2151,8 +2198,8 @@ class CaseStage(BaseStage):
|
|
2151
2198
|
self,
|
2152
2199
|
params: DictData,
|
2153
2200
|
*,
|
2154
|
-
result: Result
|
2155
|
-
event: Event
|
2201
|
+
result: Optional[Result] = None,
|
2202
|
+
event: Optional[Event] = None,
|
2156
2203
|
) -> Result:
|
2157
2204
|
"""Execute case-match condition that pass to the case field.
|
2158
2205
|
|
@@ -2244,8 +2291,8 @@ class RaiseStage(BaseAsyncStage):
|
|
2244
2291
|
self,
|
2245
2292
|
params: DictData,
|
2246
2293
|
*,
|
2247
|
-
result: Result
|
2248
|
-
event: Event
|
2294
|
+
result: Optional[Result] = None,
|
2295
|
+
event: Optional[Event] = None,
|
2249
2296
|
) -> Result:
|
2250
2297
|
"""Raise the StageException object with the message field execution.
|
2251
2298
|
|
@@ -2259,15 +2306,15 @@ class RaiseStage(BaseAsyncStage):
|
|
2259
2306
|
extras=self.extras,
|
2260
2307
|
)
|
2261
2308
|
message: str = param2template(self.message, params, extras=self.extras)
|
2262
|
-
result.trace.info(f"[STAGE]: Execute Raise-Stage: {message
|
2309
|
+
result.trace.info(f"[STAGE]: Execute Raise-Stage: ( {message} )")
|
2263
2310
|
raise StageException(message)
|
2264
2311
|
|
2265
2312
|
async def axecute(
|
2266
2313
|
self,
|
2267
2314
|
params: DictData,
|
2268
2315
|
*,
|
2269
|
-
result: Result
|
2270
|
-
event: Event
|
2316
|
+
result: Optional[Result] = None,
|
2317
|
+
event: Optional[Event] = None,
|
2271
2318
|
) -> Result:
|
2272
2319
|
"""Async execution method for this Empty stage that only logging out to
|
2273
2320
|
stdout.
|
@@ -2286,7 +2333,7 @@ class RaiseStage(BaseAsyncStage):
|
|
2286
2333
|
extras=self.extras,
|
2287
2334
|
)
|
2288
2335
|
message: str = param2template(self.message, params, extras=self.extras)
|
2289
|
-
await result.trace.ainfo(f"[STAGE]: Execute Raise-Stage: {message
|
2336
|
+
await result.trace.ainfo(f"[STAGE]: Execute Raise-Stage: ( {message} )")
|
2290
2337
|
raise StageException(message)
|
2291
2338
|
|
2292
2339
|
|
@@ -2320,7 +2367,7 @@ class DockerStage(BaseStage): # pragma: no cov
|
|
2320
2367
|
env: DictData = Field(
|
2321
2368
|
default_factory=dict,
|
2322
2369
|
description=(
|
2323
|
-
"An environment variable that want pass to Docker container."
|
2370
|
+
"An environment variable that want pass to Docker container."
|
2324
2371
|
),
|
2325
2372
|
)
|
2326
2373
|
volume: DictData = Field(
|
@@ -2338,7 +2385,7 @@ class DockerStage(BaseStage): # pragma: no cov
|
|
2338
2385
|
self,
|
2339
2386
|
params: DictData,
|
2340
2387
|
result: Result,
|
2341
|
-
event: Event
|
2388
|
+
event: Optional[Event] = None,
|
2342
2389
|
) -> Result:
|
2343
2390
|
"""Execute Docker container task.
|
2344
2391
|
|
@@ -2426,8 +2473,8 @@ class DockerStage(BaseStage): # pragma: no cov
|
|
2426
2473
|
self,
|
2427
2474
|
params: DictData,
|
2428
2475
|
*,
|
2429
|
-
result: Result
|
2430
|
-
event: Event
|
2476
|
+
result: Optional[Result] = None,
|
2477
|
+
event: Optional[Event] = None,
|
2431
2478
|
) -> Result:
|
2432
2479
|
"""Execute the Docker image via Python API.
|
2433
2480
|
|
@@ -2471,7 +2518,7 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
2471
2518
|
py: str,
|
2472
2519
|
values: DictData,
|
2473
2520
|
deps: list[str],
|
2474
|
-
run_id: str
|
2521
|
+
run_id: Optional[str] = None,
|
2475
2522
|
) -> Iterator[str]:
|
2476
2523
|
"""Create the .py file with an input Python string statement.
|
2477
2524
|
|
@@ -2479,7 +2526,7 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
2479
2526
|
:param values: A variable that want to set before running this
|
2480
2527
|
:param deps: An additional Python dependencies that want install before
|
2481
2528
|
run this python stage.
|
2482
|
-
:param run_id: (str
|
2529
|
+
:param run_id: (Optional[str]) A running ID of this stage execution.
|
2483
2530
|
"""
|
2484
2531
|
run_id: str = run_id or uuid.uuid4()
|
2485
2532
|
f_name: str = f"{run_id}.py"
|
@@ -2518,8 +2565,8 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
2518
2565
|
self,
|
2519
2566
|
params: DictData,
|
2520
2567
|
*,
|
2521
|
-
result: Result
|
2522
|
-
event: Event
|
2568
|
+
result: Optional[Result] = None,
|
2569
|
+
event: Optional[Event] = None,
|
2523
2570
|
) -> Result:
|
2524
2571
|
"""Execute the Python statement via Python virtual environment.
|
2525
2572
|
|