ddeutil-workflow 0.0.7__tar.gz → 0.0.8__tar.gz

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.
Files changed (49) hide show
  1. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/PKG-INFO +17 -92
  2. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/README.md +16 -91
  3. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/pyproject.toml +5 -1
  4. ddeutil_workflow-0.0.8/src/ddeutil/workflow/__about__.py +1 -0
  5. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/app.py +4 -0
  6. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/exceptions.py +1 -4
  7. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/log.py +49 -0
  8. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/pipeline.py +327 -167
  9. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/stage.py +191 -97
  10. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/utils.py +94 -16
  11. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil_workflow.egg-info/PKG-INFO +17 -92
  12. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil_workflow.egg-info/SOURCES.txt +4 -0
  13. ddeutil_workflow-0.0.8/tests/test_job.py +7 -0
  14. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_if.py +3 -3
  15. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_matrix.py +5 -5
  16. ddeutil_workflow-0.0.8/tests/test_pipeline_on_ready.py +26 -0
  17. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_run.py +1 -1
  18. ddeutil_workflow-0.0.8/tests/test_pipeline_run_raise.py +12 -0
  19. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_task.py +1 -1
  20. ddeutil_workflow-0.0.8/tests/test_stage.py +15 -0
  21. ddeutil_workflow-0.0.8/tests/test_utils.py +41 -0
  22. ddeutil_workflow-0.0.8/tests/test_utils_result.py +43 -0
  23. ddeutil_workflow-0.0.7/src/ddeutil/workflow/__about__.py +0 -1
  24. ddeutil_workflow-0.0.7/tests/test_utils.py +0 -8
  25. ddeutil_workflow-0.0.7/tests/test_utils_result.py +0 -22
  26. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/LICENSE +0 -0
  27. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/setup.cfg +0 -0
  28. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/__init__.py +0 -0
  29. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/__types.py +0 -0
  30. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/api.py +0 -0
  31. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/loader.py +0 -0
  32. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/on.py +0 -0
  33. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/repeat.py +0 -0
  34. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/route.py +0 -0
  35. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil/workflow/scheduler.py +0 -0
  36. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
  37. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil_workflow.egg-info/requires.txt +0 -0
  38. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
  39. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test__conf_exist.py +0 -0
  40. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test__local_and_global.py +0 -0
  41. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test__regex.py +0 -0
  42. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_on.py +0 -0
  43. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline.py +0 -0
  44. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_desc.py +0 -0
  45. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_on.py +0 -0
  46. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_pipeline_params.py +0 -0
  47. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_scheduler.py +0 -0
  48. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_stage_trigger.py +0 -0
  49. {ddeutil_workflow-0.0.7 → ddeutil_workflow-0.0.8}/tests/test_utils_param2template.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.7
3
+ Version: 0.0.8
4
4
  Summary: Data Developer & Engineer Workflow Utility Objects
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -79,13 +79,10 @@ pip install ddeutil-workflow
79
79
  This project need `ddeutil-io` extension namespace packages. If you want to install
80
80
  this package with application add-ons, you should add `app` in installation;
81
81
 
82
- ```shell
83
- pip install ddeutil-workflow[app]
84
- ```
85
-
86
- ```shell
87
- pip install ddeutil-workflow[api]
88
- ```
82
+ | Usecase | Install Optional |
83
+ |--------------------|---------------------------|
84
+ | Scheduler Service | `ddeutil-workflow[app]` |
85
+ | FastAPI Server | `ddeutil-workflow[api]` |
89
86
 
90
87
  ## Getting Started
91
88
 
@@ -168,11 +165,12 @@ use-case.
168
165
  > I recommend you to use `task` stage for all actions that you want to do with
169
166
  > pipeline object.
170
167
 
171
- ### Python & Bash
172
-
173
168
  ```yaml
174
169
  run_py_local:
175
170
  type: pipeline.Pipeline
171
+ on:
172
+ - cronjob: '* * * * *'
173
+ timezone: "Asia/Bangkok"
176
174
  params:
177
175
  author-run: str
178
176
  run-date: datetime
@@ -182,12 +180,11 @@ run_py_local:
182
180
  - name: "Printing Information"
183
181
  id: define-func
184
182
  run: |
185
- x = '${{ params.author-run }}'
186
- print(f'Hello {x}')
183
+ x = '${{ params.run-date | fmt("%Y%m%d") }}'
184
+ print(f'Hello at {x}')
187
185
 
188
186
  def echo(name: str):
189
187
  print(f'Hello {name}')
190
-
191
188
  - name: "Run Sequence and use var from Above"
192
189
  vars:
193
190
  x: ${{ params.author-run }}
@@ -195,7 +192,6 @@ run_py_local:
195
192
  print(f'Receive x from above with {x}')
196
193
  # Change x value
197
194
  x: int = 1
198
-
199
195
  - name: "Call Function"
200
196
  vars:
201
197
  echo: ${{ stages.define-func.outputs.echo }}
@@ -210,93 +206,23 @@ run_py_local:
210
206
  ```
