ddeutil-workflow 0.0.14__py3-none-any.whl → 0.0.16__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/stage.py CHANGED
@@ -3,8 +3,8 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- """Stage Model that use for getting stage data template from Job Model.
7
- The stage that handle the minimize task that run in some thread (same thread at
6
+ """Stage Model that use for getting stage data template from the Job Model.
7
+ The stage handle the minimize task that run in some thread (same thread at
8
8
  its job owner) that mean it is the lowest executor of a workflow workflow that
9
9
  can tracking logs.
10
10
 
@@ -12,11 +12,13 @@ can tracking logs.
12
12
  handle stage error on this stage model. I think stage model should have a lot of
13
13
  usecase and it does not worry when I want to create a new one.
14
14
 
15
- Execution --> Ok --> Result with 0
16
- --> Error --> Raise StageException
15
+ Execution --> Ok --> Result with 0
16
+ --> Error --> Raise StageException
17
+ --> Result with 1 (if env var was set)
17
18
 
18
- On the context I/O that pass to stage object at execute process. The execute
19
- method receive `{"params": {...}}` for mapping to template.
19
+ On the context I/O that pass to a stage object at execute process. The
20
+ execute method receives a `params={"params": {...}}` value for mapping to
21
+ template searching.
20
22
  """
21
23
  from __future__ import annotations
22
24
 
@@ -24,6 +26,7 @@ import contextlib
24
26
  import inspect
25
27
  import subprocess
26
28
  import sys
29
+ import time
27
30
  import uuid
28
31
  from abc import ABC, abstractmethod
29
32
  from collections.abc import Iterator
@@ -60,6 +63,8 @@ from .utils import (
60
63
  )
61
64
 
62
65
  P = ParamSpec("P")
66
+ ReturnResult = Callable[P, Result]
67
+ DecoratorResult = Callable[[ReturnResult], ReturnResult]
63
68
  logger = get_logger("ddeutil.workflow")
64
69
 
65
70
 
@@ -77,7 +82,7 @@ __all__: TupleStr = (
77
82
  )
78
83
 
79
84
 
80
- def handler_result(message: str | None = None) -> Callable[P, Result]:
85
+ def handler_result(message: str | None = None) -> DecoratorResult:
81
86
  """Decorator function for handler result from the stage execution. This
82
87
  function should to use with execution method only.
83
88
 
@@ -85,25 +90,33 @@ def handler_result(message: str | None = None) -> Callable[P, Result]:
85
90
  you force catching an output result with error message by specific
86
91
  environment variable,`WORKFLOW_CORE_STAGE_RAISE_ERROR`.
87
92
 
88
- Execution --> Ok --> Result with 0
93
+ Execution --> Ok --> Result
94
+ status: 0
95
+ context:
96
+ outputs: ...
89
97
  --> Error --> Raise StageException
90
- --> Result with 1 (if env var was set)
98
+ --> Result (if env var was set)
99
+ status: 1
100
+ context:
101
+ error: ...
102
+ error_message: ...
91
103
 
92
104
  On the last step, it will set the running ID on a return result object
93
105
  from current stage ID before release the final result.
94
106
 
95
107
  :param message: A message that want to add at prefix of exception statement.
108
+ :type message: str | None (Default=None)
96
109
  :rtype: Callable[P, Result]
97
110
  """
98
111
  # NOTE: The prefix message string that want to add on the first exception
99
112
  # message dialog.
100
113
  #
101
- # ... ValueError: {message}
114
+ # >>> ValueError: {message}
102
115
  # ... raise value error from the stage execution process.
103
116
  #
104
117
  message: str = message or ""
105
118
 
106
- def decorator(func: Callable[P, Result]) -> Callable[P, Result]:
119
+ def decorator(func: ReturnResult) -> ReturnResult:
107
120
 
108
121
  @wraps(func)
109
122
  def wrapped(self: Stage, *args, **kwargs):
@@ -172,7 +185,7 @@ class BaseStage(BaseModel, ABC):
172
185
  )
173
186
 
174
187
  @model_validator(mode="after")
175
- def __prepare_running_id(self) -> Self:
188
+ def __prepare_running_id__(self) -> Self:
176
189
  """Prepare stage running ID that use default value of field and this
177
190
  method will validate name and id fields should not contain any template
178
191
  parameter (exclude matrix template).
@@ -232,7 +245,7 @@ class BaseStage(BaseModel, ABC):
232
245
  :param to: A context data that want to add output result.
233
246
  :rtype: DictData
