ddeutil-workflow 0.0.55__tar.gz → 0.0.57__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.55 → ddeutil_workflow-0.0.57}/PKG-INFO +41 -35
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/README.md +38 -32
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/pyproject.toml +8 -4
- ddeutil_workflow-0.0.57/src/ddeutil/workflow/__about__.py +1 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__cron.py +26 -12
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__init__.py +4 -2
- ddeutil_workflow-0.0.57/src/ddeutil/workflow/__main__.py +30 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__types.py +1 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/conf.py +163 -101
- ddeutil_workflow-0.0.55/src/ddeutil/workflow/cron.py → ddeutil_workflow-0.0.57/src/ddeutil/workflow/event.py +37 -20
- ddeutil_workflow-0.0.57/src/ddeutil/workflow/exceptions.py +87 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/job.py +87 -58
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/logs.py +13 -5
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/result.py +9 -4
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/scheduler.py +38 -73
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/stages.py +370 -147
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/utils.py +37 -6
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/workflow.py +243 -302
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/PKG-INFO +41 -35
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/SOURCES.txt +5 -4
- ddeutil_workflow-0.0.57/src/ddeutil_workflow.egg-info/entry_points.txt +2 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/requires.txt +2 -2
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test__cron.py +27 -21
- ddeutil_workflow-0.0.57/tests/test_conf.py +218 -0
- ddeutil_workflow-0.0.55/tests/test_cron_on.py → ddeutil_workflow-0.0.57/tests/test_event.py +56 -22
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_job.py +20 -21
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_job_exec.py +93 -68
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_job_exec_strategy.py +9 -20
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_params.py +1 -4
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_release.py +7 -20
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_release_queue.py +1 -1
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_result.py +16 -28
- ddeutil_workflow-0.0.57/tests/test_reusables_call_tag.py +121 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule.py +6 -9
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule_workflow.py +1 -1
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_stage.py +22 -27
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_stage_handler_exec.py +280 -243
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_utils.py +30 -4
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow.py +112 -115
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow_exec.py +158 -137
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow_exec_job.py +10 -28
- ddeutil_workflow-0.0.57/tests/test_workflow_poke.py +168 -0
- ddeutil_workflow-0.0.57/tests/test_workflow_release.py +153 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_workflow_task.py +34 -17
- ddeutil_workflow-0.0.55/src/ddeutil/workflow/__about__.py +0 -1
- ddeutil_workflow-0.0.55/src/ddeutil/workflow/__main__.py +0 -0
- ddeutil_workflow-0.0.55/src/ddeutil/workflow/exceptions.py +0 -57
- ddeutil_workflow-0.0.55/tests/test_conf.py +0 -160
- ddeutil_workflow-0.0.55/tests/test_reusables_call_tag.py +0 -252
- ddeutil_workflow-0.0.55/tests/test_workflow_exec_poke.py +0 -171
- ddeutil_workflow-0.0.55/tests/test_workflow_exec_release.py +0 -125
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/LICENSE +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/__init__.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/logs.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/job.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/logs.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/utils.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/params.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/reusables.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test__regex.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_logs_audit.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_logs_trace.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_reusables_template.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_reusables_template_filter.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule_pending.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_schedule_tasks.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_scheduler_control.py +0 -0
- {ddeutil_workflow-0.0.55 → ddeutil_workflow-0.0.57}/tests/test_strategy.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.57
|
4
4
|
Summary: Lightweight workflow orchestration
|
5
5
|
Author-email: ddeutils <korawich.anu@gmail.com>
|
6
6
|
License: MIT
|
@@ -22,8 +22,8 @@ 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[checksum]>=0.4.
|
26
|
-
Requires-Dist: ddeutil-io[toml,yaml]>=0.2.
|
25
|
+
Requires-Dist: ddeutil[checksum]>=0.4.8
|
26
|
+
Requires-Dist: ddeutil-io[toml,yaml]>=0.2.12
|
27
27
|
Requires-Dist: pydantic==2.11.1
|
28
28
|
Requires-Dist: python-dotenv==1.1.0
|
29
29
|
Requires-Dist: schedule<2.0.0,==1.2.2
|
@@ -250,42 +250,48 @@ from ddeutil.workflow import Workflow, Result
|
|
250
250
|
|
251
251
|
workflow: Workflow = Workflow.from_conf('run-py-local')
|
252
252
|
result: Result = workflow.execute(
|
253
|
-
params={"source-extract": "USD-THB", "
|
253
|
+
params={"source-extract": "USD-THB", "run-date": "2024-01-01"}
|
254
254
|
)
|
255
255
|
```
|
256
256
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
257
|
+
> [!NOTE]
|
258
|
+
> So, this package provide the `Schedule` template for this action, and you can
|
259
|
+
> pass the parameters dynamically for changing align with that running time by
|
260
|
+
> the `release` prefix.
|
261
|
+
>
|
262
|
+
> ```yaml
|
263
|
+
> schedule-run-local-wf:
|
264
|
+
>
|
265
|
+
> # Validate model that use to parsing exists for template file
|
266
|
+
> type: Schedule
|
267
|
+
> workflows:
|
268
|
+
>
|
269
|
+
> # Map existing workflow that want to deploy with scheduler application.
|
270
|
+
> # It allows you to pass release parameter that dynamic change depend on the
|
271
|
+
> # current context of this scheduler application releasing that time.
|
272
|
+
> - name: run-py-local
|
273
|
+
> params:
|
274
|
+
> source-extract: "USD-THB"
|
275
|
+
> run-date: "${{ release.logical_date }}"
|
276
|
+
> ```
|
277
|
+
>
|
278
|
+
> The main method of the `Schedule` model that use to running is `pending`. If you
|
279
|
+
> do not pass the `stop` date on this method, it will use config with
|
280
|
+
> `WORKFLOW_APP_STOP_BOUNDARY_DELTA` key for generate this stop date.
|
281
|
+
>
|
282
|
+
> ```python
|
283
|
+
> from ddeutil.workflow import Schedule
|
284
|
+
>
|
285
|
+
> (
|
286
|
+
> Schedule
|
287
|
+
> .from_conf("schedule-run-local-wf")
|
288
|
+
> .pending(stop=None)
|
289
|
+
> )
|
290
|
+
> ```
|
282
291
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
.pending(stop=None)
|
287
|
-
)
|
288
|
-
```
|
292
|
+
> [!WARNING]
|
293
|
+
> The scheduler feature is the expensive feature of this project. You should
|
294
|
+
> avoid to use it and find a scheduler tool instead.
|
289
295
|
|
290
296
|
## :cookie: Configuration
|
291
297
|
|
@@ -205,42 +205,48 @@ from ddeutil.workflow import Workflow, Result
|
|
205
205
|
|
206
206
|
workflow: Workflow = Workflow.from_conf('run-py-local')
|
207
207
|
result: Result = workflow.execute(
|
208
|
-
params={"source-extract": "USD-THB", "
|
208
|
+
params={"source-extract": "USD-THB", "run-date": "2024-01-01"}
|
209
209
|
)
|
210
210
|
```
|
211
211
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
212
|
+
> [!NOTE]
|
213
|
+
> So, this package provide the `Schedule` template for this action, and you can
|
214
|
+
> pass the parameters dynamically for changing align with that running time by
|
215
|
+
> the `release` prefix.
|
216
|
+
>
|
217
|
+
> ```yaml
|
218
|
+
> schedule-run-local-wf:
|
219
|
+
>
|
220
|
+
> # Validate model that use to parsing exists for template file
|
221
|
+
> type: Schedule
|
222
|
+
> workflows:
|
223
|
+
>
|
224
|
+
> # Map existing workflow that want to deploy with scheduler application.
|
225
|
+
> # It allows you to pass release parameter that dynamic change depend on the
|
226
|
+
> # current context of this scheduler application releasing that time.
|
227
|
+
> - name: run-py-local
|
228
|
+
> params:
|
229
|
+
> source-extract: "USD-THB"
|
230
|
+
> run-date: "${{ release.logical_date }}"
|
231
|
+
> ```
|
232
|
+
>
|
233
|
+
> The main method of the `Schedule` model that use to running is `pending`. If you
|
234
|
+
> do not pass the `stop` date on this method, it will use config with
|
235
|
+
> `WORKFLOW_APP_STOP_BOUNDARY_DELTA` key for generate this stop date.
|
236
|
+
>
|
237
|
+
> ```python
|
238
|
+
> from ddeutil.workflow import Schedule
|
239
|
+
>
|
240
|
+
> (
|
241
|
+
> Schedule
|
242
|
+
> .from_conf("schedule-run-local-wf")
|
243
|
+
> .pending(stop=None)
|
244
|
+
> )
|
245
|
+
> ```
|
237
246
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
.pending(stop=None)
|
242
|
-
)
|
243
|
-
```
|
247
|
+
> [!WARNING]
|
248
|
+
> The scheduler feature is the expensive feature of this project. You should
|
249
|
+
> avoid to use it and find a scheduler tool instead.
|
244
250
|
|
245
251
|
## :cookie: Configuration
|
246
252
|
|
@@ -25,8 +25,8 @@ classifiers = [
|
|
25
25
|
]
|
26
26
|
requires-python = ">=3.9.13"
|
27
27
|
dependencies = [
|
28
|
-
"ddeutil[checksum]>=0.4.
|
29
|
-
"ddeutil-io[yaml,toml]>=0.2.
|
28
|
+
"ddeutil[checksum]>=0.4.8",
|
29
|
+
"ddeutil-io[yaml,toml]>=0.2.12",
|
30
30
|
"pydantic==2.11.1",
|
31
31
|
"python-dotenv==1.1.0",
|
32
32
|
"schedule==1.2.2,<2.0.0",
|
@@ -57,6 +57,9 @@ docker = [
|
|
57
57
|
Homepage = "https://github.com/ddeutils/ddeutil-workflow/"
|
58
58
|
"Source Code" = "https://github.com/ddeutils/ddeutil-workflow/"
|
59
59
|
|
60
|
+
[project.scripts]
|
61
|
+
workflow-cli = "ddeutil.workflow.__main__:app"
|
62
|
+
|
60
63
|
[tool.setuptools.dynamic]
|
61
64
|
version = {attr = "ddeutil.workflow.__about__.__version__"}
|
62
65
|
|
@@ -79,9 +82,10 @@ source = ["src.ddeutil.workflow"]
|
|
79
82
|
omit = [
|
80
83
|
"src/ddeutil/workflow/__about__.py",
|
81
84
|
"src/ddeutil/workflow/__cron.py",
|
85
|
+
"src/ddeutil/workflow/__main__.py",
|
82
86
|
"src/ddeutil/workflow/api/__init__.py",
|
83
|
-
"src/ddeutil/workflow/api/
|
84
|
-
"src/ddeutil/workflow/api/
|
87
|
+
"src/ddeutil/workflow/api/logs.py",
|
88
|
+
"src/ddeutil/workflow/api/utils.py",
|
85
89
|
"src/ddeutil/workflow/api/routes/__init__.py",
|
86
90
|
"src/ddeutil/workflow/api/routes/job.py",
|
87
91
|
"src/ddeutil/workflow/api/routes/logs.py",
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__: str = "0.0.57"
|
@@ -502,10 +502,10 @@ class CronPart:
|
|
502
502
|
except IndexError:
|
503
503
|
next_value: int = -1
|
504
504
|
if value != (next_value - 1):
|
505
|
-
# NOTE:
|
505
|
+
# NOTE: `next_value` is not the subsequent number
|
506
506
|
if start_number is None:
|
507
507
|
# NOTE:
|
508
|
-
# The last number of the list
|
508
|
+
# The last number of the list `self.values` is not in a
|
509
509
|
# range.
|
510
510
|
multi_dim_values.append(value)
|
511
511
|
else:
|
@@ -703,11 +703,14 @@ class CronJob:
|
|
703
703
|
*,
|
704
704
|
tz: str | None = None,
|
705
705
|
) -> CronRunner:
|
706
|
-
"""Returns
|
707
|
-
|
706
|
+
"""Returns CronRunner instance that be datetime runner with this
|
707
|
+
cronjob. It can use `next`, `prev`, or `reset` methods to generate
|
708
|
+
running date.
|
708
709
|
|
709
|
-
:param date: An initial date that want to mark as the start
|
710
|
-
|
710
|
+
:param date: (datetime) An initial date that want to mark as the start
|
711
|
+
point. (Default is use the current datetime)
|
712
|
+
:param tz: (str) A string timezone that want to change on runner.
|
713
|
+
(Default is None)
|
711
714
|
|
712
715
|
:rtype: CronRunner
|
713
716
|
"""
|
@@ -743,6 +746,10 @@ class CronJobYear(CronJob):
|
|
743
746
|
class CronRunner:
|
744
747
|
"""Create an instance of Date Runner object for datetime generate with
|
745
748
|
cron schedule object value.
|
749
|
+
|
750
|
+
:param cron: (CronJob | CronJobYear)
|
751
|
+
:param date: (datetime)
|
752
|
+
:param tz: (str)
|
746
753
|
"""
|
747
754
|
|
748
755
|
shift_limit: ClassVar[int] = 25
|
@@ -761,11 +768,17 @@ class CronRunner:
|
|
761
768
|
cron: CronJob | CronJobYear,
|
762
769
|
date: datetime | None = None,
|
763
770
|
*,
|
764
|
-
tz: str | None = None,
|
771
|
+
tz: str | ZoneInfo | None = None,
|
765
772
|
) -> None:
|
766
|
-
|
767
|
-
self.tz: ZoneInfo = ZoneInfo("UTC")
|
773
|
+
self.tz: ZoneInfo | None = None
|
768
774
|
if tz:
|
775
|
+
if isinstance(tz, ZoneInfo):
|
776
|
+
self.tz = tz
|
777
|
+
elif not isinstance(tz, str):
|
778
|
+
raise TypeError(
|
779
|
+
"Invalid type of `tz` parameter, it should be str or "
|
780
|
+
"ZoneInfo instance."
|
781
|
+
)
|
769
782
|
try:
|
770
783
|
self.tz = ZoneInfo(tz)
|
771
784
|
except ZoneInfoNotFoundError as err:
|
@@ -777,9 +790,10 @@ class CronRunner:
|
|
777
790
|
raise ValueError(
|
778
791
|
"Input schedule start time is not a valid datetime object."
|
779
792
|
)
|
780
|
-
if tz is None:
|
781
|
-
self.
|
782
|
-
|
793
|
+
if tz is not None:
|
794
|
+
self.date: datetime = date.astimezone(self.tz)
|
795
|
+
else:
|
796
|
+
self.date: datetime = date
|
783
797
|
else:
|
784
798
|
self.date: datetime = datetime.now(tz=self.tz)
|
785
799
|
|
@@ -7,16 +7,18 @@ from .__cron import CronJob, CronRunner
|
|
7
7
|
from .__types import DictData, DictStr, Matrix, Re, TupleStr
|
8
8
|
from .conf import (
|
9
9
|
Config,
|
10
|
-
|
10
|
+
FileLoad,
|
11
11
|
config,
|
12
12
|
env,
|
13
13
|
)
|
14
|
-
from .
|
14
|
+
from .event import *
|
15
15
|
from .exceptions import *
|
16
16
|
from .job import *
|
17
17
|
from .logs import (
|
18
18
|
Audit,
|
19
19
|
AuditModel,
|
20
|
+
FileAudit,
|
21
|
+
FileTrace,
|
20
22
|
Trace,
|
21
23
|
TraceData,
|
22
24
|
TraceMeta,
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import typer
|
2
|
+
|
3
|
+
app = typer.Typer()
|
4
|
+
|
5
|
+
|
6
|
+
@app.callback()
|
7
|
+
def callback():
|
8
|
+
"""
|
9
|
+
Awesome Portal Gun
|
10
|
+
"""
|
11
|
+
|
12
|
+
|
13
|
+
@app.command()
|
14
|
+
def provision():
|
15
|
+
"""
|
16
|
+
Shoot the portal gun
|
17
|
+
"""
|
18
|
+
typer.echo("Shooting portal gun")
|
19
|
+
|
20
|
+
|
21
|
+
@app.command()
|
22
|
+
def job():
|
23
|
+
"""
|
24
|
+
Load the portal gun
|
25
|
+
"""
|
26
|
+
typer.echo("Loading portal gun")
|
27
|
+
|
28
|
+
|
29
|
+
if __name__ == "__main__":
|
30
|
+
app()
|