ddeutil-workflow 0.0.42__tar.gz → 0.0.43__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 (67) hide show
  1. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/PKG-INFO +29 -29
  2. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/README.md +27 -27
  3. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/pyproject.toml +2 -1
  4. ddeutil_workflow-0.0.43/src/ddeutil/workflow/__about__.py +1 -0
  5. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/__init__.py +5 -1
  6. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/exceptions.py +13 -3
  7. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/job.py +22 -32
  8. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/params.py +77 -18
  9. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/result.py +36 -8
  10. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/scheduler.py +6 -9
  11. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/stages.py +51 -81
  12. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/workflow.py +16 -16
  13. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/PKG-INFO +29 -29
  14. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/requires.txt +1 -1
  15. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job.py +3 -3
  16. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_params.py +27 -0
  17. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_stage_handler_exec.py +78 -11
  18. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec.py +30 -0
  19. ddeutil_workflow-0.0.42/src/ddeutil/workflow/__about__.py +0 -1
  20. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/LICENSE +0 -0
  21. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/setup.cfg +0 -0
  22. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/__cron.py +0 -0
  23. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/__types.py +0 -0
  24. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/__init__.py +0 -0
  25. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/api.py +0 -0
  26. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/log.py +0 -0
  27. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/repeat.py +0 -0
  28. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
  29. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/job.py +0 -0
  30. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/logs.py +0 -0
  31. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
  32. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
  33. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/conf.py +0 -0
  34. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/cron.py +0 -0
  35. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/logs.py +0 -0
  36. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/reusables.py +0 -0
  37. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/utils.py +0 -0
  38. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/SOURCES.txt +0 -0
  39. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
  40. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
  41. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test__cron.py +0 -0
  42. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test__regex.py +0 -0
  43. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_conf.py +0 -0
  44. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_cron_on.py +0 -0
  45. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job_exec.py +0 -0
  46. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job_exec_strategy.py +0 -0
  47. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job_strategy.py +0 -0
  48. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_logs_audit.py +0 -0
  49. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_logs_trace.py +0 -0
  50. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_release.py +0 -0
  51. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_release_queue.py +0 -0
  52. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_result.py +0 -0
  53. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_reusables_call_tag.py +0 -0
  54. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_reusables_template.py +0 -0
  55. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_reusables_template_filter.py +0 -0
  56. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule.py +0 -0
  57. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule_pending.py +0 -0
  58. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule_tasks.py +0 -0
  59. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule_workflow.py +0 -0
  60. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_scheduler_control.py +0 -0
  61. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_stage.py +0 -0
  62. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_utils.py +0 -0
  63. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow.py +0 -0
  64. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec_job.py +0 -0
  65. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec_poke.py +0 -0
  66. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec_release.py +0 -0
  67. {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_task.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.42
3
+ Version: 0.0.43
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[checksum]>=0.4.6
26
26
  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
@@ -212,7 +212,7 @@ execution time such as `run-date` should change base on that workflow running da
212
212
  ```python
213
213
  from ddeutil.workflow import Workflow, Result
214
214
 
215
- workflow: Workflow = Workflow.from_loader('run-py-local')
215
+ workflow: Workflow = Workflow.from_conf('run-py-local')
216
216
  result: Result = workflow.execute(
217
217
  params={"source-extract": "USD-THB", "asat-dt": "2024-01-01"}
218
218
  )
@@ -246,7 +246,7 @@ from ddeutil.workflow import Schedule
246
246
 
247
247
  (
248
248
  Schedule
249
- .from_loader("schedule-run-local-wf")
249
+ .from_conf("schedule-run-local-wf")
250
250
  .pending(stop=None)
251
251
  )
252
252
  ```
@@ -261,31 +261,31 @@ it will use default value and do not raise any error to you.
261
261
  > The config value that you will set on the environment should combine with
262
262
  > prefix, component, and name which is `WORKFLOW_{component}_{name}` (Upper case).
263
263
 
264
- | Name | Component | Default | Description |
265
- |:-----------------------------|:---------:|:--------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|
266
- | **ROOT_PATH** | Core | `.` | The root path of the workflow application. |
267
- | **REGISTRY_CALLER** | Core | `.` | List of importable string for the call stage. |
268
- | **REGISTRY_FILTER** | Core | `ddeutil.workflow.templates` | List of importable string for the filter template. |
269
- | **CONF_PATH** | Core | `conf` | The config path that keep all template `.yaml` files. |
270
- | **TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. |
271
- | **STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. |
272
- | **STAGE_RAISE_ERROR** | Core | `false` | A flag that all stage raise StageException from stage execution. |
273
- | **JOB_DEFAULT_ID** | Core | `false` | A flag that enable default job ID that use for catch an execution output. The ID that use will be sequence number. |
274
- | **JOB_RAISE_ERROR** | Core | `true` | A flag that all job raise JobException from job strategy execution. |
275
- | **MAX_CRON_PER_WORKFLOW** | Core | `5` | |
276
- | **MAX_QUEUE_COMPLETE_HIST** | Core | `16` | |
277
- | **GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. |
278
- | **TRACE_PATH** | Log | `./logs` | The log path of the workflow saving log. |
279
- | **DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. |
280
- | **FORMAT** | Log | `%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d,%(thread)-5d) [%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)` | |
281
- | **FORMAT_FILE** | Log | `{datetime} ({process:5d}, {thread:5d}) {message:120s} ({filename}:{lineno})` | |
282
- | **DATETIME_FORMAT** | Log | `%Y-%m-%d %H:%M:%S` | |
283
- | **TRACE_ENABLE_WRITE** | Log | `false` | |
284
- | **AUDIT_PATH** | Log | `./audits` | |
285
- | **AUDIT_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. |
286
- | **MAX_PROCESS** | App | `2` | The maximum process worker number that run in scheduler app module. |
287
- | **MAX_SCHEDULE_PER_PROCESS** | App | `100` | A schedule per process that run parallel. |
288
- | **STOP_BOUNDARY_DELTA** | App | `'{"minutes": 5, "seconds": 20}'` | A time delta value that use to stop scheduler app in json string format. |
264
+ | Name | Component | Default | Override | Description |
265
+ |:-----------------------------|:---------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:|:-------------------------------------------------------------------------------------------------------------------|
266
+ | **ROOT_PATH** | Core | `.` | No | The root path of the workflow application. |
267
+ | **REGISTRY_CALLER** | Core | `.` | Yes | List of importable string for the call stage. |
268
+ | **REGISTRY_FILTER** | Core | `ddeutil.workflow.templates` | Yes | List of importable string for the filter template. |
269
+ | **CONF_PATH** | Core | `conf` | No | The config path that keep all template `.yaml` files. |
270
+ | **TIMEZONE** | Core | `Asia/Bangkok` | No | A Timezone string value that will pass to `ZoneInfo` object. |
271
+ | **STAGE_DEFAULT_ID** | Core | `true` | No | A flag that enable default stage ID that use for catch an execution output. |
272
+ | **STAGE_RAISE_ERROR** | Core | `false` | Yes | A flag that all stage raise StageException from stage execution. |
273
+ | **JOB_DEFAULT_ID** | Core | `false` | No | A flag that enable default job ID that use for catch an execution output. The ID that use will be sequence number. |
274
+ | **JOB_RAISE_ERROR** | Core | `true` | Yes | A flag that all job raise JobException from job strategy execution. |
275
+ | **MAX_CRON_PER_WORKFLOW** | Core | `5` | No | |
276
+ | **MAX_QUEUE_COMPLETE_HIST** | Core | `16` | No | |
277
+ | **GENERATE_ID_SIMPLE_MODE** | Core | `true` | No | A flog that enable generating ID with `md5` algorithm. |
278
+ | **DEBUG_MODE** | Log | `true` | No | A flag that enable logging with debug level mode. |
279
+ | **FORMAT** | Log | `%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d,%(thread)-5d) [%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)` | No | |
280
+ | **FORMAT_FILE** | Log | `{datetime} ({process:5d}, {thread:5d}) {message:120s} ({filename}:{lineno})` | No | |
281
+ | **DATETIME_FORMAT** | Log | `%Y-%m-%d %H:%M:%S` | No | |
282
+ | **TRACE_PATH** | Log | `./logs` | No | The log path of the workflow saving log. |
283
+ | **TRACE_ENABLE_WRITE** | Log | `false` | No | |
284
+ | **AUDIT_PATH** | Log | `./audits` | No | |
285
+ | **AUDIT_ENABLE_WRITE** | Log | `true` | No | A flag that enable logging object saving log to its destination. |
286
+ | **MAX_PROCESS** | App | `2` | No | The maximum process worker number that run in scheduler app module. |
287
+ | **MAX_SCHEDULE_PER_PROCESS** | App | `100` | No | A schedule per process that run parallel. |
288
+ | **STOP_BOUNDARY_DELTA** | App | `'{"minutes": 5, "seconds": 20}'` | No | A time delta value that use to stop scheduler app in json string format. |
289
289
 
290
290
  **API Application**:
291
291
 
@@ -168,7 +168,7 @@ execution time such as `run-date` should change base on that workflow running da
168
168
  ```python
169
169
  from ddeutil.workflow import Workflow, Result
170
170
 
171
- workflow: Workflow = Workflow.from_loader('run-py-local')
171
+ workflow: Workflow = Workflow.from_conf('run-py-local')
172
172
  result: Result = workflow.execute(
173
173
  params={"source-extract": "USD-THB", "asat-dt": "2024-01-01"}
174
174
  )
@@ -202,7 +202,7 @@ from ddeutil.workflow import Schedule
202
202
 
203
203
  (
204
204
  Schedule
205
- .from_loader("schedule-run-local-wf")
205
+ .from_conf("schedule-run-local-wf")
206
206
  .pending(stop=None)
207
207
  )
208
208
  ```
@@ -217,31 +217,31 @@ it will use default value and do not raise any error to you.
217
217
  > The config value that you will set on the environment should combine with
218
218
  > prefix, component, and name which is `WORKFLOW_{component}_{name}` (Upper case).
219
219
 
220
- | Name | Component | Default | Description |
221
- |:-----------------------------|:---------:|:--------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|
222
- | **ROOT_PATH** | Core | `.` | The root path of the workflow application. |
223
- | **REGISTRY_CALLER** | Core | `.` | List of importable string for the call stage. |
224
- | **REGISTRY_FILTER** | Core | `ddeutil.workflow.templates` | List of importable string for the filter template. |
225
- | **CONF_PATH** | Core | `conf` | The config path that keep all template `.yaml` files. |
226
- | **TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. |
227
- | **STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. |
228
- | **STAGE_RAISE_ERROR** | Core | `false` | A flag that all stage raise StageException from stage execution. |
229
- | **JOB_DEFAULT_ID** | Core | `false` | A flag that enable default job ID that use for catch an execution output. The ID that use will be sequence number. |
230
- | **JOB_RAISE_ERROR** | Core | `true` | A flag that all job raise JobException from job strategy execution. |
231
- | **MAX_CRON_PER_WORKFLOW** | Core | `5` | |
232
- | **MAX_QUEUE_COMPLETE_HIST** | Core | `16` | |
233
- | **GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. |
234
- | **TRACE_PATH** | Log | `./logs` | The log path of the workflow saving log. |
235
- | **DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. |
236
- | **FORMAT** | Log | `%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d,%(thread)-5d) [%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)` | |
237
- | **FORMAT_FILE** | Log | `{datetime} ({process:5d}, {thread:5d}) {message:120s} ({filename}:{lineno})` | |
238
- | **DATETIME_FORMAT** | Log | `%Y-%m-%d %H:%M:%S` | |
239
- | **TRACE_ENABLE_WRITE** | Log | `false` | |
240
- | **AUDIT_PATH** | Log | `./audits` | |
241
- | **AUDIT_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. |
242
- | **MAX_PROCESS** | App | `2` | The maximum process worker number that run in scheduler app module. |
243
- | **MAX_SCHEDULE_PER_PROCESS** | App | `100` | A schedule per process that run parallel. |
244
- | **STOP_BOUNDARY_DELTA** | App | `'{"minutes": 5, "seconds": 20}'` | A time delta value that use to stop scheduler app in json string format. |
220
+ | Name | Component | Default | Override | Description |
221
+ |:-----------------------------|:---------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:|:-------------------------------------------------------------------------------------------------------------------|
222
+ | **ROOT_PATH** | Core | `.` | No | The root path of the workflow application. |
223
+ | **REGISTRY_CALLER** | Core | `.` | Yes | List of importable string for the call stage. |
224
+ | **REGISTRY_FILTER** | Core | `ddeutil.workflow.templates` | Yes | List of importable string for the filter template. |
225
+ | **CONF_PATH** | Core | `conf` | No | The config path that keep all template `.yaml` files. |
226
+ | **TIMEZONE** | Core | `Asia/Bangkok` | No | A Timezone string value that will pass to `ZoneInfo` object. |
227
+ | **STAGE_DEFAULT_ID** | Core | `true` | No | A flag that enable default stage ID that use for catch an execution output. |
228
+ | **STAGE_RAISE_ERROR** | Core | `false` | Yes | A flag that all stage raise StageException from stage execution. |
229
+ | **JOB_DEFAULT_ID** | Core | `false` | No | A flag that enable default job ID that use for catch an execution output. The ID that use will be sequence number. |
230
+ | **JOB_RAISE_ERROR** | Core | `true` | Yes | A flag that all job raise JobException from job strategy execution. |
231
+ | **MAX_CRON_PER_WORKFLOW** | Core | `5` | No | |
232
+ | **MAX_QUEUE_COMPLETE_HIST** | Core | `16` | No | |
233
+ | **GENERATE_ID_SIMPLE_MODE** | Core | `true` | No | A flog that enable generating ID with `md5` algorithm. |
234
+ | **DEBUG_MODE** | Log | `true` | No | A flag that enable logging with debug level mode. |
235
+ | **FORMAT** | Log | `%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d,%(thread)-5d) [%(levelname)-7s] %(message)-120s (%(filename)s:%(lineno)s)` | No | |
236
+ | **FORMAT_FILE** | Log | `{datetime} ({process:5d}, {thread:5d}) {message:120s} ({filename}:{lineno})` | No | |
237
+ | **DATETIME_FORMAT** | Log | `%Y-%m-%d %H:%M:%S` | No | |
238
+ | **TRACE_PATH** | Log | `./logs` | No | The log path of the workflow saving log. |
239
+ | **TRACE_ENABLE_WRITE** | Log | `false` | No | |
240
+ | **AUDIT_PATH** | Log | `./audits` | No | |
241
+ | **AUDIT_ENABLE_WRITE** | Log | `true` | No | A flag that enable logging object saving log to its destination. |
242
+ | **MAX_PROCESS** | App | `2` | No | The maximum process worker number that run in scheduler app module. |
243
+ | **MAX_SCHEDULE_PER_PROCESS** | App | `100` | No | A schedule per process that run parallel. |
244
+ | **STOP_BOUNDARY_DELTA** | App | `'{"minutes": 5, "seconds": 20}'` | No | A time delta value that use to stop scheduler app in json string format. |
245
245
 
246
246
  **API Application**:
247
247
 
@@ -26,7 +26,7 @@ classifiers = [
26
26
  ]
27
27
  requires-python = ">=3.9.13"
28
28
  dependencies = [
29
- "ddeutil>=0.4.6",
29
+ "ddeutil[checksum]>=0.4.6",
30
30
  "ddeutil-io[yaml,toml]>=0.2.10",
31
31
  "pydantic==2.11.1",
32
32
  "python-dotenv==1.1.0",
@@ -99,6 +99,7 @@ exclude_lines = [
99
99
 
100
100
  [tool.pytest.ini_options]
101
101
  pythonpath = ["src"]
102
+ asyncio_default_fixture_loop_scope = "fuction"
102
103
  # NOTE: You can deslect multiple markers by '-m "not (poke or api)"'
103
104
  markers = [
104
105
  "poke: marks tests as slow by poking (deselect with '-m \"not poke\"')",
@@ -0,0 +1 @@
1
+ __version__: str = "0.0.43"
@@ -4,7 +4,7 @@
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
6
  from .__cron import CronJob, CronRunner
7
- from .__types import Re
7
+ from .__types import DictData, DictStr, Matrix, Re, TupleStr
8
8
  from .conf import (
9
9
  Config,
10
10
  Loader,
@@ -47,6 +47,10 @@ from .params import (
47
47
  StrParam,
48
48
  )
49
49
  from .result import (
50
+ FAILED,
51
+ SKIP,
52
+ SUCCESS,
53
+ WAIT,
50
54
  Result,
51
55
  Status,
52
56
  )
@@ -9,10 +9,20 @@ annotate for handle error only.
9
9
  """
10
10
  from __future__ import annotations
11
11
 
12
- from typing import Any
12
+ from typing import TypedDict
13
13
 
14
+ ErrorData = TypedDict(
15
+ "ErrorData",
16
+ {
17
+ "class": Exception,
18
+ "name": str,
19
+ "message": str,
20
+ },
21
+ )
14
22
 
15
- def to_dict(exception: Exception) -> dict[str, Any]: # pragma: no cov
23
+
24
+ def to_dict(exception: Exception) -> ErrorData: # pragma: no cov
25
+ """Create dict data from exception instance."""
16
26
  return {
17
27
  "class": exception,
18
28
  "name": exception.__class__.__name__,
@@ -22,7 +32,7 @@ def to_dict(exception: Exception) -> dict[str, Any]: # pragma: no cov
22
32
 
23
33
  class BaseWorkflowException(Exception):
24
34
 
25
- def to_dict(self) -> dict[str, Any]:
35
+ def to_dict(self) -> ErrorData:
26
36
  return to_dict(self)
27
37
 
28
38
 
@@ -39,7 +39,7 @@ from .exceptions import (
39
39
  StageException,
40
40
  UtilException,
41
41
  )
42
- from .result import Result, Status
42
+ from .result import FAILED, SKIP, SUCCESS, WAIT, Result, Status
43
43
  from .reusables import has_template, param2template
44
44
  from .stages import Stage
45
45
  from .utils import cross_product, filter_func, gen_id
@@ -51,7 +51,6 @@ __all__: TupleStr = (
51
51
  "Strategy",
52
52
  "Job",
53
53
  "TriggerRules",
54
- "TriggerState",
55
54
  "RunsOn",
56
55
  "RunsOnLocal",
57
56
  "RunsOnSelfHosted",
@@ -206,16 +205,6 @@ class TriggerRules(str, Enum):
206
205
  none_skipped: str = "none_skipped"
207
206
 
208
207
 
209
- class TriggerState(str, Enum):
210
- waiting: str = "waiting"
211
- passed: str = "passed"
212
- skipped: str = "skipped"
213
- failed: str = "failed"
214
-
215
- def is_waiting(self):
216
- return self.value == "waiting"
217
-
218
-
219
208
  class RunsOnType(str, Enum):
220
209
  """Runs-On enum object."""
221
210
 
@@ -407,30 +396,31 @@ class Job(BaseModel):
407
396
  def check_needs(
408
397
  self,
409
398
  jobs: dict[str, Any],
410
- ) -> TriggerState: # pragma: no cov
411
- """Return True if job's need exists in an input list of job's ID.
399
+ ) -> Status: # pragma: no cov
400
+ """Return Status enum for checking job's need trigger logic in an
401
+ input list of job's ID.
412
402
 
413
403
  :param jobs: A mapping of job ID and result context.
414
404
 
415
405
  :raise NotImplementedError: If the job trigger rule out of scope.
416
406
 
417
- :rtype: TriggerState
407
+ :rtype: Status
418
408
  """
419
409
  if not self.needs:
420
- return TriggerState.passed
410
+ return SUCCESS
421
411
 
422
- def make_return(result: bool) -> TriggerState:
423
- return TriggerState.passed if result else TriggerState.failed
412
+ def make_return(result: bool) -> Status:
413
+ return SUCCESS if result else FAILED
424
414
 
425
415
  need_exist: dict[str, Any] = {
426
416
  need: jobs[need] for need in self.needs if need in jobs
427
417
  }
428
418
  if len(need_exist) != len(self.needs):
429
- return TriggerState.waiting
419
+ return WAIT
430
420
  elif all("skipped" in need_exist[job] for job in need_exist):
431
- return TriggerState.skipped
421
+ return SKIP
432
422
  elif self.trigger_rule == TriggerRules.all_done:
433
- return TriggerState.passed
423
+ return SUCCESS
434
424
  elif self.trigger_rule == TriggerRules.all_success:
435
425
  rs = all(
436
426
  k not in need_exist[job]
@@ -674,7 +664,7 @@ def local_execute_strategy(
674
664
  "strategy execution."
675
665
  )
676
666
  return result.catch(
677
- status=Status.FAILED,
667
+ status=FAILED,
678
668
  context={
679
669
  strategy_id: {
680
670
  "matrix": strategy,
@@ -724,7 +714,7 @@ def local_execute_strategy(
724
714
  ) from None
725
715
 
726
716
  return result.catch(
727
- status=Status.FAILED,
717
+ status=FAILED,
728
718
  context={
729
719
  strategy_id: {
730
720
  "matrix": strategy,
@@ -735,7 +725,7 @@ def local_execute_strategy(
735
725
  )
736
726
 
737
727
  return result.catch(
738
- status=Status.SUCCESS,
728
+ status=SUCCESS,
739
729
  context={
740
730
  strategy_id: {
741
731
  "matrix": strategy,
@@ -790,7 +780,7 @@ def local_execute(
790
780
 
791
781
  if event and event.is_set(): # pragma: no cov
792
782
  return result.catch(
793
- status=Status.FAILED,
783
+ status=FAILED,
794
784
  context={
795
785
  "errors": JobException(
796
786
  "Job strategy was canceled from event that had set "
@@ -808,7 +798,7 @@ def local_execute(
808
798
  raise_error=raise_error,
809
799
  )
810
800
 
811
- return result.catch(status=Status.SUCCESS)
801
+ return result.catch(status=SUCCESS)
812
802
 
813
803
  fail_fast_flag: bool = job.strategy.fail_fast
814
804
  ls: str = "Fail-Fast" if fail_fast_flag else "All-Completed"
@@ -819,7 +809,7 @@ def local_execute(
819
809
 
820
810
  if event and event.is_set(): # pragma: no cov
821
811
  return result.catch(
822
- status=Status.FAILED,
812
+ status=FAILED,
823
813
  context={
824
814
  "errors": JobException(
825
815
  "Job strategy was canceled from event that had set "
@@ -849,7 +839,7 @@ def local_execute(
849
839
  ]
850
840
 
851
841
  context: DictData = {}
852
- status: Status = Status.SUCCESS
842
+ status: Status = SUCCESS
853
843
 
854
844
  if not fail_fast_flag:
855
845
  done = as_completed(futures, timeout=1800)
@@ -875,7 +865,7 @@ def local_execute(
875
865
  try:
876
866
  future.result()
877
867
  except JobException as err:
878
- status = Status.FAILED
868
+ status = FAILED
879
869
  result.trace.error(
880
870
  f"[JOB]: {ls} Catch:\n\t{err.__class__.__name__}:"
881
871
  f"\n\t{err}"
@@ -903,7 +893,7 @@ def self_hosted_execute(
903
893
  )
904
894
 
905
895
  if event and event.is_set():
906
- return result.catch(status=Status.FAILED)
896
+ return result.catch(status=FAILED)
907
897
 
908
898
  import requests
909
899
 
@@ -922,5 +912,5 @@ def self_hosted_execute(
922
912
  f"{job.runs_on.args.host!r}"
923
913
  )
924
914
 
925
- return result.catch(status=Status.FAILED)
926
- return result.catch(status=Status.SUCCESS)
915
+ return result.catch(status=FAILED)
916
+ return result.catch(status=SUCCESS)
@@ -3,7 +3,6 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- # [ ] Use config
7
6
  """This module include all Param Pydantic Models that use for parsing an
8
7
  incoming parameters that was passed to the Workflow and Schedule objects before
9
8
  execution or release methods.
@@ -18,6 +17,7 @@ from abc import ABC, abstractmethod
18
17
  from datetime import date, datetime
19
18
  from typing import Annotated, Any, Literal, Optional, TypeVar, Union
20
19
 
20
+ from ddeutil.core import str2dict, str2list
21
21
  from pydantic import BaseModel, Field
22
22
 
23
23
  from .__types import TupleStr
@@ -31,6 +31,8 @@ __all__: TupleStr = (
31
31
  "IntParam",
32
32
  "Param",
33
33
  "StrParam",
34
+ "ArrayParam",
35
+ "MapParam",
34
36
  )
35
37
 
36
38
  T = TypeVar("T")
@@ -42,7 +44,10 @@ class BaseParam(BaseModel, ABC):
42
44
  """
43
45
 
44
46
  desc: Optional[str] = Field(
45
- default=None, description="A description of parameter providing."
47
+ default=None,
48
+ description=(
49
+ "A description of this parameter provide to the workflow model."
50
+ ),
46
51
  )
47
52
  required: bool = Field(
48
53
  default=True,
@@ -52,6 +57,7 @@ class BaseParam(BaseModel, ABC):
52
57
 
53
58
  @abstractmethod
54
59
  def receive(self, value: Optional[T] = None) -> T:
60
+ """Abstract method receive value to this parameter model."""
55
61
  raise NotImplementedError(
56
62
  "Receive value and validate typing before return valid value."
57
63
  )
@@ -66,13 +72,14 @@ class DefaultParam(BaseParam):
66
72
  default=False,
67
73
  description="A require flag for the default-able parameter value.",
68
74
  )
69
- default: Optional[str] = Field(
75
+ default: Optional[Any] = Field(
70
76
  default=None,
71
77
  description="A default value if parameter does not pass.",
72
78
  )
73
79
 
74
80
  @abstractmethod
75
81
  def receive(self, value: Optional[Any] = None) -> Any:
82
+ """Abstract method receive value to this parameter model."""
76
83
  raise NotImplementedError(
77
84
  "Receive value and validate typing before return valid value."
78
85
  )
@@ -82,7 +89,10 @@ class DateParam(DefaultParam): # pragma: no cov
82
89
  """Date parameter model."""
83
90
 
84
91
  type: Literal["date"] = "date"
85
- default: date = Field(default_factory=get_d_now)
92
+ default: date = Field(
93
+ default_factory=get_d_now,
94
+ description="A default date that make from the current date func.",
95
+ )
86
96
 
87
97
  def receive(self, value: Optional[str | datetime | date] = None) -> date:
88
98
  """Receive value that match with date. If an input value pass with
@@ -116,7 +126,12 @@ class DatetimeParam(DefaultParam):
116
126
  """Datetime parameter model."""
117
127
 
118
128
  type: Literal["datetime"] = "datetime"
119
- default: datetime = Field(default_factory=get_dt_now)
129
+ default: datetime = Field(
130
+ default_factory=get_dt_now,
131
+ description=(
132
+ "A default datetime that make from the current datetime func."
133
+ ),
134
+ )
120
135
 
121
136
  def receive(self, value: str | datetime | date | None = None) -> datetime:
122
137
  """Receive value that match with datetime. If an input value pass with
@@ -167,10 +182,6 @@ class IntParam(DefaultParam):
167
182
  """Integer parameter."""
168
183
 
169
184
  type: Literal["int"] = "int"
170
- default: Optional[int] = Field(
171
- default=None,
172
- description="A default value if parameter does not pass.",
173
- )
174
185
 
175
186
  def receive(self, value: int | None = None) -> int | None:
176
187
  """Receive value that match with int.
@@ -222,36 +233,84 @@ class ChoiceParam(BaseParam):
222
233
  return value
223
234
 
224
235
 
225
- # TODO: Not implement this parameter yet
226
236
  class MapParam(DefaultParam): # pragma: no cov
237
+ """Map parameter."""
227
238
 
228
239
  type: Literal["map"] = "map"
229
- default: dict[Any, Any] = Field(default_factory=dict)
240
+ default: dict[Any, Any] = Field(
241
+ default_factory=dict,
242
+ description="A default dict that make from the dict built-in func.",
243
+ )
244
+
245
+ def receive(
246
+ self,
247
+ value: Optional[Union[dict[Any, Any], str]] = None,
248
+ ) -> dict[Any, Any]:
249
+ """Receive value that match with map type.
230
250
 
231
- def receive(self, value: Optional[dict[Any, Any]] = None) -> dict[Any, Any]:
251
+ :param value: A value that want to validate with map parameter type.
252
+ :rtype: dict[Any, Any]
253
+ """
232
254
  if value is None:
233
255
  return self.default
234
256
 
257
+ if isinstance(value, str):
258
+ try:
259
+ value: dict[Any, Any] = str2dict(value)
260
+ except ValueError as e:
261
+ raise ParamValueException(
262
+ f"Value that want to convert to map does not support for "
263
+ f"type: {type(value)}"
264
+ ) from e
265
+ elif not isinstance(value, dict):
266
+ raise ParamValueException(
267
+ f"Value of map param support only string-dict or dict type, "
268
+ f"not {type(value)}"
269
+ )
270
+ return value
271
+
235
272
 
236
- # TODO: Not implement this parameter yet
237
273
  class ArrayParam(DefaultParam): # pragma: no cov
274
+ """Array parameter."""
238
275
 
239
276
  type: Literal["array"] = "array"
240
- default: list[Any] = Field(default_factory=list)
277
+ default: list[Any] = Field(
278
+ default_factory=list,
279
+ description="A default list that make from the list built-in func.",
280
+ )
241
281
 
242
- def receive(self, value: Optional[list[T]] = None) -> list[T]:
282
+ def receive(
283
+ self, value: Optional[Union[list[T], tuple[T, ...], str]] = None
284
+ ) -> list[T]:
285
+ """Receive value that match with array type.
286
+
287
+ :param value: A value that want to validate with array parameter type.
288
+ :rtype: list[Any]
289
+ """
243
290
  if value is None:
244
291
  return self.default
245
- if not isinstance(value, list):
292
+ if isinstance(value, str):
293
+ try:
294
+ value: list[T] = str2list(value)
295
+ except ValueError as e:
296
+ raise ParamValueException(
297
+ f"Value that want to convert to array does not support for "
298
+ f"type: {type(value)}"
299
+ ) from e
300
+ elif isinstance(value, (tuple, set)):
301
+ return list(value)
302
+ elif not isinstance(value, list):
246
303
  raise ParamValueException(
247
- f"Value that want to convert to array does not support for "
248
- f"type: {type(value)}"
304
+ f"Value of map param support only string-list or list type, "
305
+ f"not {type(value)}"
249
306
  )
250
307
  return value
251
308
 
252
309
 
253
310
  Param = Annotated[
254
311
  Union[
312
+ MapParam,
313
+ ArrayParam,
255
314
  ChoiceParam,
256
315
  DatetimeParam,
257
316
  DateParam,