ddeutil-workflow 0.0.26.post1__tar.gz → 0.0.27__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 (64) hide show
  1. {ddeutil_workflow-0.0.26.post1/src/ddeutil_workflow.egg-info → ddeutil_workflow-0.0.27}/PKG-INFO +24 -24
  2. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/README.md +23 -23
  3. ddeutil_workflow-0.0.27/src/ddeutil/workflow/__about__.py +1 -0
  4. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/__init__.py +19 -14
  5. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/conf.py +29 -12
  6. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/exceptions.py +0 -3
  7. ddeutil_workflow-0.0.27/src/ddeutil/workflow/hook.py +153 -0
  8. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/job.py +1 -1
  9. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/stage.py +3 -55
  10. ddeutil_workflow-0.0.26.post1/src/ddeutil/workflow/utils.py → ddeutil_workflow-0.0.27/src/ddeutil/workflow/templates.py +20 -283
  11. ddeutil_workflow-0.0.27/src/ddeutil/workflow/utils.py +209 -0
  12. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/workflow.py +2 -3
  13. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27/src/ddeutil_workflow.egg-info}/PKG-INFO +24 -24
  14. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil_workflow.egg-info/SOURCES.txt +5 -3
  15. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_conf_log.py +6 -1
  16. ddeutil_workflow-0.0.26.post1/tests/test_utils_tag.py → ddeutil_workflow-0.0.27/tests/test_hook_tag.py +10 -3
  17. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_job.py +1 -1
  18. ddeutil_workflow-0.0.26.post1/tests/test_utils_template.py → ddeutil_workflow-0.0.27/tests/test_templates.py +1 -1
  19. ddeutil_workflow-0.0.26.post1/tests/test_utils_filter.py → ddeutil_workflow-0.0.27/tests/test_templates_filter.py +16 -3
  20. ddeutil_workflow-0.0.26.post1/src/ddeutil/workflow/__about__.py +0 -1
  21. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/LICENSE +0 -0
  22. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/pyproject.toml +0 -0
  23. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/setup.cfg +0 -0
  24. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/__cron.py +0 -0
  25. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/__types.py +0 -0
  26. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/api/__init__.py +0 -0
  27. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/api/api.py +0 -0
  28. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/api/repeat.py +0 -0
  29. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/api/route.py +0 -0
  30. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/cron.py +0 -0
  31. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/params.py +0 -0
  32. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/result.py +0 -0
  33. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil/workflow/scheduler.py +0 -0
  34. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
  35. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil_workflow.egg-info/requires.txt +0 -0
  36. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
  37. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test__cron.py +0 -0
  38. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test__regex.py +0 -0
  39. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_conf.py +0 -0
  40. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_cron_on.py +0 -0
  41. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_job_exec_py.py +0 -0
  42. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_job_exec_strategy.py +0 -0
  43. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_job_strategy.py +0 -0
  44. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_params.py +0 -0
  45. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_result.py +0 -0
  46. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_schedule.py +0 -0
  47. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_schedule_control.py +0 -0
  48. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_schedule_tasks.py +0 -0
  49. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_stage.py +0 -0
  50. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_stage_exec_bash.py +0 -0
  51. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_stage_exec_hook.py +0 -0
  52. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_stage_exec_py.py +0 -0
  53. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_stage_exec_trigger.py +0 -0
  54. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_utils.py +0 -0
  55. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow.py +0 -0
  56. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_exec.py +0 -0
  57. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_exec_hook.py +0 -0
  58. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_exec_needs.py +0 -0
  59. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_job_exec.py +0 -0
  60. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_poke.py +0 -0
  61. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_release.py +0 -0
  62. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_release_and_queue.py +0 -0
  63. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_schedule.py +0 -0
  64. {ddeutil_workflow-0.0.26.post1 → ddeutil_workflow-0.0.27}/tests/test_workflow_task.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ddeutil-workflow
3
- Version: 0.0.26.post1
3
+ Version: 0.0.27
4
4
  Summary: Lightweight workflow orchestration with less dependencies
5
5
  Author-email: ddeutils <korawich.anu@gmail.com>
6
6
  License: MIT
@@ -168,29 +168,29 @@ The main configuration that use to dynamic changing with your propose of this
168
168
  application. If any configuration values do not set yet, it will use default value
169
169
  and do not raise any error to you.
