ddeutil-workflow 0.0.22__py3-none-any.whl → 0.0.24__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
@@ -51,9 +51,9 @@ from typing_extensions import Self
51
51
  from .__types import DictData, DictStr, Re, TupleStr
52
52
  from .conf import config, get_logger
53
53
  from .exceptions import StageException
54
+ from .result import Result
54
55
  from .utils import (
55
56
  Registry,
56
- Result,
57
57
  TagFunc,
58
58
  cut_id,
59
59
  gen_id,
@@ -346,6 +346,11 @@ class EmptyStage(BaseStage):
346
346
  f"( {param2template(self.echo, params=params) or '...'} )"
347
347
  )
348
348
  if self.sleep > 0:
349
+ if self.sleep > 30:
350
+ logger.info(
351
+ f"({cut_id(run_id)}) [STAGE]: ... sleep "
352
+ f"({self.sleep} seconds)"
353
+ )
349
354
  time.sleep(self.sleep)
350
355
  return Result(status=0, context={}, run_id=run_id)
351
356
 
ddeutil/workflow/utils.py CHANGED
@@ -9,11 +9,9 @@ import inspect
9
9
  import logging
10
10
  import stat
11
11
  import time
12
- from abc import ABC, abstractmethod
13
12
  from ast import Call, Constant, Expr, Module, Name, parse
14
13
  from collections.abc import Iterator
15
- from dataclasses import field
16
- from datetime import date, datetime, timedelta
14
+ from datetime import datetime, timedelta
17
15
  from functools import wraps
18
16
  from hashlib import md5
19
17
  from importlib import import_module
@@ -21,7 +19,7 @@ from inspect import isfunction
21
19
  from itertools import chain, islice, product
22
20
  from pathlib import Path
23
21
  from random import randrange
24
- from typing import Any, Callable, Literal, Optional, Protocol, TypeVar, Union
22
+ from typing import Any, Callable, Protocol, TypeVar, Union
25
23
  from zoneinfo import ZoneInfo
26
24
 
27
25
  try:
@@ -31,14 +29,11 @@ except ImportError:
31
29
 
32
30
  from ddeutil.core import getdot, hasdot, hash_str, import_string, lazy
33
31
  from ddeutil.io import search_env_replace
34
- from pydantic import BaseModel, Field
35
- from pydantic.dataclasses import dataclass
36
- from pydantic.functional_validators import model_validator
37
- from typing_extensions import Self
32
+ from pydantic import BaseModel
38
33
 
39
34
  from .__types import DictData, Matrix, Re
40
35
  from .conf import config
41
- from .exceptions import ParamValueException, UtilException
36
+ from .exceptions import UtilException
42
37
 
43
38
  T = TypeVar("T")
44
39
  P = ParamSpec("P")
@@ -198,238 +193,6 @@ def make_registry(submodule: str) -> dict[str, Registry]:
198
193
  return rs
199
194
 
200
195
 
