ddeutil-workflow 0.0.28__py3-none-any.whl → 0.0.29__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.
@@ -1 +1 @@
1
- __version__: str = "0.0.28"
1
+ __version__: str = "0.0.29"
@@ -4,6 +4,7 @@
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
6
  from .__cron import CronJob, CronRunner
7
+ from .__types import Re
7
8
  from .conf import (
8
9
  Config,
9
10
  Loader,
@@ -27,6 +27,8 @@ Matrix = dict[str, Union[list[str], list[int]]]
27
27
 
28
28
 
29
29
  class Context(TypedDict):
30
+ """TypeDict support the Context."""
31
+
30
32
  params: dict[str, Any]
31
33
  jobs: dict[str, Any]
32
34
 
@@ -71,14 +73,14 @@ class Re:
71
73
  # - ${{ params.source?.schema }}
72
74
  #
73
75
  __re_caller: str = r"""
74
- \$
75
- {{
76
- \s*
76
+ \$ # start with $
77
+ {{ # value open with {{
78
+ \s* # whitespace or not
77
79
  (?P<caller>
78
80
  (?P<caller_prefix>(?:[a-zA-Z_-]+\??\.)*)
79
81
  (?P<caller_last>[a-zA-Z0-9_\-.'\"(\)[\]{}]+\??)
80
82
  )
81
- \s*
83
+ \s* # whitespace or not
82
84
  (?P<post_filters>
83
85
  (?:
84
86
  \|\s*
@@ -88,7 +90,7 @@ class Re:
88
90
  )\s*
89
91
  )*
90
92
  )
91
- }}
93
+ }} # value close with }}
92
94
  """
93
95
  RE_CALLER: Pattern = re.compile(
94
96
  __re_caller, MULTILINE | IGNORECASE | UNICODE | VERBOSE
@@ -103,13 +105,13 @@ class Re:
103
105
  # - tasks/function@dummy
104
106
  #
105
107
  __re_task_fmt: str = r"""
106
- ^
108
+ ^ # start task format
107
109
  (?P<path>[^/@]+)
108
- /
110
+ / # start get function with /
109
111
  (?P<func>[^@]+)
110
- @
112
+ @ # start tag with @
111
113
  (?P<tag>.+)
112
- $
114
+ $ # end task format
113
115
  """
114
116
  RE_TASK_FMT: Pattern = re.compile(
115
117
  __re_task_fmt, MULTILINE | IGNORECASE | UNICODE | VERBOSE
ddeutil/workflow/conf.py CHANGED
@@ -13,7 +13,7 @@ from collections.abc import Iterator
13
13
  from datetime import datetime, timedelta
14
14
  from functools import cached_property, lru_cache
15
15
  from pathlib import Path
16
- from typing import ClassVar, Optional, Union
16
+ from typing import ClassVar, Optional, TypeVar, Union
17
17
  from zoneinfo import ZoneInfo
18
18
 
19
19
  from ddeutil.core import str2bool
@@ -39,6 +39,7 @@ __all__: TupleStr = (
39
39
  "env",
40
40
  "get_logger",
41
41
  "get_log",
42
+ "C",
42
43
  "Config",
43
44
  "SimLoad",
44
45
  "Loader",
@@ -81,18 +82,42 @@ def get_logger(name: str):
81
82
  return lg
82
83
 
83
84
 
84
- class Config: # pragma: no cov
85
+ class BaseConfig: # pragma: no cov
86
+ """BaseConfig object inheritable."""
87
+
88
+ __slots__ = ()
89
+
90
+ @property
91
+ def root_path(self) -> Path:
92
+ """Root path or the project path.
93
+
94
+ :rtype: Path
95
+ """
96
+ return Path(os.getenv("ROOT_PATH", "."))
97
+
98
+ @property
99
+ def conf_path(self) -> Path:
100
+ """Config path that use root_path class argument for this construction.
101
+
102
+ :rtype: Path
103
+ """
104
+ return self.root_path / os.getenv("CONF_PATH", "conf")
105
+
106
+
107
+ class Config(BaseConfig): # pragma: no cov
85
108
  """Config object for keeping core configurations on the current session
86
109
  without changing when if the application still running.
87
110
 
88
111
  The config value can change when you call that config property again.
89
112
  """
90
113
 
91
- __slots__ = ()
92
-
93
114
  # NOTE: Core
94
115
  @property
95
116
  def root_path(self) -> Path:
117
+ """Root path or the project path.
118
+
119
+ :rtype: Path
120
+ """
96
121
  return Path(env("CORE_ROOT_PATH", "."))
97
122
 
98
123
  @property
@@ -114,7 +139,7 @@ class Config: # pragma: no cov
114
139
  # NOTE: Register
115
140
  @property
116
141
  def regis_hook(self) -> list[str]:
117
- regis_hook_str: str = env("CORE_REGISTRY", "src")
142
+ regis_hook_str: str = env("CORE_REGISTRY", ".")
118
143
  return [r.strip() for r in regis_hook_str.split(",")]
119
144
 
120
145
  @property
@@ -220,6 +245,9 @@ class Config: # pragma: no cov
220
245
  return str2bool(env("API_ENABLE_ROUTE_SCHEDULE", "true"))
221
246
 
222
247
 
248
+ C = TypeVar("C", bound=BaseConfig)
249
+
250
+
223
251
  class SimLoad:
224
252
  """Simple Load Object that will search config data by given some identity
225
253
  value like name of workflow or on.
@@ -243,7 +271,7 @@ class SimLoad:
243
271
  def __init__(
244
272
  self,
245
273
  name: str,
246
- conf: Config,
274
+ conf: C,
247
275
  externals: DictData | None = None,
248
276
  ) -> None:
249
277
  self.data: DictData = {}
@@ -256,7 +284,7 @@ class SimLoad:
256
284
  if not self.data:
257
285
  raise ValueError(f"Config {name!r} does not found on conf path")
258
286
 
259
- self.conf: Config = conf
287
+ self.conf: C = conf
260
288
  self.externals: DictData = externals or {}
261
289
  self.data.update(self.externals)
262
290
 
@@ -264,7 +292,7 @@ class SimLoad:
264
292
  def finds(
265
293
  cls,
266
294
  obj: object,
267
- conf: Config,
295
+ conf: C,
268
296
  *,
269
297
  included: list[str] | None = None,
270
298
  excluded: list[str] | None = None,
@@ -273,7 +301,7 @@ class SimLoad:
273
301
  method can use include and exclude list of identity name for filter and
274
302
  adds-on.
275
303
 
276
- :param obj: A object that want to validate matching before return.
304
+ :param obj: An object that want to validate matching before return.
277
305
  :param conf: A config object.
278
306
  :param included:
279
307
  :param excluded:
@@ -338,7 +366,7 @@ class Loader(SimLoad):
338
366
  ) -> Iterator[tuple[str, DictData]]:
339
367
  """Override the find class method from the Simple Loader object.
340
368
 
341
- :param obj: A object that want to validate matching before return.
369
+ :param obj: An object that want to validate matching before return.
342
370
  :param included:
343
371
  :param excluded:
344
372
 
ddeutil/workflow/hook.py CHANGED
@@ -50,6 +50,7 @@ def tag(
50
50
  :param: name: A tag name for make different use-case of a function.
51
51
  :param: alias: A alias function name that keeping in registries. If this
52
52
  value does not supply, it will use original function name from __name__.
53
+
53
54
  :rtype: Callable[P, TagFunc]
54
55
  """
55
56
 
@@ -58,7 +59,7 @@ def tag(
58
59
  func.name = alias or func.__name__.replace("_", "-")
59
60
 
60
61
  @wraps(func)
61
- def wrapped(*args, **kwargs):
62
+ def wrapped(*args: P.args, **kwargs: P.kwargs) -> TagFunc:
62
63
  # NOTE: Able to do anything before calling hook function.
63
64
  return func(*args, **kwargs)
64
65
 
@@ -74,10 +75,11 @@ def make_registry(submodule: str) -> dict[str, Registry]:
74
75
  """Return registries of all functions that able to called with task.
75
76
 
76
77
  :param submodule: A module prefix that want to import registry.
78
+
77
79
  :rtype: dict[str, Registry]
78
80
  """
79
81
  rs: dict[str, Registry] = {}
80
- for module in config.regis_hook:
82
+ for module in config.regis_hook | ["ddeutil.vendors"]:
81
83
  # NOTE: try to sequential import task functions
82
84
  try:
83
85
  importer = import_module(f"{module}.{submodule}")
@@ -295,10 +295,7 @@ def str2template(
295
295
  return search_env_replace(value)
296
296
 
297
297
 
298
- def param2template(
299
- value: Any,
300
- params: DictData,
301
- ) -> Any:
298
+ def param2template(value: Any, params: DictData) -> Any:
302
299
  """Pass param to template string that can search by ``RE_CALLER`` regular
303
300
  expression.
304
301
 
@@ -884,7 +884,9 @@ class Workflow(BaseModel):
884
884
  :param run_id: A workflow running ID for this job execution.
885
885
  :type run_id: str | None (default: None)
886
886
  :param timeout: A workflow execution time out in second unit that use
887
- for limit time of execution and waiting job dependency.
887
+ for limit time of execution and waiting job dependency. This value
888
+ does not force stop the task that still running more than this limit
889
+ time.
888
890
  :type timeout: int (default: 0)
889
891
 
890
892
  :rtype: Result
@@ -1220,6 +1222,7 @@ class WorkflowTask:
1220
1222
  return queue
1221
1223
 
1222
1224
  def __repr__(self) -> str:
1225
+ """Override ___repr__ method."""
1223
1226
  return (
1224
1227
  f"{self.__class__.__name__}(alias={self.alias!r}, "
1225
1228
  f"workflow={self.workflow.name!r}, runner={self.runner!r}, "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.28
3
+ Version: 0.0.29
4
4
  Summary: Lightweight workflow orchestration
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.13
22
22
  Requires-Python: >=3.9.13
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: ddeutil==0.4.6
25
+ Requires-Dist: ddeutil>=0.4.6
26
26
  Requires-Dist: ddeutil-io[toml,yaml]>=0.2.3
27
27
  Requires-Dist: pydantic==2.10.6
28
28
  Requires-Dist: python-dotenv==1.0.1
@@ -55,6 +55,8 @@ the input parameters per use-case instead.
55
55
  This way I can handle a lot of logical workflows in our orgs with only metadata
56
56
  configuration. It called **Metadata Driven Data Workflow**.
57
57
 
58
+ ---
59
+
58
60
  **:pushpin: <u>Rules of This Workflow engine</u>**:
59
61
 
60
62
  1. The Minimum frequency unit of scheduling is **1 minute** :warning:
@@ -62,8 +64,14 @@ configuration. It called **Metadata Driven Data Workflow**.
62
64
  3. All parallel tasks inside workflow engine use Multi-Threading
63
65
  (Python 3.13 unlock GIL :unlock:)
64
66
 
67
+ ---
68
+
65
69
  **:memo: <u>Workflow Diagrams</u>**:
66
70
 
71
+ This diagram show where is this application run on the production infrastructure.
72
+ You will see that this application do only running code with stress-less which mean
73
+ you should to set the data layer separate this core program before run this application.
74
+
67
75
  ```mermaid
68
76
  flowchart LR
69
77
  subgraph Interface
@@ -215,8 +223,8 @@ and do not raise any error to you.
215
223
  | Name | Component | Default | Description |
216
224
  |:-----------------------------|:---------:|:----------------------------------|:-------------------------------------------------------------------------------------------------------------------|
217
225
  | **ROOT_PATH** | Core | `.` | The root path of the workflow application. |
218
- | **REGISTRY** | Core | `src` | List of importable string for the hook stage. |
219
- | **REGISTRY_FILTER** | Core | `ddeutil.workflow.utils` | List of importable string for the filter template. |
226
+ | **REGISTRY** | Core | `.` | List of importable string for the hook stage. |
227
+ | **REGISTRY_FILTER** | Core | `ddeutil.workflow.templates` | List of importable string for the filter template. |
220
228
  | **CONF_PATH** | Core | `conf` | The config path that keep all template `.yaml` files. |
221
229
  | **TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. |
222
230
  | **STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. |
@@ -1,25 +1,25 @@
1
- ddeutil/workflow/__about__.py,sha256=Fb6dv9Oq3jpI1oIsn3w_zS2izPiywO6k7tph7IMZ9mA,28
1
+ ddeutil/workflow/__about__.py,sha256=msVKiLUg4jRVo_KJlghj1cc0zwX_olhWZZkqcWYz16E,28
2
2
  ddeutil/workflow/__cron.py,sha256=uA8XcbY_GwA9rJSHaHUaXaJyGDObJN0ZeYlJSinL8y8,26880
3
- ddeutil/workflow/__init__.py,sha256=ATYXzGtLyq4LWCtJ-Odz36QSrLL7dKymVs8ziThOVOk,1582
4
- ddeutil/workflow/__types.py,sha256=Ia7f38kvL3NibwmRKi0wQ1ud_45Z-SojYGhNJwIqcu8,3713
5
- ddeutil/workflow/conf.py,sha256=eoge4fNy2bb5qIunyVDDxSSp2l9rDKYPiqdxSuYtKcs,16954
3
+ ddeutil/workflow/__init__.py,sha256=dghn2lFl3Own4Pyq7SFHu-FMymOgLontJ6aCfxea9h4,1606
4
+ ddeutil/workflow/__types.py,sha256=CK1jfzyHP9P-MB0ElhpJZ59ZFGJC9MkQuAop5739_9k,4304
5
+ ddeutil/workflow/conf.py,sha256=7lj_Im9jsa95fWUo19Q4-ZAcHa8Pu1HW-vaLgvrjNUM,17559
6
6
  ddeutil/workflow/cron.py,sha256=OLgniUxmrn65gzckk-uTmE2Pk1enJJyjYUKVeBbDQz0,7522
7
7
  ddeutil/workflow/exceptions.py,sha256=XUnpJSuxOyataClP0w_gpYjzn-NIwZK2BHro-J7Yw24,895
8
- ddeutil/workflow/hook.py,sha256=--4obgSCEImeRASSWIx-es3BctNmN3RVdhfKQ3O5AVk,5353
8
+ ddeutil/workflow/hook.py,sha256=vgiJVbgm4aVl-tt_HVhHn-65UXCojzGLapdOPkoX9QA,5406
9
9
  ddeutil/workflow/job.py,sha256=XcewyALsLYYq94ycF6mkj3Ydr6if683z7t1oBqEVInE,24290
10
10
  ddeutil/workflow/params.py,sha256=svCjmFgEhim8yFJVjZhFmKP8JqTDHQ5EPhwJHVuDGno,5289
11
11
  ddeutil/workflow/result.py,sha256=k4pcj5KjbEcEPymsEUXeGY4gyLMfPkMTO6YDrAtfk7Q,3408
12
12
  ddeutil/workflow/scheduler.py,sha256=OlrnBZvVttoymeY1g-on9icEMU729OWISJReeX3jAKI,20452
13
13
  ddeutil/workflow/stage.py,sha256=wn8CARTvFJY4ZK1SwjzH8sKoMRz_eIeSGUMgnDWNi6g,24031
14
- ddeutil/workflow/templates.py,sha256=Ray7YFCxXHrYoMv_0WOsXqhthfU1hePrBDdnPfjtcqo,10818
14
+ ddeutil/workflow/templates.py,sha256=bVU_8gnMQmdhhw3W28ZqwmpEaOx10Nx_aauqiLS0lqg,10807
15
15
  ddeutil/workflow/utils.py,sha256=8LTqpvRPfrEYxsxhwszk6GKkyjrswxnwF3r_9vE8szw,6059
16
- ddeutil/workflow/workflow.py,sha256=OHr-G57abR3OwynJiJb6DfoYpGeqXrifKcXOOroo8WI,42198
16
+ ddeutil/workflow/workflow.py,sha256=vuy0Q3ceslBth04qbslXrp5NAQQ7XfpOochwgORzQ4Q,42349
17
17
  ddeutil/workflow/api/__init__.py,sha256=F53NMBWtb9IKaDWkPU5KvybGGfKAcbehgn6TLBwHuuM,21
18
18
  ddeutil/workflow/api/api.py,sha256=hmH45GtpyZ-kbiqQNmnHgjwEiCiDDXLKTGvcNa5nFos,4041
19
19
  ddeutil/workflow/api/repeat.py,sha256=zyvsrXKk-3-_N8ZRZSki0Mueshugum2jtqctEOp9QSc,4927
20
20
  ddeutil/workflow/api/route.py,sha256=v96jNbgjM1cJ2MpVSRWs2kgRqF8DQElEBdRZrVFEpEw,8578
21
- ddeutil_workflow-0.0.28.dist-info/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
22
- ddeutil_workflow-0.0.28.dist-info/METADATA,sha256=9YcDUz85c3ka_-AIkeas4hDvOqYrzlW78vBiYAzj8GA,14535
23
- ddeutil_workflow-0.0.28.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
24
- ddeutil_workflow-0.0.28.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
25
- ddeutil_workflow-0.0.28.dist-info/RECORD,,
21
+ ddeutil_workflow-0.0.29.dist-info/LICENSE,sha256=nGFZ1QEhhhWeMHf9n99_fdt4vQaXS29xWKxt-OcLywk,1085
22
+ ddeutil_workflow-0.0.29.dist-info/METADATA,sha256=UXsjCGddPiksHRAByDfUcsYAsGIqAbL1qJ87uQKWCVQ,14801
23
+ ddeutil_workflow-0.0.29.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
24
+ ddeutil_workflow-0.0.29.dist-info/top_level.txt,sha256=m9M6XeSWDwt_yMsmH6gcOjHZVK5O0-vgtNBuncHjzW4,8
25
+ ddeutil_workflow-0.0.29.dist-info/RECORD,,