170
170
 
171
- | Environment | Component | Default | Description | Remark |
172
- |:-------------------------------------------|:---------:|:-----------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|--------|
173
- | **WORKFLOW_ROOT_PATH** | Core | `.` | The root path of the workflow application. | |
174
- | **WORKFLOW_CORE_REGISTRY** | Core | `src,src.ddeutil.workflow,tests,tests.utils` | List of importable string for the hook stage. | |
175
- | **WORKFLOW_CORE_REGISTRY_FILTER** | Core | `src.ddeutil.workflow.utils,ddeutil.workflow.utils` | List of importable string for the filter template. | |
176
- | **WORKFLOW_CORE_PATH_CONF** | Core | `conf` | The config path that keep all template `.yaml` files. | |
177
- | **WORKFLOW_CORE_TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. | |
178
- | **WORKFLOW_CORE_STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. | |
179
- | **WORKFLOW_CORE_STAGE_RAISE_ERROR** | Core | `false` | A flag that all stage raise StageException from stage execution. | |
180
- | **WORKFLOW_CORE_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. | |
181
- | **WORKFLOW_CORE_JOB_RAISE_ERROR** | Core | `true` | A flag that all job raise JobException from job strategy execution. | |
182
- | **WORKFLOW_CORE_MAX_NUM_POKING** | Core | `4` | . | |
183
- | **WORKFLOW_CORE_MAX_JOB_PARALLEL** | Core | `2` | The maximum job number that able to run parallel in workflow executor. | |
184
- | **WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT** | Core | `600` | | |
185
- | **WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW** | Core | `5` | | |
186
- | **WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST** | Core | `16` | | |
187
- | **WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. | |
188
- | **WORKFLOW_LOG_PATH** | Log | `./logs` | The log path of the workflow saving log. | |
189
- | **WORKFLOW_LOG_DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. | |
190
- | **WORKFLOW_LOG_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. | |
191
- | **WORKFLOW_APP_MAX_PROCESS** | Schedule | `2` | The maximum process worker number that run in scheduler app module. | |
192
- | **WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS** | Schedule | `100` | A schedule per process that run parallel. | |
193
- | **WORKFLOW_APP_STOP_BOUNDARY_DELTA** | Schedule | `'{"minutes": 5, "seconds": 20}'` | A time delta value that use to stop scheduler app in json string format. | |
171
+ | Environment | Component | Default | Description | Remark |
172
+ |:-------------------------------------------|:---------:|:----------------------------------|:-------------------------------------------------------------------------------------------------------------------|--------|
173
+ | **WORKFLOW_ROOT_PATH** | Core | `.` | The root path of the workflow application. | |
174
+ | **WORKFLOW_CORE_REGISTRY** | Core | `src` | List of importable string for the hook stage. | |
175
+ | **WORKFLOW_CORE_REGISTRY_FILTER** | Core | `ddeutil.workflow.utils` | List of importable string for the filter template. | |
176
+ | **WORKFLOW_CORE_PATH_CONF** | Core | `conf` | The config path that keep all template `.yaml` files. | |
177
+ | **WORKFLOW_CORE_TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. | |
178
+ | **WORKFLOW_CORE_STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. | |
179
+ | **WORKFLOW_CORE_STAGE_RAISE_ERROR** | Core | `false` | A flag that all stage raise StageException from stage execution. | |
180
+ | **WORKFLOW_CORE_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. | |
181
+ | **WORKFLOW_CORE_JOB_RAISE_ERROR** | Core | `true` | A flag that all job raise JobException from job strategy execution. | |
182
+ | **WORKFLOW_CORE_MAX_NUM_POKING** | Core | `4` | . | |
183
+ | **WORKFLOW_CORE_MAX_JOB_PARALLEL** | Core | `2` | The maximum job number that able to run parallel in workflow executor. | |
184
+ | **WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT** | Core | `600` | | |
185
+ | **WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW** | Core | `5` | | |
186
+ | **WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST** | Core | `16` | | |
187
+ | **WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. | |
188
+ | **WORKFLOW_LOG_PATH** | Log | `./logs` | The log path of the workflow saving log. | |
189
+ | **WORKFLOW_LOG_DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. | |
190
+ | **WORKFLOW_LOG_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. | |
191
+ | **WORKFLOW_APP_MAX_PROCESS** | Schedule | `2` | The maximum process worker number that run in scheduler app module. | |
192
+ | **WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS** | Schedule | `100` | A schedule per process that run parallel. | |
193
+ | **WORKFLOW_APP_STOP_BOUNDARY_DELTA** | Schedule | `'{"minutes": 5, "seconds": 20}'` | A time delta value that use to stop scheduler app in json string format. | |
194
194
 
