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.
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/PKG-INFO +29 -29
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/README.md +27 -27
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/pyproject.toml +2 -1
- ddeutil_workflow-0.0.43/src/ddeutil/workflow/__about__.py +1 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/__init__.py +5 -1
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/exceptions.py +13 -3
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/job.py +22 -32
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/params.py +77 -18
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/result.py +36 -8
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/scheduler.py +6 -9
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/stages.py +51 -81
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/workflow.py +16 -16
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/PKG-INFO +29 -29
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/requires.txt +1 -1
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job.py +3 -3
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_params.py +27 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_stage_handler_exec.py +78 -11
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec.py +30 -0
- ddeutil_workflow-0.0.42/src/ddeutil/workflow/__about__.py +0 -1
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/LICENSE +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/__cron.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/__types.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/__init__.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/api.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/log.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/repeat.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/job.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/logs.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/conf.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/cron.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/logs.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/reusables.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil/workflow/utils.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/SOURCES.txt +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test__cron.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test__regex.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_conf.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_cron_on.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job_exec.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job_exec_strategy.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_job_strategy.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_logs_audit.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_logs_trace.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_release.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_release_queue.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_result.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_reusables_call_tag.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_reusables_template.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_reusables_template_filter.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule_pending.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule_tasks.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_schedule_workflow.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_scheduler_control.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_stage.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_utils.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec_job.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec_poke.py +0 -0
- {ddeutil_workflow-0.0.42 → ddeutil_workflow-0.0.43}/tests/test_workflow_exec_release.py +0 -0
- {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.
|
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.
|
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
|
-
.
|
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
|
-
| **
|
279
|
-
| **
|
280
|
-
| **
|
281
|
-
| **
|
282
|
-
| **
|
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.
|
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
|
-
.
|
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
|
-
| **
|
235
|
-
| **
|
236
|
-
| **
|
237
|
-
| **
|
238
|
-
| **
|
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
|
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
|
-
|
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) ->
|
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
|
-
) ->
|
411
|
-
"""Return
|
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:
|
407
|
+
:rtype: Status
|
418
408
|
"""
|
419
409
|
if not self.needs:
|
420
|
-
return
|
410
|
+
return SUCCESS
|
421
411
|
|
422
|
-
def make_return(result: bool) ->
|
423
|
-
return
|
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
|
419
|
+
return WAIT
|
430
420
|
elif all("skipped" in need_exist[job] for job in need_exist):
|
431
|
-
return
|
421
|
+
return SKIP
|
432
422
|
elif self.trigger_rule == TriggerRules.all_done:
|
433
|
-
return
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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 =
|
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 =
|
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=
|
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=
|
926
|
-
return result.catch(status=
|
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,
|
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[
|
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(
|
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(
|
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(
|
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
|
-
|
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(
|
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(
|
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
|
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
|
248
|
-
f"
|
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,
|