234
247
  """
235
- if not (self.id or config.stage_default_id):
248
+ if self.id is None and not config.stage_default_id:
236
249
  logger.debug(
237
250
  f"({self.run_id}) [STAGE]: Output does not set because this "
238
251
  f"stage does not set ID or default stage ID config flag not be "
@@ -252,7 +265,7 @@ class BaseStage(BaseModel, ABC):
252
265
  )
253
266
 
254
267
  # NOTE: Set the output to that stage generated ID with ``outputs`` key.
255
- logger.debug(f"({self.run_id}) [STAGE]: Set outputs on: {_id}")
268
+ logger.debug(f"({self.run_id}) [STAGE]: Set outputs to {_id!r}")
256
269
  to["stages"][_id] = {"outputs": output}
257
270
  return to
258
271
 
@@ -293,6 +306,11 @@ class EmptyStage(BaseStage):
293
306
  default=None,
294
307
  description="A string statement that want to logging",
295
308
  )
309
+ sleep: float = Field(
310
+ default=0,
311
+ description="A second value to sleep before finish execution",
312
+ ge=0,
313
+ )
296
314
 
297
315
  def execute(self, params: DictData) -> Result:
298
316
  """Execution method for the Empty stage that do only logging out to
@@ -310,6 +328,8 @@ class EmptyStage(BaseStage):
310
328
  f"({self.run_id}) [STAGE]: Empty-Execute: {self.name!r}: "
311
329
  f"( {param2template(self.echo, params=params) or '...'} )"
312
330
  )
331
+ if self.sleep > 0:
332
+ time.sleep(self.sleep)
313
333
  return Result(status=0, context={})
314
334
 
315
335
 
@@ -342,7 +362,7 @@ class BashStage(BaseStage):
342
362
  )
343
363
 
344
364
  @contextlib.contextmanager
345
- def __prepare_bash(self, bash: str, env: DictStr) -> Iterator[TupleStr]:
365
+ def prepare_bash(self, bash: str, env: DictStr) -> Iterator[TupleStr]:
346
366
  """Return context of prepared bash statement that want to execute. This
347
367
  step will write the `.sh` file before giving this file name to context.
348
368
  After that, it will auto delete this file automatic.
@@ -385,15 +405,12 @@ class BashStage(BaseStage):
385
405
  :rtype: Result
386
406
  """
387
407
  bash: str = param2template(dedent(self.bash), params)
388
- with self.__prepare_bash(
408
+ with self.prepare_bash(
389
409
  bash=bash, env=param2template(self.env, params)
390
410
  ) as sh:
391
411
  logger.info(f"({self.run_id}) [STAGE]: Shell-Execute: {sh}")
392
412
  rs: CompletedProcess = subprocess.run(
393
- sh,
394
- shell=False,
395
- capture_output=True,
396
- text=True,
413
+ sh, shell=False, capture_output=True, text=True
397
414
  )
398
415
  if rs.returncode > 0:
399
416
  # NOTE: Prepare stderr message that returning from subprocess.
@@ -410,8 +427,8 @@ class BashStage(BaseStage):
410
427
  status=0,
411
428
  context={
412
429
  "return_code": rs.returncode,
413
- "stdout": rs.stdout.rstrip("\n"),
414
- "stderr": rs.stderr.rstrip("\n"),
430
+ "stdout": rs.stdout.rstrip("\n") or None,
431
+ "stderr": rs.stderr.rstrip("\n") or None,
415
432
  },
416
433
  )
417
434
 
@@ -545,14 +562,14 @@ class HookStage(BaseStage):
545
562
  >>> stage = {
546
563
  ... "name": "Task stage execution",
547
564
  ... "uses": "tasks/function-name@tag-name",
548
- ... "args": {
549
- ... "FOO": "BAR",
550
- ... },
565
+ ... "args": {"FOO": "BAR"},
551
566
  ... }
552
567
  """
553
568
 
554
569
  uses: str = Field(
555
- description="A pointer that want to load function from registry.",
570
+ description=(
571
+ "A pointer that want to load function from the hook registry."
572
+ ),
556
573
  )
557
574
  args: DictData = Field(
558
575
  default_factory=dict,
@@ -613,10 +630,7 @@ class TriggerStage(BaseStage):
613
630
  >>> stage = {
614
631
  ... "name": "Trigger workflow stage execution",
615
632
  ... "trigger": 'workflow-name-for-loader',
616
- ... "params": {
617
- ... "run-date": "2024-08-01",
618
- ... "source": "src",
619
- ... },
633
+ ... "params": {"run-date": "2024-08-01", "source": "src"},
620
634
  ... }
621
635
  """
622
636