ddeutil-workflow 0.0.85__py3-none-any.whl → 0.0.86__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/api/routes/job.py +3 -2
- ddeutil/workflow/conf.py +5 -3
- ddeutil/workflow/errors.py +3 -0
- ddeutil/workflow/job.py +66 -42
- ddeutil/workflow/result.py +46 -55
- ddeutil/workflow/stages.py +157 -165
- ddeutil/workflow/traces.py +147 -89
- ddeutil/workflow/workflow.py +300 -360
- {ddeutil_workflow-0.0.85.dist-info → ddeutil_workflow-0.0.86.dist-info}/METADATA +2 -2
- {ddeutil_workflow-0.0.85.dist-info → ddeutil_workflow-0.0.86.dist-info}/RECORD +15 -15
- {ddeutil_workflow-0.0.85.dist-info → ddeutil_workflow-0.0.86.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.85.dist-info → ddeutil_workflow-0.0.86.dist-info}/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.85.dist-info → ddeutil_workflow-0.0.86.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.85.dist-info → ddeutil_workflow-0.0.86.dist-info}/top_level.txt +0 -0
ddeutil/workflow/stages.py
CHANGED
@@ -122,6 +122,7 @@ from .utils import (
|
|
122
122
|
extract_id,
|
123
123
|
filter_func,
|
124
124
|
gen_id,
|
125
|
+
get_dt_now,
|
125
126
|
make_exec,
|
126
127
|
to_train,
|
127
128
|
)
|
@@ -133,9 +134,9 @@ DictOrModel = Union[DictData, BaseModel]
|
|
133
134
|
class BaseStage(BaseModel, ABC):
|
134
135
|
"""Abstract base class for all stage implementations.
|
135
136
|
|
136
|
-
|
137
|
-
It defines the common interface and metadata fields that all stages
|
138
|
-
implement, ensuring consistent behavior across different stage types.
|
137
|
+
BaseStage provides the foundation for all stage types in the workflow
|
138
|
+
system. It defines the common interface and metadata fields that all stages
|
139
|
+
must implement, ensuring consistent behavior across different stage types.
|
139
140
|
|
140
141
|
This abstract class handles core stage functionality including:
|
141
142
|
- Stage identification and naming
|
@@ -143,7 +144,7 @@ class BaseStage(BaseModel, ABC):
|
|
143
144
|
- Output management and templating
|
144
145
|
- Execution lifecycle management
|
145
146
|
|
146
|
-
|
147
|
+
Custom stages should inherit from this class and implement the abstract
|
147
148
|
`process()` method to define their specific execution behavior.
|
148
149
|
|
149
150
|
Attributes:
|
@@ -189,7 +190,7 @@ class BaseStage(BaseModel, ABC):
|
|
189
190
|
default=None,
|
190
191
|
description=(
|
191
192
|
"A stage condition statement to allow stage executable. This field "
|
192
|
-
"
|
193
|
+
"alias with `if` key."
|
193
194
|
),
|
194
195
|
alias="if",
|
195
196
|
)
|
@@ -260,6 +261,13 @@ class BaseStage(BaseModel, ABC):
|
|
260
261
|
"""Process abstraction method that action something by sub-model class.
|
261
262
|
This is important method that make this class is able to be the stage.
|
262
263
|
|
264
|
+
For process method, it designs to break process with any status by
|
265
|
+
raise it with a specific exception class.
|
266
|
+
|
267
|
+
- StageError -> FAILED
|
268
|
+
- StageSkipError -> SKIP
|
269
|
+
- StageCancelError -> CANCEL
|
270
|
+
|
263
271
|
Args:
|
264
272
|
params (DictData): A parameter data that want to use in this
|
265
273
|
execution.
|
@@ -321,13 +329,16 @@ class BaseStage(BaseModel, ABC):
|
|
321
329
|
parent_run_id, run_id = extract_id(
|
322
330
|
self.iden, run_id=run_id, extras=self.extras
|
323
331
|
)
|
324
|
-
context: DictData = {
|
332
|
+
context: DictData = {
|
333
|
+
"status": WAIT,
|
334
|
+
"info": {"exec_start": get_dt_now()},
|
335
|
+
}
|
325
336
|
trace: Trace = get_trace(
|
326
337
|
run_id, parent_run_id=parent_run_id, extras=self.extras
|
327
338
|
)
|
328
339
|
try:
|
329
340
|
_id: str = (
|
330
|
-
f" with ID: {
|
341
|
+
f" with ID: {self.pass_template(self.id, params=params)!r}"
|
331
342
|
if self.id
|
332
343
|
else ""
|
333
344
|
)
|
@@ -348,84 +359,73 @@ class BaseStage(BaseModel, ABC):
|
|
348
359
|
|
349
360
|
# NOTE: Start call wrapped execution method that will use custom
|
350
361
|
# execution before the real execution from inherit stage model.
|
351
|
-
|
362
|
+
result: Result = self._execute(
|
352
363
|
params,
|
353
|
-
run_id=run_id,
|
354
364
|
context=context,
|
355
|
-
|
365
|
+
trace=trace,
|
356
366
|
event=event,
|
357
367
|
)
|
358
|
-
if
|
368
|
+
if result.status == WAIT: # pragma: no cov
|
359
369
|
raise StageError(
|
360
370
|
"Status from execution should not return waiting status."
|
361
371
|
)
|
362
|
-
return
|
363
|
-
{"execution_time": time.monotonic() - ts}
|
364
|
-
)
|
372
|
+
return result
|
365
373
|
|
366
374
|
# NOTE: Catch this error in this line because the execution can raise
|
367
375
|
# this exception class at other location.
|
368
|
-
except
|
369
|
-
StageSkipError,
|
370
|
-
StageNestedSkipError,
|
371
|
-
StageNestedError,
|
372
|
-
StageError,
|
373
|
-
) as e: # pragma: no cov
|
376
|
+
except StageError as e: # pragma: no cov
|
374
377
|
updated: Optional[DictData] = {"errors": e.to_dict()}
|
375
378
|
if isinstance(e, StageNestedError):
|
376
|
-
trace.error(f"[STAGE]: Nested: {e}")
|
379
|
+
trace.error(f"[STAGE]: ⚠️ Nested: {e}")
|
377
380
|
elif isinstance(e, (StageSkipError, StageNestedSkipError)):
|
378
|
-
trace.error(f"[STAGE]: ⏭️ Skip: {e}")
|
381
|
+
trace.error(f"[STAGE]: ⏭️ Skip: {e}", module="stage")
|
379
382
|
updated = None
|
380
383
|
elif e.allow_traceback:
|
381
384
|
trace.error(
|
382
|
-
f"[STAGE]: Stage Failed:||🚨 {traceback.format_exc()}||"
|
385
|
+
f"[STAGE]: 📢 Stage Failed:||🚨 {traceback.format_exc()}||"
|
383
386
|
)
|
384
387
|
else:
|
385
388
|
trace.error(
|
386
389
|
f"[STAGE]: 🤫 Stage Failed with disable traceback:||{e}"
|
387
390
|
)
|
388
391
|
st: Status = get_status_from_error(e)
|
389
|
-
return Result(
|
390
|
-
run_id=run_id,
|
391
|
-
parent_run_id=parent_run_id,
|
392
|
+
return Result.from_trace(trace).catch(
|
392
393
|
status=st,
|
393
394
|
context=catch(context, status=st, updated=updated),
|
394
|
-
info={"execution_time": time.monotonic() - ts},
|
395
|
-
extras=self.extras,
|
396
395
|
)
|
397
396
|
except Exception as e:
|
398
397
|
trace.error(
|
399
|
-
f"
|
398
|
+
f"💥 Error Failed:||🚨 {traceback.format_exc()}||",
|
399
|
+
module="stage",
|
400
400
|
)
|
401
|
-
return Result(
|
402
|
-
run_id=run_id,
|
403
|
-
parent_run_id=parent_run_id,
|
401
|
+
return Result.from_trace(trace).catch(
|
404
402
|
status=FAILED,
|
405
403
|
context=catch(
|
406
404
|
context, status=FAILED, updated={"errors": to_dict(e)}
|
407
405
|
),
|
408
|
-
info={"execution_time": time.monotonic() - ts},
|
409
|
-
extras=self.extras,
|
410
406
|
)
|
411
407
|
finally:
|
412
|
-
|
408
|
+
context["info"].update(
|
409
|
+
{
|
410
|
+
"exec_end": get_dt_now(),
|
411
|
+
"exec_latency": round(time.monotonic() - ts, 6),
|
412
|
+
}
|
413
|
+
)
|
414
|
+
trace.debug("End Handler stage execution.", module="stage")
|
413
415
|
|
414
416
|
def _execute(
|
415
417
|
self,
|
416
418
|
params: DictData,
|
417
|
-
run_id: str,
|
418
419
|
context: DictData,
|
419
|
-
|
420
|
+
trace: Trace,
|
420
421
|
event: Optional[Event] = None,
|
421
422
|
) -> Result:
|
422
423
|
"""Wrapped the process method before returning to handler execution.
|
423
424
|
|
424
425
|
Args:
|
425
426
|
params: A parameter data that want to use in this execution.
|
426
|
-
run_id (str):
|
427
427
|
context:
|
428
|
-
|
428
|
+
trace (Trace):
|
429
429
|
event: An event manager that use to track parent process
|
430
430
|
was not force stopped.
|
431
431
|
|
@@ -435,9 +435,9 @@ class BaseStage(BaseModel, ABC):
|
|
435
435
|
catch(context, status=WAIT)
|
436
436
|
return self.process(
|
437
437
|
params,
|
438
|
-
run_id=run_id,
|
438
|
+
run_id=trace.run_id,
|
439
439
|
context=context,
|
440
|
-
parent_run_id=parent_run_id,
|
440
|
+
parent_run_id=trace.parent_run_id,
|
441
441
|
event=event,
|
442
442
|
)
|
443
443
|
|
@@ -454,7 +454,7 @@ class BaseStage(BaseModel, ABC):
|
|
454
454
|
For example of setting output method, If you receive process output
|
455
455
|
and want to set on the `to` like;
|
456
456
|
|
457
|
-
... (i) output: {'foo': 'bar', '
|
457
|
+
... (i) output: {'foo': 'bar', 'status': SUCCESS, 'info': {}}
|
458
458
|
... (ii) to: {'stages': {}}
|
459
459
|
|
460
460
|
The received context in the `to` argument will be;
|
@@ -463,7 +463,8 @@ class BaseStage(BaseModel, ABC):
|
|
463
463
|
'stages': {
|
464
464
|
'<stage-id>': {
|
465
465
|
'outputs': {'foo': 'bar'},
|
466
|
-
'
|
466
|
+
'status': SUCCESS,
|
467
|
+
'info': {},
|
467
468
|
}
|
468
469
|
}
|
469
470
|
}
|
@@ -504,8 +505,13 @@ class BaseStage(BaseModel, ABC):
|
|
504
505
|
status: dict[str, Status] = (
|
505
506
|
{"status": output.pop("status")} if "status" in output else {}
|
506
507
|
)
|
508
|
+
info: DictData = (
|
509
|
+
{"info": output.pop("info")} if "info" in output else {}
|
510
|
+
)
|
507
511
|
kwargs: DictData = kwargs or {}
|
508
|
-
to["stages"][_id] =
|
512
|
+
to["stages"][_id] = (
|
513
|
+
{"outputs": output} | errors | status | info | kwargs
|
514
|
+
)
|
509
515
|
return to
|
510
516
|
|
511
517
|
def get_outputs(self, output: DictData) -> DictData:
|
@@ -533,15 +539,18 @@ class BaseStage(BaseModel, ABC):
|
|
533
539
|
"""Return true if condition of this stage do not correct. This process
|
534
540
|
use build-in eval function to execute the if-condition.
|
535
541
|
|
536
|
-
:
|
537
|
-
|
542
|
+
Args:
|
543
|
+
params (DictData): A parameters that want to pass to condition
|
544
|
+
template.
|
538
545
|
|
539
|
-
:
|
540
|
-
|
541
|
-
|
542
|
-
|
546
|
+
Raises:
|
547
|
+
StageError: When it has any error raise from the eval
|
548
|
+
condition statement.
|
549
|
+
StageError: When return type of the eval condition statement
|
550
|
+
does not return with boolean type.
|
543
551
|
|
544
|
-
:
|
552
|
+
Returns:
|
553
|
+
bool: True if the condition is valid with the current parameters.
|
545
554
|
"""
|
546
555
|
# NOTE: Support for condition value is empty string.
|
547
556
|
if not self.condition:
|
@@ -569,9 +578,11 @@ class BaseStage(BaseModel, ABC):
|
|
569
578
|
"""Generate stage ID that dynamic use stage's name if it ID does not
|
570
579
|
set.
|
571
580
|
|
572
|
-
:
|
581
|
+
Args:
|
582
|
+
params (DictData): A parameter or context data.
|
573
583
|
|
574
|
-
:
|
584
|
+
Returns:
|
585
|
+
str: An ID that already generated from id or name fields.
|
575
586
|
"""
|
576
587
|
return (
|
577
588
|
param2template(self.id, params=params, extras=self.extras)
|
@@ -779,15 +790,19 @@ class BaseAsyncStage(BaseStage, ABC):
|
|
779
790
|
Result: The execution result with status and context data.
|
780
791
|
"""
|
781
792
|
ts: float = time.monotonic()
|
782
|
-
parent_run_id
|
783
|
-
|
784
|
-
|
793
|
+
parent_run_id, run_id = extract_id(
|
794
|
+
self.iden, run_id=run_id, extras=self.extras
|
795
|
+
)
|
796
|
+
context: DictData = {
|
797
|
+
"status": WAIT,
|
798
|
+
"info": {"exec_start": get_dt_now()},
|
799
|
+
}
|
785
800
|
trace: Trace = get_trace(
|
786
801
|
run_id, parent_run_id=parent_run_id, extras=self.extras
|
787
802
|
)
|
788
803
|
try:
|
789
804
|
_id: str = (
|
790
|
-
f" with ID: {
|
805
|
+
f" with ID: {self.pass_template(self.id, params=params)!r}"
|
791
806
|
if self.id
|
792
807
|
else ""
|
793
808
|
)
|
@@ -808,67 +823,59 @@ class BaseAsyncStage(BaseStage, ABC):
|
|
808
823
|
|
809
824
|
# NOTE: Start call wrapped execution method that will use custom
|
810
825
|
# execution before the real execution from inherit stage model.
|
811
|
-
|
826
|
+
result: Result = await self._axecute(
|
812
827
|
params,
|
813
828
|
run_id=run_id,
|
814
829
|
context=context,
|
815
830
|
parent_run_id=parent_run_id,
|
816
831
|
event=event,
|
817
832
|
)
|
818
|
-
if
|
833
|
+
if result.status == WAIT: # pragma: no cov
|
819
834
|
raise StageError(
|
820
835
|
"Status from execution should not return waiting status."
|
821
836
|
)
|
822
|
-
return
|
837
|
+
return result
|
823
838
|
|
824
839
|
# NOTE: Catch this error in this line because the execution can raise
|
825
840
|
# this exception class at other location.
|
826
|
-
except
|
827
|
-
|
828
|
-
StageNestedSkipError,
|
829
|
-
StageNestedError,
|
830
|
-
StageError,
|
831
|
-
) as e: # pragma: no cov
|
841
|
+
except StageError as e: # pragma: no cov
|
842
|
+
updated: Optional[DictData] = {"errors": e.to_dict()}
|
832
843
|
if isinstance(e, StageNestedError):
|
833
|
-
await trace.
|
844
|
+
await trace.aerror(f"[STAGE]: ⚠️ Nested: {e}")
|
834
845
|
elif isinstance(e, (StageSkipError, StageNestedSkipError)):
|
835
|
-
await trace.
|
846
|
+
await trace.aerror(f"[STAGE]: ⏭️ Skip: {e}")
|
847
|
+
updated = None
|
848
|
+
elif e.allow_traceback:
|
849
|
+
await trace.aerror(
|
850
|
+
f"[STAGE]: 📢 Stage Failed:||🚨 {traceback.format_exc()}||"
|
851
|
+
)
|
836
852
|
else:
|
837
|
-
await trace.
|
838
|
-
f"[STAGE]: Stage Failed
|
853
|
+
await trace.aerror(
|
854
|
+
f"[STAGE]: 🤫 Stage Failed with disable traceback:||{e}"
|
839
855
|
)
|
840
856
|
st: Status = get_status_from_error(e)
|
841
|
-
return Result(
|
842
|
-
run_id=run_id,
|
843
|
-
parent_run_id=parent_run_id,
|
857
|
+
return Result.from_trace(trace).catch(
|
844
858
|
status=st,
|
845
|
-
context=catch(
|
846
|
-
context,
|
847
|
-
status=st,
|
848
|
-
updated=(
|
849
|
-
None
|
850
|
-
if isinstance(e, (StageSkipError, StageNestedSkipError))
|
851
|
-
else {"errors": e.to_dict()}
|
852
|
-
),
|
853
|
-
),
|
854
|
-
info={"execution_time": time.monotonic() - ts},
|
855
|
-
extras=self.extras,
|
859
|
+
context=catch(context, status=st, updated=updated),
|
856
860
|
)
|
857
861
|
except Exception as e:
|
858
862
|
await trace.aerror(
|
859
|
-
f"
|
863
|
+
f"💥 Error Failed:||🚨 {traceback.format_exc()}||",
|
864
|
+
module="stage",
|
860
865
|
)
|
861
|
-
return Result(
|
862
|
-
run_id=run_id,
|
863
|
-
parent_run_id=parent_run_id,
|
866
|
+
return Result.from_trace(trace).catch(
|
864
867
|
status=FAILED,
|
865
868
|
context=catch(
|
866
869
|
context, status=FAILED, updated={"errors": to_dict(e)}
|
867
870
|
),
|
868
|
-
info={"execution_time": time.monotonic() - ts},
|
869
|
-
extras=self.extras,
|
870
871
|
)
|
871
872
|
finally:
|
873
|
+
context["info"].update(
|
874
|
+
{
|
875
|
+
"exec_end": get_dt_now(),
|
876
|
+
"exec_latency": time.monotonic() - ts,
|
877
|
+
}
|
878
|
+
)
|
872
879
|
trace.debug("[STAGE]: End Handler stage process.")
|
873
880
|
|
874
881
|
async def _axecute(
|
@@ -905,6 +912,7 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
905
912
|
`StageRetryError`.
|
906
913
|
"""
|
907
914
|
|
915
|
+
action_stage: ClassVar[bool] = True
|
908
916
|
retry: int = Field(
|
909
917
|
default=0,
|
910
918
|
ge=0,
|
@@ -918,9 +926,8 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
918
926
|
def _execute(
|
919
927
|
self,
|
920
928
|
params: DictData,
|
921
|
-
run_id: str,
|
922
929
|
context: DictData,
|
923
|
-
|
930
|
+
trace: Trace,
|
924
931
|
event: Optional[Event] = None,
|
925
932
|
) -> Result:
|
926
933
|
"""Wrapped the execute method with retry strategy before returning to
|
@@ -938,9 +945,6 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
938
945
|
current_retry: int = 0
|
939
946
|
exception: Exception
|
940
947
|
catch(context, status=WAIT)
|
941
|
-
trace: Trace = get_trace(
|
942
|
-
run_id, parent_run_id=parent_run_id, extras=self.extras
|
943
|
-
)
|
944
948
|
# NOTE: First execution for not pass to retry step if it passes.
|
945
949
|
try:
|
946
950
|
if (
|
@@ -949,16 +953,16 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
949
953
|
):
|
950
954
|
return self.dryrun(
|
951
955
|
params | {"retry": current_retry},
|
952
|
-
run_id=run_id,
|
956
|
+
run_id=trace.run_id,
|
953
957
|
context=context,
|
954
|
-
parent_run_id=parent_run_id,
|
958
|
+
parent_run_id=trace.parent_run_id,
|
955
959
|
event=event,
|
956
960
|
)
|
957
961
|
return self.process(
|
958
962
|
params | {"retry": current_retry},
|
959
|
-
run_id=run_id,
|
963
|
+
run_id=trace.run_id,
|
960
964
|
context=context,
|
961
|
-
parent_run_id=parent_run_id,
|
965
|
+
parent_run_id=trace.parent_run_id,
|
962
966
|
event=event,
|
963
967
|
)
|
964
968
|
except (
|
@@ -970,13 +974,11 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
970
974
|
trace.debug("[STAGE]: process raise skip or cancel error.")
|
971
975
|
raise
|
972
976
|
except Exception as e:
|
977
|
+
if self.retry == 0:
|
978
|
+
raise
|
979
|
+
|
973
980
|
current_retry += 1
|
974
981
|
exception = e
|
975
|
-
finally:
|
976
|
-
trace.debug("[STAGE]: Failed at the first execution.")
|
977
|
-
|
978
|
-
if self.retry == 0:
|
979
|
-
raise exception
|
980
982
|
|
981
983
|
trace.warning(
|
982
984
|
f"[STAGE]: Retry count: {current_retry} ... "
|
@@ -996,16 +998,16 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
996
998
|
):
|
997
999
|
return self.dryrun(
|
998
1000
|
params | {"retry": current_retry},
|
999
|
-
run_id=run_id,
|
1001
|
+
run_id=trace.run_id,
|
1000
1002
|
context=context,
|
1001
|
-
parent_run_id=parent_run_id,
|
1003
|
+
parent_run_id=trace.parent_run_id,
|
1002
1004
|
event=event,
|
1003
1005
|
)
|
1004
1006
|
return self.process(
|
1005
1007
|
params | {"retry": current_retry},
|
1006
|
-
run_id=run_id,
|
1008
|
+
run_id=trace.run_id,
|
1007
1009
|
context=context,
|
1008
|
-
parent_run_id=parent_run_id,
|
1010
|
+
parent_run_id=trace.parent_run_id,
|
1009
1011
|
event=event,
|
1010
1012
|
)
|
1011
1013
|
except (
|
@@ -1086,13 +1088,11 @@ class BaseRetryStage(BaseAsyncStage, ABC): # pragma: no cov
|
|
1086
1088
|
await trace.adebug("[STAGE]: process raise skip or cancel error.")
|
1087
1089
|
raise
|
1088
1090
|
except Exception as e:
|
1091
|
+
if self.retry == 0:
|
1092
|
+
raise
|
1093
|
+
|
1089
1094
|
current_retry += 1
|
1090
1095
|
exception = e
|
1091
|
-
finally:
|
1092
|
-
await trace.adebug("[STAGE]: Failed at the first execution.")
|
1093
|
-
|
1094
|
-
if self.retry == 0:
|
1095
|
-
raise exception
|
1096
1096
|
|
1097
1097
|
await trace.awarning(
|
1098
1098
|
f"[STAGE]: Retry count: {current_retry} ... "
|
@@ -1172,6 +1172,7 @@ class EmptyStage(BaseAsyncStage):
|
|
1172
1172
|
... })
|
1173
1173
|
"""
|
1174
1174
|
|
1175
|
+
action_stage: ClassVar[bool] = True
|
1175
1176
|
echo: StrOrNone = Field(
|
1176
1177
|
default=None,
|
1177
1178
|
description=(
|
@@ -1205,13 +1206,14 @@ class EmptyStage(BaseAsyncStage):
|
|
1205
1206
|
without calling logging function.
|
1206
1207
|
|
1207
1208
|
Args:
|
1208
|
-
params: A parameter data that want to use in this
|
1209
|
+
params (DictData): A parameter data that want to use in this
|
1209
1210
|
execution.
|
1210
|
-
run_id: A running stage ID.
|
1211
|
-
context: A context data
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1211
|
+
run_id (str): A running stage ID.
|
1212
|
+
context (DictData): A context data that was passed from handler
|
1213
|
+
method.
|
1214
|
+
parent_run_id (str, default None): A parent running ID.
|
1215
|
+
event (Event, default None): An event manager that use to track
|
1216
|
+
parent process was not force stopped.
|
1215
1217
|
|
1216
1218
|
Raises:
|
1217
1219
|
StageCancelError: If event was set before start process.
|
@@ -1223,9 +1225,7 @@ class EmptyStage(BaseAsyncStage):
|
|
1223
1225
|
run_id, parent_run_id=parent_run_id, extras=self.extras
|
1224
1226
|
)
|
1225
1227
|
message: str = (
|
1226
|
-
|
1227
|
-
dedent(self.echo.strip("\n")), params, extras=self.extras
|
1228
|
-
)
|
1228
|
+
self.pass_template(dedent(self.echo.strip("\n")), params=params)
|
1229
1229
|
if self.echo
|
1230
1230
|
else "..."
|
1231
1231
|
)
|
@@ -1238,12 +1238,8 @@ class EmptyStage(BaseAsyncStage):
|
|
1238
1238
|
if self.sleep > 5:
|
1239
1239
|
trace.info(f"[STAGE]: Sleep ... ({self.sleep} sec)")
|
1240
1240
|
time.sleep(self.sleep)
|
1241
|
-
return Result(
|
1242
|
-
|
1243
|
-
parent_run_id=parent_run_id,
|
1244
|
-
status=SUCCESS,
|
1245
|
-
context=catch(context=context, status=SUCCESS),
|
1246
|
-
extras=self.extras,
|
1241
|
+
return Result.from_trace(trace).catch(
|
1242
|
+
status=SUCCESS, context=catch(context=context, status=SUCCESS)
|
1247
1243
|
)
|
1248
1244
|
|
1249
1245
|
async def async_process(
|
@@ -1259,13 +1255,14 @@ class EmptyStage(BaseAsyncStage):
|
|
1259
1255
|
stdout.
|
1260
1256
|
|
1261
1257
|
Args:
|
1262
|
-
params: A parameter data that want to use in this
|
1258
|
+
params (DictData): A parameter data that want to use in this
|
1263
1259
|
execution.
|
1264
|
-
run_id: A running stage ID.
|
1265
|
-
context: A context data
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1260
|
+
run_id (str): A running stage ID.
|
1261
|
+
context (DictData): A context data that was passed from handler
|
1262
|
+
method.
|
1263
|
+
parent_run_id (str, default None): A parent running ID.
|
1264
|
+
event (Event, default None): An event manager that use to track
|
1265
|
+
parent process was not force stopped.
|
1269
1266
|
|
1270
1267
|
Raises:
|
1271
1268
|
StageCancelError: If event was set before start process.
|
@@ -1277,9 +1274,7 @@ class EmptyStage(BaseAsyncStage):
|
|
1277
1274
|
run_id, parent_run_id=parent_run_id, extras=self.extras
|
1278
1275
|
)
|
1279
1276
|
message: str = (
|
1280
|
-
|
1281
|
-
dedent(self.echo.strip("\n")), params, extras=self.extras
|
1282
|
-
)
|
1277
|
+
self.pass_template(dedent(self.echo.strip("\n")), params=params)
|
1283
1278
|
if self.echo
|
1284
1279
|
else "..."
|
1285
1280
|
)
|
@@ -1292,12 +1287,8 @@ class EmptyStage(BaseAsyncStage):
|
|
1292
1287
|
if self.sleep > 5:
|
1293
1288
|
await trace.ainfo(f"[STAGE]: Sleep ... ({self.sleep} sec)")
|
1294
1289
|
await asyncio.sleep(self.sleep)
|
1295
|
-
return Result(
|
1296
|
-
|
1297
|
-
parent_run_id=parent_run_id,
|
1298
|
-
status=SUCCESS,
|
1299
|
-
context=catch(context=context, status=SUCCESS),
|
1300
|
-
extras=self.extras,
|
1290
|
+
return Result.from_trace(trace).catch(
|
1291
|
+
status=SUCCESS, context=catch(context=context, status=SUCCESS)
|
1301
1292
|
)
|
1302
1293
|
|
1303
1294
|
|
@@ -1322,7 +1313,6 @@ class BashStage(BaseRetryStage):
|
|
1322
1313
|
... })
|
1323
1314
|
"""
|
1324
1315
|
|
1325
|
-
action_stage: ClassVar[bool] = True
|
1326
1316
|
bash: str = Field(
|
1327
1317
|
description=(
|
1328
1318
|
"A bash statement that want to execute via Python subprocess."
|
@@ -1370,10 +1360,11 @@ class BashStage(BaseRetryStage):
|
|
1370
1360
|
# NOTE: Make this .sh file able to executable.
|
1371
1361
|
make_exec(f"./{f_name}")
|
1372
1362
|
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1363
|
+
try:
|
1364
|
+
yield f_shebang, f_name
|
1365
|
+
finally:
|
1366
|
+
# Note: Remove .sh file that use to run bash.
|
1367
|
+
Path(f"./{f_name}").unlink()
|
1377
1368
|
|
1378
1369
|
@contextlib.contextmanager
|
1379
1370
|
def make_sh_file(
|
@@ -1408,10 +1399,11 @@ class BashStage(BaseRetryStage):
|
|
1408
1399
|
# NOTE: Make this .sh file able to executable.
|
1409
1400
|
make_exec(f"./{f_name}")
|
1410
1401
|
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1402
|
+
try:
|
1403
|
+
yield f_shebang, f_name
|
1404
|
+
finally:
|
1405
|
+
# Note: Remove .sh file that use to run bash.
|
1406
|
+
Path(f"./{f_name}").unlink()
|
1415
1407
|
|
1416
1408
|
@staticmethod
|
1417
1409
|
def prepare_std(value: str) -> Optional[str]:
|
@@ -1592,7 +1584,6 @@ class PyStage(BaseRetryStage):
|
|
1592
1584
|
... })
|
1593
1585
|
"""
|
1594
1586
|
|
1595
|
-
action_stage: ClassVar[bool] = True
|
1596
1587
|
run: str = Field(
|
1597
1588
|
description="A Python string statement that want to run with `exec`.",
|
1598
1589
|
)
|
@@ -1622,6 +1613,7 @@ class PyStage(BaseRetryStage):
|
|
1622
1613
|
or (value.startswith("__") and value.endswith("__"))
|
1623
1614
|
or ismodule(values[value])
|
1624
1615
|
or isclass(values[value])
|
1616
|
+
or value in ("trace",)
|
1625
1617
|
):
|
1626
1618
|
continue
|
1627
1619
|
|
@@ -1831,7 +1823,6 @@ class CallStage(BaseRetryStage):
|
|
1831
1823
|
... })
|
1832
1824
|
"""
|
1833
1825
|
|
1834
|
-
action_stage: ClassVar[bool] = True
|
1835
1826
|
uses: str = Field(
|
1836
1827
|
description=(
|
1837
1828
|
"A caller function with registry importer syntax that use to load "
|
@@ -2337,10 +2328,10 @@ class TriggerStage(BaseRetryStage):
|
|
2337
2328
|
if (msg := result.context.get("errors", {}).get("message"))
|
2338
2329
|
else "."
|
2339
2330
|
)
|
2340
|
-
|
2341
|
-
f"Trigger workflow was failed{err_msg}",
|
2331
|
+
raise StageError(
|
2332
|
+
f"Trigger workflow was failed{err_msg}",
|
2333
|
+
allow_traceback=False,
|
2342
2334
|
)
|
2343
|
-
raise err
|
2344
2335
|
elif result.status == CANCEL:
|
2345
2336
|
raise StageCancelError("Trigger workflow was cancel.")
|
2346
2337
|
elif result.status == SKIP:
|
@@ -2405,8 +2396,8 @@ class BaseNestedStage(BaseAsyncStage, ABC):
|
|
2405
2396
|
execute func.
|
2406
2397
|
|
2407
2398
|
Args:
|
2408
|
-
context
|
2409
|
-
error
|
2399
|
+
context (DictData): A context data.
|
2400
|
+
error (StageError): A stage exception object.
|
2410
2401
|
"""
|
2411
2402
|
if "errors" in context:
|
2412
2403
|
context["errors"][error.refs] = error.to_dict()
|
@@ -2425,13 +2416,14 @@ class BaseNestedStage(BaseAsyncStage, ABC):
|
|
2425
2416
|
"""Async process for nested-stage do not implement yet.
|
2426
2417
|
|
2427
2418
|
Args:
|
2428
|
-
params: A parameter data that want to use in this
|
2419
|
+
params (DictData): A parameter data that want to use in this
|
2429
2420
|
execution.
|
2430
|
-
run_id: A running stage ID.
|
2431
|
-
context: A context data
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2421
|
+
run_id (str): A running stage ID.
|
2422
|
+
context (DictData): A context data that was passed from handler
|
2423
|
+
method.
|
2424
|
+
parent_run_id (str, default None): A parent running ID.
|
2425
|
+
event (Event, default None): An event manager that use to track
|
2426
|
+
parent process was not force stopped.
|
2435
2427
|
|
2436
2428
|
Returns:
|
2437
2429
|
Result: The execution result with status and context data.
|