211
207
 
212
208
  ```python
209
+ from datetime import datetime
213
210
  from ddeutil.workflow.pipeline import Pipeline
214
211
 
215
- pipe = Pipeline.from_loader(name='run_py_local', externals={})
216
- pipe.execute(params={'author-run': 'Local Workflow', 'run-date': '2024-01-01'})
212
+ pipe: Pipeline = Pipeline.from_loader(name='run_py_local', externals={})
213
+ pipe.execute(params={
214
+ 'author-run': 'Local Workflow',
215
+ 'run-date': datetime(2024, 1, 1),
216
+ })
217
217
  ```
218
218
 
219
219
  ```shell
220
- > Hello Local Workflow
220
+ > Hello at 20240101
221
221
  > Receive x from above with Local Workflow
222
222
  > Hello Caller
223
223
  > Hello World from Shell
224
224
  ```
225
225
 
226
- ### Hook (Extract & Load)
227
-
228
- ```yaml
229
- pipe_el_pg_to_lake:
230
- type: pipeline.Pipeline
231
- params:
232
- run-date: datetime
233
- author-email: str
234
- jobs:
235
- extract-load:
236
- stages:
237
- - name: "Extract Load from Postgres to Lake"
238
- id: extract-load
239
- uses: tasks/postgres-to-delta@polars
240
- with:
241
- source:
242
- conn: conn_postgres_url
243
- query: |
244
- select * from ${{ params.name }}
245
- where update_date = '${{ params.datetime }}'
246
- sink:
247
- conn: conn_az_lake
248
- endpoint: "/${{ params.name }}"
249
- ```
250
-
251
- Implement hook:
252
-
253
- ```python
254
- from ddeutil.workflow.utils import tag
255
-
256
- @tag('polars', alias='postgres-to-delta')
257
- def postgres_to_delta(source, sink):
258
- return {
259
- "source": source, "sink": sink
260
- }
261
- ```
262
-
263
- ### Hook (Transform)
264
-
265
- ```yaml
266
- pipeline_hook_mssql_proc:
267
- type: pipeline.Pipeline
268
- params:
269
- run_date: datetime
270
- sp_name: str
271
- source_name: str
272
- target_name: str
273
- jobs:
274
- transform:
275
- stages:
276
- - name: "Transform Data in MS SQL Server"
277
- id: transform
278
- uses: tasks/mssql-proc@odbc
279
- with:
280
- exec: ${{ params.sp_name }}
281
- params:
282
- run_mode: "T"
283
- run_date: ${{ params.run_date }}
284
- source: ${{ params.source_name }}
285
- target: ${{ params.target_name }}
286
- ```
287
-
288
- Implement hook:
289
-
290
- ```python
291
- from ddeutil.workflow.utils import tag
292
-
293
- @tag('odbc', alias='mssql-proc')
294
- def odbc_mssql_procedure(_exec: str, params: dict):
295
- return {
296
- "exec": _exec, "params": params
297
- }
298
- ```
299
-
300
226
  ## Configuration
301
227
 
302
228
  ```bash
@@ -306,7 +232,6 @@ export WORKFLOW_CORE_REGISTRY_FILTER=ddeutil.workflow.utils
306
232
  export WORKFLOW_CORE_PATH_CONF=conf
307
233
  export WORKFLOW_CORE_TIMEZONE=Asia/Bangkok
308
234
  export WORKFLOW_CORE_DEFAULT_STAGE_ID=true
309
-
310
235
  export WORKFLOW_CORE_MAX_PIPELINE_POKING=4
311
236
  export WORKFLOW_CORE_MAX_JOB_PARALLEL=2
312
237
  ```
@@ -46,13 +46,10 @@ pip install ddeutil-workflow
46
46
  This project need `ddeutil-io` extension namespace packages. If you want to install
47
47
  this package with application add-ons, you should add `app` in installation;
48
48
 
49
- ```shell
50
- pip install ddeutil-workflow[app]
51
- ```
52
-
53
- ```shell
54
- pip install ddeutil-workflow[api]
55
- ```
49
+ | Usecase | Install Optional |
50
+ |--------------------|---------------------------|
51
+ | Scheduler Service | `ddeutil-workflow[app]` |
52
+ | FastAPI Server | `ddeutil-workflow[api]` |
56
53
 
