ddeutil-workflow 0.0.40__py3-none-any.whl → 0.0.41__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 +21 -25
- ddeutil/workflow/api/api.py +1 -1
- ddeutil/workflow/api/routes/logs.py +1 -2
- ddeutil/workflow/api/routes/workflows.py +1 -1
- ddeutil/workflow/conf.py +11 -1
- ddeutil/workflow/job.py +55 -4
- ddeutil/workflow/logs.py +334 -72
- ddeutil/workflow/params.py +1 -0
- ddeutil/workflow/result.py +6 -15
- ddeutil/workflow/{templates.py → reusables.py} +195 -9
- ddeutil/workflow/scheduler.py +1 -1
- ddeutil/workflow/stages.py +188 -24
- ddeutil/workflow/utils.py +11 -0
- ddeutil/workflow/workflow.py +16 -8
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/METADATA +7 -1
- ddeutil_workflow-0.0.41.dist-info/RECORD +31 -0
- ddeutil/workflow/audit.py +0 -257
- ddeutil/workflow/caller.py +0 -179
- ddeutil_workflow-0.0.40.dist-info/RECORD +0 -33
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.40.dist-info → ddeutil_workflow-0.0.41.dist-info}/top_level.txt +0 -0
ddeutil/workflow/stages.py
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# Licensed under the MIT License. See LICENSE in the project root for
|
4
4
|
# license information.
|
5
5
|
# ------------------------------------------------------------------------------
|
6
|
+
# [x] Use config
|
6
7
|
"""Stage Model that use for getting stage data template from the Job Model.
|
7
8
|
The stage handle the minimize task that run in some thread (same thread at
|
8
9
|
its job owner) that mean it is the lowest executor of a workflow that can
|
@@ -41,6 +42,7 @@ from inspect import Parameter
|
|
41
42
|
from pathlib import Path
|
42
43
|
from subprocess import CompletedProcess
|
43
44
|
from textwrap import dedent
|
45
|
+
from threading import Event
|
44
46
|
from typing import Annotated, Optional, Union
|
45
47
|
|
46
48
|
from pydantic import BaseModel, Field
|
@@ -48,11 +50,10 @@ from pydantic.functional_validators import model_validator
|
|
48
50
|
from typing_extensions import Self
|
49
51
|
|
50
52
|
from .__types import DictData, DictStr, TupleStr
|
51
|
-
from .caller import TagFunc, extract_call
|
52
53
|
from .conf import config
|
53
54
|
from .exceptions import StageException, to_dict
|
54
55
|
from .result import Result, Status
|
55
|
-
from .
|
56
|
+
from .reusables import TagFunc, extract_call, not_in_template, param2template
|
56
57
|
from .utils import (
|
57
58
|
gen_id,
|
58
59
|
make_exec,
|
@@ -93,6 +94,10 @@ class BaseStage(BaseModel, ABC):
|
|
93
94
|
description="A stage condition statement to allow stage executable.",
|
94
95
|
alias="if",
|
95
96
|
)
|
97
|
+
extras: DictData = Field(
|
98
|
+
default_factory=dict,
|
99
|
+
description="An extra override values.",
|
100
|
+
)
|
96
101
|
|
97
102
|
@property
|
98
103
|
def iden(self) -> str:
|
@@ -126,7 +131,11 @@ class BaseStage(BaseModel, ABC):
|
|
126
131
|
|
127
132
|
@abstractmethod
|
128
133
|
def execute(
|
129
|
-
self,
|
134
|
+
self,
|
135
|
+
params: DictData,
|
136
|
+
*,
|
137
|
+
result: Result | None = None,
|
138
|
+
event: Event | None = None,
|
130
139
|
) -> Result:
|
131
140
|
"""Execute abstraction method that action something by sub-model class.
|
132
141
|
This is important method that make this class is able to be the stage.
|
@@ -135,11 +144,22 @@ class BaseStage(BaseModel, ABC):
|
|
135
144
|
execution.
|
136
145
|
:param result: (Result) A result object for keeping context and status
|
137
146
|
data.
|
147
|
+
:param event: (Event) An event manager that use to track parent execute
|
148
|
+
was not force stopped.
|
138
149
|
|
139
150
|
:rtype: Result
|
140
151
|
"""
|
141
152
|
raise NotImplementedError("Stage should implement `execute` method.")
|
142
153
|
|
154
|
+
async def axecute(
|
155
|
+
self,
|
156
|
+
params: DictData,
|
157
|
+
*,
|
158
|
+
result: Result | None = None,
|
159
|
+
event: Event | None,
|
160
|
+
) -> Result: # pragma: no cov
|
161
|
+
...
|
162
|
+
|
143
163
|
def handler_execute(
|
144
164
|
self,
|
145
165
|
params: DictData,
|
@@ -149,6 +169,7 @@ class BaseStage(BaseModel, ABC):
|
|
149
169
|
result: Result | None = None,
|
150
170
|
raise_error: bool = False,
|
151
171
|
to: DictData | None = None,
|
172
|
+
event: Event | None = None,
|
152
173
|
) -> Result:
|
153
174
|
"""Handler stage execution result from the stage `execute` method.
|
154
175
|
|
@@ -183,6 +204,7 @@ class BaseStage(BaseModel, ABC):
|
|
183
204
|
:param raise_error: (bool) A flag that all this method raise error
|
184
205
|
:param to: (DictData) A target object for auto set the return output
|
185
206
|
after execution.
|
207
|
+
:param event: (Event) An event manager that pass to the stage execution.
|
186
208
|
|
187
209
|
:rtype: Result
|
188
210
|
"""
|
@@ -194,7 +216,7 @@ class BaseStage(BaseModel, ABC):
|
|
194
216
|
)
|
195
217
|
|
196
218
|
try:
|
197
|
-
rs: Result = self.execute(params, result=result)
|
219
|
+
rs: Result = self.execute(params, result=result, event=event)
|
198
220
|
if to is not None:
|
199
221
|
return self.set_outputs(rs.context, to=to)
|
200
222
|
return rs
|
@@ -322,7 +344,11 @@ class EmptyStage(BaseStage):
|
|
322
344
|
)
|
323
345
|
|
324
346
|
def execute(
|
325
|
-
self,
|
347
|
+
self,
|
348
|
+
params: DictData,
|
349
|
+
*,
|
350
|
+
result: Result | None = None,
|
351
|
+
event: Event | None = None,
|
326
352
|
) -> Result:
|
327
353
|
"""Execution method for the Empty stage that do only logging out to
|
328
354
|
stdout. This method does not use the `handler_result` decorator because
|
@@ -335,6 +361,8 @@ class EmptyStage(BaseStage):
|
|
335
361
|
But this stage does not pass any output.
|
336
362
|
:param result: (Result) A result object for keeping context and status
|
337
363
|
data.
|
364
|
+
:param event: (Event) An event manager that use to track parent execute
|
365
|
+
was not force stopped.
|
338
366
|
|
339
367
|
:rtype: Result
|
340
368
|
"""
|
@@ -354,9 +382,25 @@ class EmptyStage(BaseStage):
|
|
354
382
|
return result.catch(status=Status.SUCCESS)
|
355
383
|
|
356
384
|
# TODO: Draft async execute method for the perf improvement.
|
357
|
-
async def
|
358
|
-
self,
|
385
|
+
async def axecute(
|
386
|
+
self,
|
387
|
+
params: DictData,
|
388
|
+
*,
|
389
|
+
result: Result | None = None,
|
390
|
+
event: Event | None,
|
359
391
|
) -> Result: # pragma: no cov
|
392
|
+
"""Async execution method for this Empty stage that only logging out to
|
393
|
+
stdout.
|
394
|
+
|
395
|
+
:param params: (DictData) A context data that want to add output result.
|
396
|
+
But this stage does not pass any output.
|
397
|
+
:param result: (Result) A result object for keeping context and status
|
398
|
+
data.
|
399
|
+
:param event: (Event) An event manager that use to track parent execute
|
400
|
+
was not force stopped.
|
401
|
+
|
402
|
+
:rtype: Result
|
403
|
+
"""
|
360
404
|
if result is None: # pragma: no cov
|
361
405
|
result: Result = Result(
|
362
406
|
run_id=gen_id(self.name + (self.id or ""), unique=True)
|
@@ -367,7 +411,11 @@ class EmptyStage(BaseStage):
|
|
367
411
|
f"( {param2template(self.echo, params=params) or '...'} )"
|
368
412
|
)
|
369
413
|
|
370
|
-
|
414
|
+
if self.sleep > 0:
|
415
|
+
if self.sleep > 5:
|
416
|
+
result.trace.info(f"[STAGE]: ... sleep ({self.sleep} seconds)")
|
417
|
+
await asyncio.sleep(self.sleep)
|
418
|
+
|
371
419
|
return result.catch(status=Status.SUCCESS)
|
372
420
|
|
373
421
|
|
@@ -438,7 +486,11 @@ class BashStage(BaseStage):
|
|
438
486
|
Path(f"./{f_name}").unlink()
|
439
487
|
|
440
488
|
def execute(
|
441
|
-
self,
|
489
|
+
self,
|
490
|
+
params: DictData,
|
491
|
+
*,
|
492
|
+
result: Result | None = None,
|
493
|
+
event: Event | None = None,
|
442
494
|
) -> Result:
|
443
495
|
"""Execute the Bash statement with the Python build-in ``subprocess``
|
444
496
|
package.
|
@@ -446,6 +498,8 @@ class BashStage(BaseStage):
|
|
446
498
|
:param params: A parameter data that want to use in this execution.
|
447
499
|
:param result: (Result) A result object for keeping context and status
|
448
500
|
data.
|
501
|
+
:param event: (Event) An event manager that use to track parent execute
|
502
|
+
was not force stopped.
|
449
503
|
|
450
504
|
:rtype: Result
|
451
505
|
"""
|
@@ -555,7 +609,11 @@ class PyStage(BaseStage):
|
|
555
609
|
return to
|
556
610
|
|
557
611
|
def execute(
|
558
|
-
self,
|
612
|
+
self,
|
613
|
+
params: DictData,
|
614
|
+
*,
|
615
|
+
result: Result | None = None,
|
616
|
+
event: Event | None = None,
|
559
617
|
) -> Result:
|
560
618
|
"""Execute the Python statement that pass all globals and input params
|
561
619
|
to globals argument on ``exec`` build-in function.
|
@@ -563,6 +621,8 @@ class PyStage(BaseStage):
|
|
563
621
|
:param params: A parameter that want to pass before run any statement.
|
564
622
|
:param result: (Result) A result object for keeping context and status
|
565
623
|
data.
|
624
|
+
:param event: (Event) An event manager that use to track parent execute
|
625
|
+
was not force stopped.
|
566
626
|
|
567
627
|
:rtype: Result
|
568
628
|
"""
|
@@ -629,7 +689,11 @@ class CallStage(BaseStage):
|
|
629
689
|
)
|
630
690
|
|
631
691
|
def execute(
|
632
|
-
self,
|
692
|
+
self,
|
693
|
+
params: DictData,
|
694
|
+
*,
|
695
|
+
result: Result | None = None,
|
696
|
+
event: Event | None = None,
|
633
697
|
) -> Result:
|
634
698
|
"""Execute the Call function that already in the call registry.
|
635
699
|
|
@@ -638,11 +702,12 @@ class CallStage(BaseStage):
|
|
638
702
|
:raise TypeError: When the return type of call function does not be
|
639
703
|
dict type.
|
640
704
|
|
641
|
-
:param params: A parameter that want to pass before run any
|
642
|
-
|
705
|
+
:param params: (DictData) A parameter that want to pass before run any
|
706
|
+
statement.
|
643
707
|
:param result: (Result) A result object for keeping context and status
|
644
708
|
data.
|
645
|
-
:
|
709
|
+
:param event: (Event) An event manager that use to track parent execute
|
710
|
+
was not force stopped.
|
646
711
|
|
647
712
|
:rtype: Result
|
648
713
|
"""
|
@@ -728,7 +793,11 @@ class TriggerStage(BaseStage):
|
|
728
793
|
)
|
729
794
|
|
730
795
|
def execute(
|
731
|
-
self,
|
796
|
+
self,
|
797
|
+
params: DictData,
|
798
|
+
*,
|
799
|
+
result: Result | None = None,
|
800
|
+
event: Event | None = None,
|
732
801
|
) -> Result:
|
733
802
|
"""Trigger another workflow execution. It will wait the trigger
|
734
803
|
workflow running complete before catching its result.
|
@@ -736,6 +805,8 @@ class TriggerStage(BaseStage):
|
|
736
805
|
:param params: A parameter data that want to use in this execution.
|
737
806
|
:param result: (Result) A result object for keeping context and status
|
738
807
|
data.
|
808
|
+
:param event: (Event) An event manager that use to track parent execute
|
809
|
+
was not force stopped.
|
739
810
|
|
740
811
|
:rtype: Result
|
741
812
|
"""
|
@@ -838,7 +909,11 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
838
909
|
return context
|
839
910
|
|
840
911
|
def execute(
|
841
|
-
self,
|
912
|
+
self,
|
913
|
+
params: DictData,
|
914
|
+
*,
|
915
|
+
result: Result | None = None,
|
916
|
+
event: Event | None = None,
|
842
917
|
) -> Result:
|
843
918
|
"""Execute the stages that parallel each branch via multi-threading mode
|
844
919
|
or async mode by changing `async_mode` flag.
|
@@ -846,6 +921,8 @@ class ParallelStage(BaseStage): # pragma: no cov
|
|
846
921
|
:param params: A parameter that want to pass before run any statement.
|
847
922
|
:param result: (Result) A result object for keeping context and status
|
848
923
|
data.
|
924
|
+
:param event: (Event) An event manager that use to track parent execute
|
925
|
+
was not force stopped.
|
849
926
|
|
850
927
|
:rtype: Result
|
851
928
|
"""
|
@@ -910,19 +987,34 @@ class ForEachStage(BaseStage):
|
|
910
987
|
),
|
911
988
|
)
|
912
989
|
stages: list[Stage] = Field(
|
990
|
+
default_factory=list,
|
913
991
|
description=(
|
914
992
|
"A list of stage that will run with each item in the foreach field."
|
915
993
|
),
|
916
994
|
)
|
995
|
+
concurrent: int = Field(
|
996
|
+
default=1,
|
997
|
+
gt=0,
|
998
|
+
description=(
|
999
|
+
"A concurrent value allow to run each item at the same time. It "
|
1000
|
+
"will be sequential mode if this value equal 1."
|
1001
|
+
),
|
1002
|
+
)
|
917
1003
|
|
918
1004
|
def execute(
|
919
|
-
self,
|
1005
|
+
self,
|
1006
|
+
params: DictData,
|
1007
|
+
*,
|
1008
|
+
result: Result | None = None,
|
1009
|
+
event: Event | None = None,
|
920
1010
|
) -> Result:
|
921
1011
|
"""Execute the stages that pass each item form the foreach field.
|
922
1012
|
|
923
1013
|
:param params: A parameter that want to pass before run any statement.
|
924
1014
|
:param result: (Result) A result object for keeping context and status
|
925
1015
|
data.
|
1016
|
+
:param event: (Event) An event manager that use to track parent execute
|
1017
|
+
was not force stopped.
|
926
1018
|
|
927
1019
|
:rtype: Result
|
928
1020
|
"""
|
@@ -933,6 +1025,7 @@ class ForEachStage(BaseStage):
|
|
933
1025
|
|
934
1026
|
rs: DictData = {"items": self.foreach, "foreach": {}}
|
935
1027
|
status = Status.SUCCESS
|
1028
|
+
# TODO: Implement concurrent more than 1.
|
936
1029
|
for item in self.foreach:
|
937
1030
|
result.trace.debug(f"[STAGE]: Execute foreach item: {item!r}")
|
938
1031
|
params["item"] = item
|
@@ -969,6 +1062,33 @@ class ForEachStage(BaseStage):
|
|
969
1062
|
return result.catch(status=status, context=rs)
|
970
1063
|
|
971
1064
|
|
1065
|
+
# TODO: Not implement this stages yet
|
1066
|
+
class UntilStage(BaseStage): # pragma: no cov
|
1067
|
+
"""Until execution stage."""
|
1068
|
+
|
1069
|
+
until: str = Field(description="A until condition.")
|
1070
|
+
item: Union[str, int, bool] = Field(description="An initial value.")
|
1071
|
+
stages: list[Stage] = Field(
|
1072
|
+
default_factory=list,
|
1073
|
+
description=(
|
1074
|
+
"A list of stage that will run with each item until condition "
|
1075
|
+
"correct."
|
1076
|
+
),
|
1077
|
+
)
|
1078
|
+
max_until_not_change: int = Field(
|
1079
|
+
default=3,
|
1080
|
+
description="The maximum value of loop if condition not change.",
|
1081
|
+
)
|
1082
|
+
|
1083
|
+
def execute(
|
1084
|
+
self,
|
1085
|
+
params: DictData,
|
1086
|
+
*,
|
1087
|
+
result: Result | None = None,
|
1088
|
+
event: Event | None = None,
|
1089
|
+
) -> Result: ...
|
1090
|
+
|
1091
|
+
|
972
1092
|
# TODO: Not implement this stages yet
|
973
1093
|
class IfStage(BaseStage): # pragma: no cov
|
974
1094
|
"""If execution stage.
|
@@ -1008,19 +1128,45 @@ class IfStage(BaseStage): # pragma: no cov
|
|
1008
1128
|
match: list[dict[str, Union[str, Stage]]]
|
1009
1129
|
|
1010
1130
|
def execute(
|
1011
|
-
self,
|
1131
|
+
self,
|
1132
|
+
params: DictData,
|
1133
|
+
*,
|
1134
|
+
result: Result | None = None,
|
1135
|
+
event: Event | None = None,
|
1012
1136
|
) -> Result: ...
|
1013
1137
|
|
1014
1138
|
|
1015
1139
|
class RaiseStage(BaseStage): # pragma: no cov
|
1140
|
+
"""Raise error stage that raise StageException that use a message field for
|
1141
|
+
making error message before raise.
|
1142
|
+
|
1143
|
+
Data Validate:
|
1144
|
+
>>> stage = {
|
1145
|
+
... "name": "Raise stage",
|
1146
|
+
... "raise": "raise this stage",
|
1147
|
+
... }
|
1148
|
+
|
1149
|
+
"""
|
1150
|
+
|
1016
1151
|
message: str = Field(
|
1017
1152
|
description="An error message that want to raise",
|
1018
1153
|
alias="raise",
|
1019
1154
|
)
|
1020
1155
|
|
1021
1156
|
def execute(
|
1022
|
-
self,
|
1157
|
+
self,
|
1158
|
+
params: DictData,
|
1159
|
+
*,
|
1160
|
+
result: Result | None = None,
|
1161
|
+
event: Event | None = None,
|
1023
1162
|
) -> Result:
|
1163
|
+
"""Raise the stage."""
|
1164
|
+
if result is None: # pragma: no cov
|
1165
|
+
result: Result = Result(
|
1166
|
+
run_id=gen_id(self.name + (self.id or ""), unique=True)
|
1167
|
+
)
|
1168
|
+
|
1169
|
+
result.trace.error(f"[STAGE]: ... raise ( {self.message} )")
|
1024
1170
|
raise StageException(self.message)
|
1025
1171
|
|
1026
1172
|
|
@@ -1031,7 +1177,11 @@ class HookStage(BaseStage): # pragma: no cov
|
|
1031
1177
|
callback: str
|
1032
1178
|
|
1033
1179
|
def execute(
|
1034
|
-
self,
|
1180
|
+
self,
|
1181
|
+
params: DictData,
|
1182
|
+
*,
|
1183
|
+
result: Result | None = None,
|
1184
|
+
event: Event | None = None,
|
1035
1185
|
) -> Result: ...
|
1036
1186
|
|
1037
1187
|
|
@@ -1039,13 +1189,19 @@ class HookStage(BaseStage): # pragma: no cov
|
|
1039
1189
|
class DockerStage(BaseStage): # pragma: no cov
|
1040
1190
|
"""Docker container stage execution."""
|
1041
1191
|
|
1042
|
-
image: str
|
1192
|
+
image: str = Field(
|
1193
|
+
description="A Docker image url with tag that want to run.",
|
1194
|
+
)
|
1043
1195
|
env: DictData = Field(default_factory=dict)
|
1044
1196
|
volume: DictData = Field(default_factory=dict)
|
1045
1197
|
auth: DictData = Field(default_factory=dict)
|
1046
1198
|
|
1047
1199
|
def execute(
|
1048
|
-
self,
|
1200
|
+
self,
|
1201
|
+
params: DictData,
|
1202
|
+
*,
|
1203
|
+
result: Result | None = None,
|
1204
|
+
event: Event | None = None,
|
1049
1205
|
) -> Result: ...
|
1050
1206
|
|
1051
1207
|
|
@@ -1059,7 +1215,11 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
1059
1215
|
def create_py_file(self, py: str, run_id: str | None): ...
|
1060
1216
|
|
1061
1217
|
def execute(
|
1062
|
-
self,
|
1218
|
+
self,
|
1219
|
+
params: DictData,
|
1220
|
+
*,
|
1221
|
+
result: Result | None = None,
|
1222
|
+
event: Event | None = None,
|
1063
1223
|
) -> Result:
|
1064
1224
|
return super().execute(params, result=result)
|
1065
1225
|
|
@@ -1068,7 +1228,11 @@ class VirtualPyStage(PyStage): # pragma: no cov
|
|
1068
1228
|
class SensorStage(BaseStage): # pragma: no cov
|
1069
1229
|
|
1070
1230
|
def execute(
|
1071
|
-
self,
|
1231
|
+
self,
|
1232
|
+
params: DictData,
|
1233
|
+
*,
|
1234
|
+
result: Result | None = None,
|
1235
|
+
event: Event | None = None,
|
1072
1236
|
) -> Result: ...
|
1073
1237
|
|
1074
1238
|
|
ddeutil/workflow/utils.py
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
# Licensed under the MIT License. See LICENSE in the project root for
|
4
4
|
# license information.
|
5
5
|
# ------------------------------------------------------------------------------
|
6
|
+
# [ ] Use config
|
7
|
+
"""Utility function model."""
|
6
8
|
from __future__ import annotations
|
7
9
|
|
8
10
|
import stat
|
@@ -154,6 +156,15 @@ def gen_id(
|
|
154
156
|
).hexdigest()
|
155
157
|
|
156
158
|
|
159
|
+
def default_gen_id() -> str:
|
160
|
+
"""Return running ID which use for making default ID for the Result model if
|
161
|
+
a run_id field initializes at the first time.
|
162
|
+
|
163
|
+
:rtype: str
|
164
|
+
"""
|
165
|
+
return gen_id("manual", unique=True)
|
166
|
+
|
167
|
+
|
157
168
|
def make_exec(path: str | Path) -> None:
|
158
169
|
"""Change mode of file to be executable file.
|
159
170
|
|
ddeutil/workflow/workflow.py
CHANGED
@@ -31,14 +31,14 @@ from typing_extensions import Self
|
|
31
31
|
|
32
32
|
from .__cron import CronJob, CronRunner
|
33
33
|
from .__types import DictData, TupleStr
|
34
|
-
from .audit import Audit, get_audit
|
35
34
|
from .conf import Loader, SimLoad, config, get_logger
|
36
35
|
from .cron import On
|
37
36
|
from .exceptions import JobException, WorkflowException
|
38
37
|
from .job import Job, TriggerState
|
38
|
+
from .logs import Audit, get_audit
|
39
39
|
from .params import Param
|
40
40
|
from .result import Result, Status
|
41
|
-
from .
|
41
|
+
from .reusables import has_template, param2template
|
42
42
|
from .utils import (
|
43
43
|
gen_id,
|
44
44
|
get_dt_now,
|
@@ -271,6 +271,10 @@ class Workflow(BaseModel):
|
|
271
271
|
default_factory=dict,
|
272
272
|
description="A mapping of job ID and job model that already loaded.",
|
273
273
|
)
|
274
|
+
extras: DictData = Field(
|
275
|
+
default_factory=dict,
|
276
|
+
description="An extra override values.",
|
277
|
+
)
|
274
278
|
|
275
279
|
@classmethod
|
276
280
|
def from_loader(
|
@@ -297,9 +301,10 @@ class Workflow(BaseModel):
|
|
297
301
|
raise ValueError(f"Type {loader.type} does not match with {cls}")
|
298
302
|
|
299
303
|
loader_data: DictData = copy.deepcopy(loader.data)
|
300
|
-
|
301
|
-
# NOTE: Add name to loader data
|
302
304
|
loader_data["name"] = name.replace(" ", "_")
|
305
|
+
if externals: # pragma: no cov
|
306
|
+
loader_data["extras"] = externals
|
307
|
+
|
303
308
|
cls.__bypass_on__(
|
304
309
|
loader_data, path=loader.conf_path, externals=externals
|
305
310
|
)
|
@@ -333,9 +338,10 @@ class Workflow(BaseModel):
|
|
333
338
|
raise ValueError(f"Type {loader.type} does not match with {cls}")
|
334
339
|
|
335
340
|
loader_data: DictData = copy.deepcopy(loader.data)
|
336
|
-
|
337
|
-
# NOTE: Add name to loader data
|
338
341
|
loader_data["name"] = name.replace(" ", "_")
|
342
|
+
if externals: # pragma: no cov
|
343
|
+
loader_data["extras"] = externals
|
344
|
+
|
339
345
|
cls.__bypass_on__(loader_data, path=path, externals=externals)
|
340
346
|
return cls.model_validate(obj=loader_data)
|
341
347
|
|
@@ -446,7 +452,6 @@ class Workflow(BaseModel):
|
|
446
452
|
f"{self.name!r}."
|
447
453
|
)
|
448
454
|
|
449
|
-
# NOTE: update a job id with its job id from workflow template
|
450
455
|
self.jobs[job].id = job
|
451
456
|
|
452
457
|
# VALIDATE: Validate workflow name should not dynamic with params
|
@@ -476,7 +481,10 @@ class Workflow(BaseModel):
|
|
476
481
|
f"A Job {name!r} does not exists in this workflow, "
|
477
482
|
f"{self.name!r}"
|
478
483
|
)
|
479
|
-
|
484
|
+
job: Job = self.jobs[name]
|
485
|
+
if self.extras:
|
486
|
+
job.extras = self.extras
|
487
|
+
return job
|
480
488
|
|
481
489
|
def parameterize(self, params: DictData) -> DictData:
|
482
490
|
"""Prepare a passing parameters before use it in execution process.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ddeutil-workflow
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.41
|
4
4
|
Summary: Lightweight workflow orchestration
|
5
5
|
Author-email: ddeutils <korawich.anu@gmail.com>
|
6
6
|
License: MIT
|
@@ -27,6 +27,12 @@ Requires-Dist: ddeutil-io[toml,yaml]>=0.2.10
|
|
27
27
|
Requires-Dist: pydantic==2.11.1
|
28
28
|
Requires-Dist: python-dotenv==1.1.0
|
29
29
|
Requires-Dist: schedule<2.0.0,==1.2.2
|
30
|
+
Provides-Extra: all
|
31
|
+
Requires-Dist: fastapi<1.0.0,>=0.115.0; extra == "all"
|
32
|
+
Requires-Dist: httpx; extra == "all"
|
33
|
+
Requires-Dist: ujson; extra == "all"
|
34
|
+
Requires-Dist: aiofiles; extra == "all"
|
35
|
+
Requires-Dist: aiohttp; extra == "all"
|
30
36
|
Provides-Extra: api
|
31
37
|
Requires-Dist: fastapi<1.0.0,>=0.115.0; extra == "api"
|
32
38
|
Requires-Dist: httpx; extra == "api"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
ddeutil/workflow/__about__.py,sha256=chYiprva6VKQg6XFgrwBoMIWSlSshsb-yyHtFoiipvc,28
|
2
|
+
ddeutil/workflow/__cron.py,sha256=h8rLeIUAAEB2SdZ4Jhch7LU1Yl3bbJ-iNNJ3tQ0eYVM,28095
|
3
|
+
ddeutil/workflow/__init__.py,sha256=cYWwG2utpsYvdwqvkFSRWi_Q6gylDgNQBcIWcF5NFs4,1861
|
4
|
+
ddeutil/workflow/__types.py,sha256=8jBdbfb3aZSetjz0mvNrpGHwwxJff7mK8_4v41cLqlc,4316
|
5
|
+
ddeutil/workflow/conf.py,sha256=wQXL5bfEUx8DbS6cEIRtsDjvQZzw7sGPvs-g5r2zOeM,12095
|
6
|
+
ddeutil/workflow/context.py,sha256=vsk4JQL7t3KsnKPfshw3O7YrPFo2h4rnnNd3B-G9Kj4,1700
|
7
|
+
ddeutil/workflow/cron.py,sha256=j8EeoHst70toRfnD_frix41vrI-eLYVJkZ9yeJtpfnI,8871
|
8
|
+
ddeutil/workflow/exceptions.py,sha256=fO37f9p7lOjIJgVOpKE_1X44yJTwBepyukZV9a7NNm4,1241
|
9
|
+
ddeutil/workflow/job.py,sha256=TAtOFOFWHGqXlc6QWvtum1KpfWFDs5AfNbYMtwvrIE8,30102
|
10
|
+
ddeutil/workflow/logs.py,sha256=nbyoUONqSZ4QpowgMs962m-Qs-UDfcyMHs4bxIAT470,18782
|
11
|
+
ddeutil/workflow/params.py,sha256=Mv-D2DY5inm1ug0lsgCPDkO5wT_AUhc5XEF5jxgDx6U,8036
|
12
|
+
ddeutil/workflow/result.py,sha256=ynZB0g_vEEXn24034J-hatjNWDBmRAj38S8SqGRM-8I,4029
|
13
|
+
ddeutil/workflow/reusables.py,sha256=Rw7qS2cQM4SBxuIyqiyJN5yZNBfObISXWRIgDUMC2fY,17449
|
14
|
+
ddeutil/workflow/scheduler.py,sha256=Y4VuVDIHz64l3IN-7tKP76qrMKShpgXXjX64mKjSWLo,27651
|
15
|
+
ddeutil/workflow/stages.py,sha256=Kp3VLhKMMlgQyMLEYWJfBdR8DoCD0nuzSY0-r-P8eS8,41574
|
16
|
+
ddeutil/workflow/utils.py,sha256=XwkxOpPaHbvjCKCGA3kVriEYabKyZ_P6pTbkYPnK704,7380
|
17
|
+
ddeutil/workflow/workflow.py,sha256=s2z_QMTmfsRjiw25CuKFQIqY9smCbKjFwbBwCZkikfc,49615
|
18
|
+
ddeutil/workflow/api/__init__.py,sha256=F53NMBWtb9IKaDWkPU5KvybGGfKAcbehgn6TLBwHuuM,21
|
19
|
+
ddeutil/workflow/api/api.py,sha256=C9f6w11zE1SHz8lwjRxVOwrO90pCMr9REj2WLQsO0lI,5190
|
20
|
+
ddeutil/workflow/api/log.py,sha256=NMTnOnsBrDB5129329xF2myLdrb-z9k1MQrmrP7qXJw,1818
|
21
|
+
ddeutil/workflow/api/repeat.py,sha256=cycd1-91j-4v6uY1SkrZHd9l95e-YgVC4UCSNNFuGJ8,5277
|
22
|
+
ddeutil/workflow/api/routes/__init__.py,sha256=qoGtOMyVgQ5nTUc8J8wH27A8isaxl3IFCX8qoyibeCY,484
|
23
|
+
ddeutil/workflow/api/routes/job.py,sha256=YVta083i8vU8-o4WdKFwDpfdC9vN1dZ6goZSmNlQXHA,1954
|
24
|
+
ddeutil/workflow/api/routes/logs.py,sha256=TeRDrEelbKS2Hu_EovgLh0bOdmSv9mfnrIZsrE7uPD4,5353
|
25
|
+
ddeutil/workflow/api/routes/schedules.py,sha256=uWYDOwlV8w56hKQmfkQFwdZ6t2gZSJeCdBIzMmJenAQ,4824
|
26
|
+
ddeutil/workflow/api/routes/workflows.py,sha256=TiGlwosHucccVmGv_SE9mvs3_BR2c6QZWQhw--aAv5w,4537
|
27
|
+
ddeutil_workflow-0.0.41.dist-info/licenses/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
|
28
|
+
ddeutil_workflow-0.0.41.dist-info/METADATA,sha256=ACsWRIhGZuaRo_d400dlAFsSRlNcha8Vy0PzVMkE3NU,19729
|
29
|
+
ddeutil_workflow-0.0.41.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
30
|
+
ddeutil_workflow-0.0.41.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
|
31
|
+
ddeutil_workflow-0.0.41.dist-info/RECORD,,
|