201
- class BaseParam(BaseModel, ABC):
202
- """Base Parameter that use to make Params Model."""
203
-
204
- desc: Optional[str] = Field(
205
- default=None, description="A description of parameter providing."
206
- )
207
- required: bool = Field(
208
- default=True,
209
- description="A require flag that force to pass this parameter value.",
210
- )
211
- type: str = Field(description="A type of parameter.")
212
-
213
- @abstractmethod
214
- def receive(self, value: Optional[Any] = None) -> Any:
215
- raise NotImplementedError(
216
- "Receive value and validate typing before return valid value."
217
- )
218
-
219
-
220
- class DefaultParam(BaseParam):
221
- """Default Parameter that will check default if it required. This model do
222
- not implement the receive method.
223
- """
224
-
225
- required: bool = Field(
226
- default=False,
227
- description="A require flag for the default-able parameter value.",
228
- )
229
- default: Optional[str] = Field(
230
- default=None,
231
- description="A default value if parameter does not pass.",
232
- )
233
-
234
- @abstractmethod
235
- def receive(self, value: Optional[Any] = None) -> Any:
236
- raise NotImplementedError(
237
- "Receive value and validate typing before return valid value."
238
- )
239
-
240
-
241
- class DatetimeParam(DefaultParam):
242
- """Datetime parameter."""
243
-
244
- type: Literal["datetime"] = "datetime"
245
- default: datetime = Field(default_factory=get_dt_now)
246
-
247
- def receive(self, value: str | datetime | date | None = None) -> datetime:
248
- """Receive value that match with datetime. If a input value pass with
249
- None, it will use default value instead.
250
-
251
- :param value: A value that want to validate with datetime parameter
252
- type.
253
- :rtype: datetime
254
- """
255
- if value is None:
256
- return self.default
257
-
258
- if isinstance(value, datetime):
259
- return value
260
- elif isinstance(value, date):
261
- return datetime(value.year, value.month, value.day)
262
- elif not isinstance(value, str):
263
- raise ParamValueException(
264
- f"Value that want to convert to datetime does not support for "
265
- f"type: {type(value)}"
266
- )
267
- try:
268
- return datetime.fromisoformat(value)
269
- except ValueError:
270
- raise ParamValueException(
271
- f"Invalid isoformat string: {value!r}"
272
- ) from None
273
-
274
-
275
- class StrParam(DefaultParam):
276
- """String parameter."""
277
-
278
- type: Literal["str"] = "str"
279
-
280
- def receive(self, value: str | None = None) -> str | None:
281
- """Receive value that match with str.
282
-
283
- :param value: A value that want to validate with string parameter type.
284
- :rtype: str | None
285
- """
286
- if value is None:
287
- return self.default
288
- return str(value)
289
-
290
-
291
- class IntParam(DefaultParam):
292
- """Integer parameter."""
293
-
294
- type: Literal["int"] = "int"
295
- default: Optional[int] = Field(
296
- default=None,
297
- description="A default value if parameter does not pass.",
298
- )
299
-
300
- def receive(self, value: int | None = None) -> int | None:
301
- """Receive value that match with int.
302
-
303
- :param value: A value that want to validate with integer parameter type.
304
- :rtype: int | None
305
- """
306
- if value is None:
307
- return self.default
308
- if not isinstance(value, int):
309
- try:
310
- return int(str(value))
311
- except ValueError as err:
312
- raise ParamValueException(
313
- f"Value can not convert to int, {value}, with base 10"
314
- ) from err
315
- return value
316
-
317
-
318
- class ChoiceParam(BaseParam):
319
- """Choice parameter."""
320
-
321
- type: Literal["choice"] = "choice"
322
- options: list[str] = Field(description="A list of choice parameters.")
323
-
324
- def receive(self, value: str | None = None) -> str:
325
- """Receive value that match with options.
326
-
327
- :param value: A value that want to select from the options field.
328
- :rtype: str
329
- """
330
- # NOTE:
331
- # Return the first value in options if does not pass any input value
332
- if value is None:
333
- return self.options[0]
334
- if value not in self.options:
335
- raise ParamValueException(
336
- f"{value!r} does not match any value in choice options."
337
- )
338
- return value
339
-
340
-
341
- Param = Union[
342
- ChoiceParam,
343
- DatetimeParam,
344
- IntParam,
345
- StrParam,
346
- ]
347
-
348
-
349
- @dataclass
350
- class Result:
351
- """Result Pydantic Model for passing and receiving data context from any
352
- module execution process like stage execution, job execution, or workflow
353
- execution.
354
-
355
- For comparison property, this result will use ``status``, ``context``,
356
- and ``_run_id`` fields to comparing with other result instance.
357
- """
358
-
359
- status: int = field(default=2)
360
- context: DictData = field(default_factory=dict)
361
-
362
- # NOTE: Ignore this field to compare another result model with __eq__.
363
- run_id: Optional[str] = field(default=None)
364
- parent_run_id: Optional[str] = field(default=None, compare=False)
365
-
366
- @model_validator(mode="after")
367
- def __prepare_run_id(self) -> Self:
368
- """Prepare running ID which use default ID if it initialize at the first
369
- time
370
-
371
- :rtype: Self
372
- """
373
- self._run_id = gen_id("manual", unique=True)
374
- return self
375
-
376
- def set_run_id(self, running_id: str) -> Self:
377
- """Set a running ID.
378
-
379
- :param running_id: A running ID that want to update on this model.
380
- :rtype: Self
381
- """
382
- self.run_id = running_id
383
- return self
384
-
385
- def set_parent_run_id(self, running_id: str) -> Self:
386
- """Set a parent running ID.
387
-
388
- :param running_id: A running ID that want to update on this model.
389
- :rtype: Self
390
- """
391
- self.parent_run_id: str = running_id
392
- return self
393
-
394
- def catch(self, status: int, context: DictData) -> Self:
395
- """Catch the status and context to current data."""
396
- self.__dict__["status"] = status
397
- self.__dict__["context"].update(context)
398
- return self
399
-
400
- def receive(self, result: Result) -> Self:
401
- """Receive context from another result object.
402
-
403
- :rtype: Self
404
- """
405
- self.__dict__["status"] = result.status
406
- self.__dict__["context"].update(result.context)
407
-
408
- # NOTE: Update running ID from an incoming result.
409
- self.parent_run_id = result.parent_run_id
410
- self.run_id = result.run_id
411
- return self
412
-
413
- def receive_jobs(self, result: Result) -> Self:
414
- """Receive context from another result object that use on the workflow
415
- execution which create a ``jobs`` keys on the context if it do not
416
- exist.
417
-
418
- :rtype: Self
419
- """
420
- self.__dict__["status"] = result.status
421
-
422
- # NOTE: Check the context has jobs key.
423
- if "jobs" not in self.__dict__["context"]:
424
- self.__dict__["context"]["jobs"] = {}
425
- self.__dict__["context"]["jobs"].update(result.context)
426
-
427
- # NOTE: Update running ID from an incoming result.
428
- self.parent_run_id: str = result.parent_run_id
429
- self.run_id: str = result.run_id
430
- return self
431
-
432
-
433
196
  def make_exec(path: str | Path) -> None:
434
197
  """Change mode of file to be executable file.
435
198
 
@@ -814,10 +577,6 @@ def batch(iterable: Iterator[Any], n: int) -> Iterator[Any]:
814
577
  yield chain((first_el,), chunk_it)
815
578
 
816
579
 
817
- def queue2str(queue: list[datetime]) -> Iterator[str]: # pragma: no cov
818
- return (f"{q:%Y-%m-%d %H:%M:%S}" for q in queue)
819
-
820
-
821
580
  def cut_id(run_id: str, *, num: int = 6):
822
581
  """Cutting running ID with length.
823
582