195
195
  **API Application**:
196
196
 
@@ -136,29 +136,29 @@ The main configuration that use to dynamic changing with your propose of this
136
136
  application. If any configuration values do not set yet, it will use default value
137
137
  and do not raise any error to you.
138
138
 
139
- | Environment | Component | Default | Description | Remark |
140
- |:-------------------------------------------|:---------:|:-----------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|--------|
141
- | **WORKFLOW_ROOT_PATH** | Core | `.` | The root path of the workflow application. | |
142
- | **WORKFLOW_CORE_REGISTRY** | Core | `src,src.ddeutil.workflow,tests,tests.utils` | List of importable string for the hook stage. | |
143
- | **WORKFLOW_CORE_REGISTRY_FILTER** | Core | `src.ddeutil.workflow.utils,ddeutil.workflow.utils` | List of importable string for the filter template. | |
144
- | **WORKFLOW_CORE_PATH_CONF** | Core | `conf` | The config path that keep all template `.yaml` files. | |
145
- | **WORKFLOW_CORE_TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. | |
146
- | **WORKFLOW_CORE_STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. | |
147
- | **WORKFLOW_CORE_STAGE_RAISE_ERROR** | Core | `false` | A flag that all stage raise StageException from stage execution. | |
148
- | **WORKFLOW_CORE_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. | |
149
- | **WORKFLOW_CORE_JOB_RAISE_ERROR** | Core | `true` | A flag that all job raise JobException from job strategy execution. | |
150
- | **WORKFLOW_CORE_MAX_NUM_POKING** | Core | `4` | . | |
151
- | **WORKFLOW_CORE_MAX_JOB_PARALLEL** | Core | `2` | The maximum job number that able to run parallel in workflow executor. | |
152
- | **WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT** | Core | `600` | | |
153
- | **WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW** | Core | `5` | | |
154
- | **WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST** | Core | `16` | | |
155
- | **WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. | |
156
- | **WORKFLOW_LOG_PATH** | Log | `./logs` | The log path of the workflow saving log. | |
157
- | **WORKFLOW_LOG_DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. | |
158
- | **WORKFLOW_LOG_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. | |
159
- | **WORKFLOW_APP_MAX_PROCESS** | Schedule | `2` | The maximum process worker number that run in scheduler app module. | |
160
- | **WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS** | Schedule | `100` | A schedule per process that run parallel. | |
161
- | **WORKFLOW_APP_STOP_BOUNDARY_DELTA** | Schedule | `'{"minutes": 5, "seconds": 20}'` | A time delta value that use to stop scheduler app in json string format. | |
139
+ | Environment | Component | Default | Description | Remark |
140
+ |:-------------------------------------------|:---------:|:----------------------------------|:-------------------------------------------------------------------------------------------------------------------|--------|
141
+ | **WORKFLOW_ROOT_PATH** | Core | `.` | The root path of the workflow application. | |
142
+ | **WORKFLOW_CORE_REGISTRY** | Core | `src` | List of importable string for the hook stage. | |
143
+ | **WORKFLOW_CORE_REGISTRY_FILTER** | Core | `ddeutil.workflow.utils` | List of importable string for the filter template. | |
144
+ | **WORKFLOW_CORE_PATH_CONF** | Core | `conf` | The config path that keep all template `.yaml` files. | |
145
+ | **WORKFLOW_CORE_TIMEZONE** | Core | `Asia/Bangkok` | A Timezone string value that will pass to `ZoneInfo` object. | |
146
+ | **WORKFLOW_CORE_STAGE_DEFAULT_ID** | Core | `true` | A flag that enable default stage ID that use for catch an execution output. | |
147
+ | **WORKFLOW_CORE_STAGE_RAISE_ERROR** | Core | `false` | A flag that all stage raise StageException from stage execution. | |
148
+ | **WORKFLOW_CORE_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. | |
149
+ | **WORKFLOW_CORE_JOB_RAISE_ERROR** | Core | `true` | A flag that all job raise JobException from job strategy execution. | |
150
+ | **WORKFLOW_CORE_MAX_NUM_POKING** | Core | `4` | . | |
151
+ | **WORKFLOW_CORE_MAX_JOB_PARALLEL** | Core | `2` | The maximum job number that able to run parallel in workflow executor. | |
152
+ | **WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT** | Core | `600` | | |
153
+ | **WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW** | Core | `5` | | |
154
+ | **WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST** | Core | `16` | | |
155
+ | **WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE** | Core | `true` | A flog that enable generating ID with `md5` algorithm. | |
156
+ | **WORKFLOW_LOG_PATH** | Log | `./logs` | The log path of the workflow saving log. | |
157
+ | **WORKFLOW_LOG_DEBUG_MODE** | Log | `true` | A flag that enable logging with debug level mode. | |
158
+ | **WORKFLOW_LOG_ENABLE_WRITE** | Log | `true` | A flag that enable logging object saving log to its destination. | |
159
+ | **WORKFLOW_APP_MAX_PROCESS** | Schedule | `2` | The maximum process worker number that run in scheduler app module. | |
160
+ | **WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS** | Schedule | `100` | A schedule per process that run parallel. | |
161
+ | **WORKFLOW_APP_STOP_BOUNDARY_DELTA** | Schedule | `'{"minutes": 5, "seconds": 20}'` | A time delta value that use to stop scheduler app in json string format. | |
162
162
 