57
54
  ## Getting Started
58
55
 
@@ -135,11 +132,12 @@ use-case.
135
132
  > I recommend you to use `task` stage for all actions that you want to do with
136
133
  > pipeline object.
137
134
 
138
- ### Python & Bash
139
-
140
135
  ```yaml
141
136
  run_py_local:
142
137
  type: pipeline.Pipeline
138
+ on:
139
+ - cronjob: '* * * * *'
140
+ timezone: "Asia/Bangkok"
143
141
  params:
144
142
  author-run: str
145
143
  run-date: datetime
@@ -149,12 +147,11 @@ run_py_local:
149
147
  - name: "Printing Information"
150
148
  id: define-func
151
149
  run: |
152
- x = '${{ params.author-run }}'
153
- print(f'Hello {x}')
150
+ x = '${{ params.run-date | fmt("%Y%m%d") }}'
151
+ print(f'Hello at {x}')
154
152
 
155
153
  def echo(name: str):
156
154
  print(f'Hello {name}')
157
-
158
155
  - name: "Run Sequence and use var from Above"
159
156
  vars:
160
157
  x: ${{ params.author-run }}
@@ -162,7 +159,6 @@ run_py_local:
162
159
  print(f'Receive x from above with {x}')
163
160
  # Change x value
164
161
  x: int = 1
165
-
166
162
  - name: "Call Function"
167
163
  vars:
168
164
  echo: ${{ stages.define-func.outputs.echo }}
@@ -177,93 +173,23 @@ run_py_local:
177
173
  ```
178
174
 
179
175
  ```python
176
+ from datetime import datetime
180
177
  from ddeutil.workflow.pipeline import Pipeline
181
178
 
182
- pipe = Pipeline.from_loader(name='run_py_local', externals={})
183
- pipe.execute(params={'author-run': 'Local Workflow', 'run-date': '2024-01-01'})
179
+ pipe: Pipeline = Pipeline.from_loader(name='run_py_local', externals={})
180
+ pipe.execute(params={
181
+ 'author-run': 'Local Workflow',
182
+ 'run-date': datetime(2024, 1, 1),
183
+ })
184
184
  ```
185
185
 
186
186
  ```shell
187
- > Hello Local Workflow
187
+ > Hello at 20240101
188
188
  > Receive x from above with Local Workflow
189
189
  > Hello Caller
190
190
  > Hello World from Shell
191
191
  ```
192
192
 
193
- ### Hook (Extract & Load)
194
-
195
- ```yaml
196
- pipe_el_pg_to_lake:
197
- type: pipeline.Pipeline
198
- params:
199
- run-date: datetime
200
- author-email: str
201
- jobs:
202
- extract-load:
203
- stages:
204
- - name: "Extract Load from Postgres to Lake"
205
- id: extract-load
206
- uses: tasks/postgres-to-delta@polars
207
- with:
208
- source:
209
- conn: conn_postgres_url
210
- query: |
211
- select * from ${{ params.name }}
212
- where update_date = '${{ params.datetime }}'
213
- sink:
214
- conn: conn_az_lake
215
- endpoint: "/${{ params.name }}"
216
- ```
217
-
218
- Implement hook:
219
-
220
- ```python
221
- from ddeutil.workflow.utils import tag
222
-
223
- @tag('polars', alias='postgres-to-delta')
224
- def postgres_to_delta(source, sink):
225
- return {
226
- "source": source, "sink": sink
227
- }
228
- ```
229
-
230
- ### Hook (Transform)
231
-
232
- ```yaml
233
- pipeline_hook_mssql_proc:
234
- type: pipeline.Pipeline
235
- params:
236
- run_date: datetime
237
- sp_name: str
238
- source_name: str
239
- target_name: str
240
- jobs:
241
- transform:
242
- stages:
243
- - name: "Transform Data in MS SQL Server"
244
- id: transform
245
- uses: tasks/mssql-proc@odbc
246
- with:
247
- exec: ${{ params.sp_name }}
248
- params:
249
- run_mode: "T"
250
- run_date: ${{ params.run_date }}
251
- source: ${{ params.source_name }}
252
- target: ${{ params.target_name }}
253
- ```
254
-
255
- Implement hook:
256
-
257
- ```python
258
- from ddeutil.workflow.utils import tag
259
-
260
- @tag('odbc', alias='mssql-proc')
261
- def odbc_mssql_procedure(_exec: str, params: dict):
262
- return {
263
- "exec": _exec, "params": params
264
- }
265
- ```
266
-
267
193
  ## Configuration
