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.
@@ -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 .templates import not_in_template, param2template
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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 aexecute(
358
- self, params: DictData, *, result: Result | None = None
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
- await asyncio.sleep(1)
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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 statement.
642
- :type params: DictData
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
- :type: str | None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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, params: DictData, *, result: Result | None = None
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
 
@@ -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 .templates import has_template, param2template
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
- return self.jobs[name]
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.40
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,,