163
163
  **API Application**:
164
164
 
@@ -0,0 +1 @@
1
+ __version__: str = "0.0.27"
@@ -8,6 +8,7 @@ from .conf import (
8
8
  Config,
9
9
  Loader,
10
10
  Log,
11
+ config,
11
12
  env,
12
13
  get_log,
13
14
  get_logger,
@@ -24,6 +25,13 @@ from .exceptions import (
24
25
  UtilException,
25
26
  WorkflowException,
26
27
  )
28
+ from .hook import (
29
+ ReturnTagFunc,
30
+ TagFunc,
31
+ extract_hook,
32
+ make_registry,
33
+ tag,
34
+ )
27
35
  from .job import (
28
36
  Job,
29
37
  Strategy,
@@ -48,33 +56,30 @@ from .stage import (
48
56
  PyStage,
49
57
  Stage,
50
58
  TriggerStage,
51
- extract_hook,
52
59
  )
53
- from .utils import (
60
+ from .templates import (
54
61
  FILTERS,
55
62
  FilterFunc,
56
63
  FilterRegistry,
57
- ReturnTagFunc,
58
- TagFunc,
64
+ custom_filter,
65
+ get_args_const,
66
+ has_template,
67
+ make_filter_registry,
68
+ map_post_filter,
69
+ not_in_template,
70
+ param2template,
71
+ str2template,
72
+ )
73
+ from .utils import (
59
74
  batch,
60
75
  cross_product,
61
- custom_filter,
62
76
  dash2underscore,
63
77
  delay,
64
78
  filter_func,
65
79
  gen_id,
66
- get_args_const,
67
80
  get_diff_sec,
68
81
  get_dt_now,
69
- has_template,
70
82
  make_exec,
71
- make_filter_registry,
72
- make_registry,
73
- map_post_filter,
74
- not_in_template,
75
- param2template,
76
- str2template,
77
- tag,
78
83
  )
79
84
  from .workflow import (
80
85
  Workflow,
@@ -108,15 +108,13 @@ class Config: # pragma: no cov
108
108
  # NOTE: Register
109
109
  @property
110
110
  def regis_hook(self) -> list[str]:
111
- regis_hook_str: str = env(
112
- "CORE_REGISTRY", "src,src.ddeutil.workflow,tests,tests.utils"
113
- )
111
+ regis_hook_str: str = env("CORE_REGISTRY", "src")
114
112
  return [r.strip() for r in regis_hook_str.split(",")]
115
113
 
116
114
  @property
117
115
  def regis_filter(self) -> list[str]:
118
116
  regis_filter_str: str = env(
119
- "CORE_REGISTRY_FILTER", "ddeutil.workflow.utils"
117
+ "CORE_REGISTRY_FILTER", "ddeutil.workflow.templates"
120
118
  )
121
119
  return [r.strip() for r in regis_filter_str.split(",")]
122
120
 
@@ -312,6 +310,10 @@ class SimLoad:
312
310
  )
313
311
 
314
312
 
313
+ config = Config()
314
+ logger = get_logger("ddeutil.workflow")
315
+
316
+
315
317
  class Loader(SimLoad):
316
318
  """Loader Object that get the config `yaml` file from current path.
317
319
 
@@ -337,15 +339,11 @@ class Loader(SimLoad):
337
339
  :rtype: Iterator[tuple[str, DictData]]
338
340
  """
339
341
  return super().finds(
340
- obj=obj, conf=Config(), included=included, excluded=excluded
342
+ obj=obj, conf=config, included=included, excluded=excluded
341
343
  )
342
344
 
343
345
  def __init__(self, name: str, externals: DictData) -> None:
344
- super().__init__(name, conf=Config(), externals=externals)
345
-
346
-
347
- config = Config()
348
- logger = get_logger("ddeutil.workflow")
346
+ super().__init__(name, conf=config, externals=externals)
349
347
 
350
348
 
351
349
  class BaseLog(BaseModel, ABC):
@@ -427,8 +425,8 @@ class FileLog(BaseLog):
427
425
  workflow name and release values. If a release does not pass to an input
428
426
  argument, it will return the latest release from the current log path.
429
427
 
430
- :param name:
431
- :param release:
428
+ :param name: A workflow name that want to search log.
429
+ :param release: A release datetime that want to search log.
432
430
 
433
431
  :raise FileNotFoundError:
434
432
  :raise NotImplementedError:
@@ -492,8 +490,14 @@ class FileLog(BaseLog):
492
490
 
493
491
  :rtype: Self
494
492
  """
493
+ from .utils import cut_id
494
+
495
495
  # NOTE: Check environ variable was set for real writing.
496
496
  if not config.enable_write_log:
497
+ logger.debug(
498
+ f"({cut_id(self.run_id)}) [LOG]: Skip writing log cause "
499
+ f"config was set"
500
+ )
497
501
  return self
498
502
 
499
503
  log_file: Path = self.pointer() / f"{self.run_id}.log"
@@ -523,6 +527,19 @@ class SQLiteLog(BaseLog): # pragma: no cov
523
527
  """
524
528
 
525
529
  def save(self, excluded: list[str] | None) -> None:
530
+ """Save logging data that receive a context data from a workflow
531
+ execution result.
532
+ """
533
+ from .utils import cut_id
534
+
535
+ # NOTE: Check environ variable was set for real writing.
536
+ if not config.enable_write_log:
537
+ logger.debug(
538
+ f"({cut_id(self.run_id)}) [LOG]: Skip writing log cause "
539
+ f"config was set"
540
+ )
541
+ return self
542
+
526
543
  raise NotImplementedError("SQLiteLog does not implement yet.")
527
544
 
528
545
 
@@ -29,6 +29,3 @@ class WorkflowFailException(WorkflowException): ...
29
29
 
30
30
 
31
31
  class ParamValueException(WorkflowException): ...
32
-
33
-
34
- class CliException(BaseWorkflowException): ...
@@ -0,0 +1,153 @@
1
+ # ------------------------------------------------------------------------------
2
+ # Copyright (c) 2022 Korawich Anuttra. All rights reserved.
3
+ # Licensed under the MIT License. See LICENSE in the project root for
4
+ # license information.
5
+ # ------------------------------------------------------------------------------
6
+ from __future__ import annotations
7
+
8
+ import inspect
9
+ import logging
10
+ from dataclasses import dataclass
11
+ from functools import wraps
12
+ from importlib import import_module
13
+ from typing import Any, Callable, Protocol, TypeVar
14
+
15
+ try:
16
+ from typing import ParamSpec
17
+ except ImportError:
18
+ from typing_extensions import ParamSpec
19
+
20
+ from ddeutil.core import lazy
21
+
22
+ from .__types import Re
23
+ from .conf import config
24
+
25
+ T = TypeVar("T")
26
+ P = ParamSpec("P")
27
+
28
+ logger = logging.getLogger("ddeutil.workflow")
29
+
30
+
31
+ class TagFunc(Protocol):
32
+ """Tag Function Protocol"""
33
+
34
+ name: str
35
+ tag: str
36
+
37
+ def __call__(self, *args, **kwargs): ... # pragma: no cov
38
+
39
+
40
+ ReturnTagFunc = Callable[P, TagFunc]
41
+ DecoratorTagFunc = Callable[[Callable[[...], Any]], ReturnTagFunc]
42
+
43
+
44
+ def tag(
45
+ name: str, alias: str | None = None
46
+ ) -> DecoratorTagFunc: # pragma: no cov
47
+ """Tag decorator function that set function attributes, ``tag`` and ``name``
48
+ for making registries variable.
49
+
50
+ :param: name: A tag name for make different use-case of a function.
51
+ :param: alias: A alias function name that keeping in registries. If this
52
+ value does not supply, it will use original function name from __name__.
53
+ :rtype: Callable[P, TagFunc]
54
+ """
55
+
56
+ def func_internal(func: Callable[[...], Any]) -> ReturnTagFunc:
57
+ func.tag = name
58
+ func.name = alias or func.__name__.replace("_", "-")
59
+
60
+ @wraps(func)
61
+ def wrapped(*args, **kwargs):
62
+ # NOTE: Able to do anything before calling hook function.
63
+ return func(*args, **kwargs)
64
+
65
+ return wrapped
66
+
67
+ return func_internal
68
+
69
+
70
+ Registry = dict[str, Callable[[], TagFunc]]
71
+
72
+
73
+ def make_registry(submodule: str) -> dict[str, Registry]:
74
+ """Return registries of all functions that able to called with task.
75
+
76
+ :param submodule: A module prefix that want to import registry.
77
+ :rtype: dict[str, Registry]
78
+ """
79
+ rs: dict[str, Registry] = {}
80
+ for module in config.regis_hook:
81
+ # NOTE: try to sequential import task functions
82
+ try:
83
+ importer = import_module(f"{module}.{submodule}")
84
+ except ModuleNotFoundError:
85
+ continue
86
+
87
+ for fstr, func in inspect.getmembers(importer, inspect.isfunction):
88
+ # NOTE: check function attribute that already set tag by
89
+ # ``utils.tag`` decorator.
90
+ if not hasattr(func, "tag"):
91
+ continue
92
+
93
+ # NOTE: Create new register name if it not exists
94
+ if func.name not in rs:
95
+ rs[func.name] = {func.tag: lazy(f"{module}.{submodule}.{fstr}")}
96
+ continue
97
+
98
+ if func.tag in rs[func.name]:
99
+ raise ValueError(
100
+ f"The tag {func.tag!r} already exists on "
101
+ f"{module}.{submodule}, you should change this tag name or "
102
+ f"change it func name."
103
+ )
104
+ rs[func.name][func.tag] = lazy(f"{module}.{submodule}.{fstr}")
105
+
106
+ return rs
107
+
108
+
109
+ @dataclass(frozen=True)
110
+ class HookSearchData:
111
+ """Hook Search dataclass that use for receive regular expression grouping
112
+ dict from searching hook string value.
113
+ """
114
+
115
+ path: str
116
+ func: str
117
+ tag: str
118
+
119
+
120
+ def extract_hook(hook: str) -> Callable[[], TagFunc]:
121
+ """Extract Hook function from string value to hook partial function that
122
+ does run it at runtime.
123
+
124
+ :raise NotImplementedError: When the searching hook's function result does
125
+ not exist in the registry.
126
+ :raise NotImplementedError: When the searching hook's tag result does not
127
+ exists in the registry with its function key.
128
+
129
+ :param hook: A hook value that able to match with Task regex.
130
+ :rtype: Callable[[], TagFunc]
131
+ """
132
+ if not (found := Re.RE_TASK_FMT.search(hook)):
133
+ raise ValueError(
134
+ f"Hook {hook!r} does not match with hook format regex."
135
+ )
136
+
137
+ # NOTE: Pass the searching hook string to `path`, `func`, and `tag`.
138
+ hook: HookSearchData = HookSearchData(**found.groupdict())
139
+
140
+ # NOTE: Registry object should implement on this package only.
141
+ rgt: dict[str, Registry] = make_registry(f"{hook.path}")
142
+ if hook.func not in rgt:
143
+ raise NotImplementedError(
144
+ f"``REGISTER-MODULES.{hook.path}.registries`` does not "
145
+ f"implement registry: {hook.func!r}."
146
+ )
147
+
148
+ if hook.tag not in rgt[hook.func]:
149
+ raise NotImplementedError(
150
+ f"tag: {hook.tag!r} does not found on registry func: "
151
+ f"``REGISTER-MODULES.{hook.path}.registries.{hook.func}``"
152
+ )
153
+ return rgt[hook.func][hook.tag]
@@ -38,13 +38,13 @@ from .exceptions import (
38
38
  )
39
39
  from .result import Result
40
40
  from .stage import Stage
41
+ from .templates import has_template
41
42
  from .utils import (
42
43
  cross_product,
43
44
  cut_id,
44
45
  dash2underscore,
45
46
  filter_func,
46
47
  gen_id,
47
- has_template,
48
48
  )
49
49
 
50
50
  logger = get_logger("ddeutil.workflow")
@@ -31,7 +31,6 @@ import time
31
31
  import uuid
32
32
  from abc import ABC, abstractmethod
33
33
  from collections.abc import Iterator
34
- from dataclasses import dataclass
35
34
  from functools import wraps
36
35
  from inspect import Parameter
37
36
  from pathlib import Path
@@ -48,19 +47,16 @@ from pydantic import BaseModel, Field
48
47
  from pydantic.functional_validators import model_validator
49
48
  from typing_extensions import Self
50
49
 
51
- from .__types import DictData, DictStr, Re, TupleStr
50
+ from .__types import DictData, DictStr, TupleStr
52
51
  from .conf import config, get_logger
53
52
  from .exceptions import StageException
53
+ from .hook import TagFunc, extract_hook
54
54
  from .result import Result
55
+ from .templates import not_in_template, param2template
55
56
  from .utils import (
56
- Registry,
57
- TagFunc,
58
57
  cut_id,
59
58
  gen_id,
60
59
  make_exec,
61
- make_registry,
62
- not_in_template,
63
- param2template,
64
60
  )
65
61
 
66
62
  P = ParamSpec("P")
@@ -76,7 +72,6 @@ __all__: TupleStr = (
76
72
  "HookStage",
77
73
  "TriggerStage",
78
74
  "Stage",
79
- "extract_hook",
80
75
  )
81
76
 
82
77
 
@@ -558,53 +553,6 @@ class PyStage(BaseStage):
558
553
  )
559
554
 
560
555
 
561
- @dataclass(frozen=True)
562
- class HookSearchData:
563
- """Hook Search dataclass that use for receive regular expression grouping
564
- dict from searching hook string value.
565
- """
566
-
567
- path: str
568
- func: str
569
- tag: str
570
-
571
-
572
- def extract_hook(hook: str) -> Callable[[], TagFunc]:
573
- """Extract Hook function from string value to hook partial function that
574
- does run it at runtime.
575
-
576
- :raise NotImplementedError: When the searching hook's function result does
577
- not exist in the registry.
578
- :raise NotImplementedError: When the searching hook's tag result does not
579
- exists in the registry with its function key.
580
-
581
- :param hook: A hook value that able to match with Task regex.
582
- :rtype: Callable[[], TagFunc]
583
- """
584
- if not (found := Re.RE_TASK_FMT.search(hook)):
585
- raise ValueError(
586
- f"Hook {hook!r} does not match with hook format regex."
587
- )
588
-
589
- # NOTE: Pass the searching hook string to `path`, `func`, and `tag`.
590
- hook: HookSearchData = HookSearchData(**found.groupdict())
591
-
592
- # NOTE: Registry object should implement on this package only.
593
- rgt: dict[str, Registry] = make_registry(f"{hook.path}")
594
- if hook.func not in rgt:
595
- raise NotImplementedError(
596
- f"``REGISTER-MODULES.{hook.path}.registries`` does not "
597
- f"implement registry: {hook.func!r}."
598
- )
599
-
600
- if hook.tag not in rgt[hook.func]:
601
- raise NotImplementedError(
602
- f"tag: {hook.tag!r} does not found on registry func: "
603
- f"``REGISTER-MODULES.{hook.path}.registries.{hook.func}``"
604
- )
605
- return rgt[hook.func][hook.tag]
606
-
607
-
608
556
  class HookStage(BaseStage):
609
557
  """Hook executor that hook the Python function from registry with tag
610
558
  decorator function in ``utils`` module and run it with input arguments.