268
194
 
269
195
  ```bash
@@ -273,7 +199,6 @@ export WORKFLOW_CORE_REGISTRY_FILTER=ddeutil.workflow.utils
273
199
  export WORKFLOW_CORE_PATH_CONF=conf
274
200
  export WORKFLOW_CORE_TIMEZONE=Asia/Bangkok
275
201
  export WORKFLOW_CORE_DEFAULT_STAGE_ID=true
276
-
277
202
  export WORKFLOW_CORE_MAX_PIPELINE_POKING=4
278
203
  export WORKFLOW_CORE_MAX_JOB_PARALLEL=2
279
204
  ```
@@ -62,6 +62,10 @@ concurrency = ["thread", "multiprocessing"]
62
62
  source = ["ddeutil.workflow", "tests"]
63
63
  omit = [
64
64
  "scripts/",
65
+ "src/ddeutil/workflow/api.py",
66
+ "src/ddeutil/workflow/app.py",
67
+ "src/ddeutil/workflow/repeat.py",
68
+ "src/ddeutil/workflow/route.py",
65
69
  "tests/utils.py",
66
70
  "tests/tasks/dummy.py",
67
71
  ]
@@ -79,7 +83,7 @@ addopts = [
79
83
  filterwarnings = ["error"]
80
84
  log_cli = true
81
85
  log_cli_level = "DEBUG"
82
- log_cli_format = "%(asctime)s [%(levelname)-7s] %(message)-75s (%(filename)s:%(lineno)s)"
86
+ log_cli_format = "%(asctime)s [%(levelname)-7s] %(message)-100s (%(filename)s:%(lineno)s)"
83
87
  log_cli_date_format = "%Y%m%d %H:%M:%S"
84
88
 
85
89
  [tool.black]
@@ -0,0 +1 @@
1
+ __version__: str = "0.0.8"
@@ -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
+ from __future__ import annotations
7
+
6
8
  import functools
7
9
  import time
8
10
 
@@ -10,6 +12,8 @@ import schedule
10
12
 
11
13
 
12
14
  def catch_exceptions(cancel_on_failure=False):
15
+ """Catch exception error from scheduler job."""
16
+
13
17
  def catch_exceptions_decorator(job_func):
14
18
  @functools.wraps(job_func)
15
19
  def wrapper(*args, **kwargs):
@@ -3,9 +3,6 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- """
7
- Define Errors Object for Node package
8
- """
9
6
  from __future__ import annotations
10
7
 
11
8
 
@@ -24,4 +21,4 @@ class JobException(WorkflowException): ...
24
21
  class PipelineException(WorkflowException): ...
25
22
 
26
23
 
27
- class ParamValueException(ValueError): ...
24
+ class ParamValueException(WorkflowException): ...
@@ -6,11 +6,16 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import logging
9
+ from datetime import datetime
9
10
  from functools import lru_cache
11
+ from typing import Union
10
12
 
13
+ from pydantic import BaseModel, Field
11
14
  from rich.console import Console
12
15
  from rich.logging import RichHandler
13
16
 
17
+ from .__types import DictData
18
+
14
19
  console = Console(color_system="256", width=200, style="blue")
15
20
 
16
21
 
@@ -28,3 +33,47 @@ def get_logger(module_name):
28
33
  logger.addHandler(handler)
29
34
  logger.setLevel(logging.DEBUG)
30
35
  return logger
36
+
37
+
38
+ class BaseLog(BaseModel):
39
+ """Base logging model."""
40
+
41
+ parent_id: str
42
+ id: str
43
+ input: DictData
44
+ output: DictData
45
+ update_time: datetime = Field(default_factory=datetime.now)
46
+
47
+
48
+ class StageLog(BaseLog): ...
49
+
50
+
51
+ class JobLog(BaseLog): ...
52
+
53
+
54
+ class PipelineLog(BaseLog): ...
55
+
56
+
57
+ Log = Union[
58
+ StageLog,
59
+ JobLog,
60
+ PipelineLog,
61
+ ]
62
+
63
+
64
+ def push_log_memory(log: DictData):
65
+ """Push message log to globals log queue."""
66
+ print(log)
67
+
68
+
69
+ LOGS_REGISTRY = {
70
+ "memory": push_log_memory,
71
+ }
72
+
73
+
74
+ def push_log(log: DictData, mode: str = "memory"):
75
+ return LOGS_REGISTRY[mode](log)
76
+
77
+
78
+ def save_log():
79
+ """Save log that push to queue to target saving"""