ddeutil-workflow 0.0.56__tar.gz → 0.0.58__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.56 → ddeutil_workflow-0.0.58}/PKG-INFO +41 -35
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/README.md +38 -32
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/pyproject.toml +4 -3
- ddeutil_workflow-0.0.58/src/ddeutil/workflow/__about__.py +1 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/__cron.py +26 -12
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/__types.py +1 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/conf.py +21 -9
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/event.py +11 -10
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/exceptions.py +33 -12
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/job.py +89 -58
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/logs.py +59 -37
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/params.py +4 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/result.py +9 -4
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/scheduler.py +15 -9
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/stages.py +441 -171
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/utils.py +37 -6
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/workflow.py +218 -243
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil_workflow.egg-info/PKG-INFO +41 -35
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil_workflow.egg-info/SOURCES.txt +2 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil_workflow.egg-info/requires.txt +2 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test__cron.py +28 -16
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_conf.py +81 -10
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_event.py +52 -27
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_job.py +20 -21
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_job_exec.py +93 -68
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_job_exec_strategy.py +9 -20
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_params.py +1 -4
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_release.py +7 -20
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_release_queue.py +1 -1
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_result.py +16 -28
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_schedule.py +3 -3
- ddeutil_workflow-0.0.58/tests/test_stage_handler_exec.py +966 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_utils.py +28 -1
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_workflow.py +13 -3
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_workflow_exec.py +158 -137
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_workflow_exec_job.py +10 -28
- ddeutil_workflow-0.0.58/tests/test_workflow_poke.py +168 -0
- ddeutil_workflow-0.0.58/tests/test_workflow_release.py +153 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_workflow_task.py +44 -16
- ddeutil_workflow-0.0.56/src/ddeutil/workflow/__about__.py +0 -1
- ddeutil_workflow-0.0.56/tests/test_stage_handler_exec.py +0 -1149
- ddeutil_workflow-0.0.56/tests/test_workflow_exec_poke.py +0 -171
- ddeutil_workflow-0.0.56/tests/test_workflow_exec_release.py +0 -125
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/LICENSE +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/__init__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/__main__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/__init__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/logs.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/routes/job.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/routes/logs.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/api/utils.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil/workflow/reusables.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil_workflow.egg-info/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test__regex.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_logs_audit.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_logs_trace.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_reusables_call_tag.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_reusables_template.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_reusables_template_filter.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_schedule_pending.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_schedule_tasks.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_schedule_workflow.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_scheduler_control.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/tests/test_stage.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.58}/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.58
|
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",
|
@@ -82,8 +82,9 @@ source = ["src.ddeutil.workflow"]
|
|
82
82
|
omit = [
|
83
83
|
"src/ddeutil/workflow/__about__.py",
|
84
84
|
"src/ddeutil/workflow/__cron.py",
|
85
|
+
"src/ddeutil/workflow/__main__.py",
|
85
86
|
"src/ddeutil/workflow/api/__init__.py",
|
86
|
-
"src/ddeutil/workflow/api/
|
87
|
+
"src/ddeutil/workflow/api/logs.py",
|
87
88
|
"src/ddeutil/workflow/api/utils.py",
|
88
89
|
"src/ddeutil/workflow/api/routes/__init__.py",
|
89
90
|
"src/ddeutil/workflow/api/routes/job.py",
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__: str = "0.0.58"
|
@@ -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
|
|
@@ -200,7 +200,10 @@ class APIConfig:
|
|
200
200
|
return str2bool(env("API_ENABLE_ROUTE_SCHEDULE", "true"))
|
201
201
|
|
202
202
|
|
203
|
-
class BaseLoad(ABC):
|
203
|
+
class BaseLoad(ABC): # pragma: no cov
|
204
|
+
"""Base Load object is the abstraction object for any Load object that
|
205
|
+
should to inherit from this base class.
|
206
|
+
"""
|
204
207
|
|
205
208
|
@classmethod
|
206
209
|
@abstractmethod
|
@@ -215,7 +218,7 @@ class BaseLoad(ABC):
|
|
215
218
|
|
216
219
|
class FileLoad(BaseLoad):
|
217
220
|
"""Base Load object that use to search config data by given some identity
|
218
|
-
value like name of `Workflow` or `
|
221
|
+
value like name of `Workflow` or `Crontab` templates.
|
219
222
|
|
220
223
|
:param name: (str) A name of key of config data that read with YAML
|
221
224
|
Environment object.
|
@@ -335,8 +338,13 @@ class FileLoad(BaseLoad):
|
|
335
338
|
"""
|
336
339
|
excluded: list[str] = excluded or []
|
337
340
|
path: Path = dynamic("conf_path", f=path, extras=extras)
|
341
|
+
paths: Optional[list[Path]] = paths or (extras or {}).get("conf_paths")
|
338
342
|
if not paths:
|
339
343
|
paths: list[Path] = [path]
|
344
|
+
elif not isinstance(paths, list):
|
345
|
+
raise TypeError(
|
346
|
+
f"Multi-config paths does not support for type: {type(paths)}"
|
347
|
+
)
|
340
348
|
else:
|
341
349
|
paths.append(path)
|
342
350
|
|
@@ -431,17 +439,21 @@ def dynamic(
|
|
431
439
|
"""Dynamic get config if extra value was passed at run-time.
|
432
440
|
|
433
441
|
:param key: (str) A config key that get from Config object.
|
434
|
-
:param f: An inner config function scope.
|
442
|
+
:param f: (T) An inner config function scope.
|
435
443
|
:param extras: An extra values that pass at run-time.
|
444
|
+
|
445
|
+
:rtype: T
|
436
446
|
"""
|
437
|
-
|
438
|
-
|
439
|
-
if
|
447
|
+
extra: Optional[T] = (extras or {}).get(key, None)
|
448
|
+
conf: Optional[T] = getattr(config, key, None) if f is None else f
|
449
|
+
if extra is None:
|
450
|
+
return conf
|
451
|
+
if not isinstance(extra, type(conf)):
|
440
452
|
raise TypeError(
|
441
|
-
f"Type of config {key!r} from extras: {
|
442
|
-
f"as config {type(
|
453
|
+
f"Type of config {key!r} from extras: {extra!r} does not valid "
|
454
|
+
f"as config {type(conf)}."
|
443
455
|
)
|
444
|
-
return
|
456
|
+
return extra
|
445
457
|
|
446
458
|
|
447
459
|
class Loader(Protocol): # pragma: no cov
|
@@ -3,8 +3,8 @@
|
|
3
3
|
# Licensed under the MIT License. See LICENSE in the project root for
|
4
4
|
# license information.
|
5
5
|
# ------------------------------------------------------------------------------
|
6
|
-
"""Event module that store all event object. Now, it has only `
|
7
|
-
model these are schedule with crontab event.
|
6
|
+
"""Event module that store all event object. Now, it has only `Crontab` and
|
7
|
+
`CrontabYear` model these are schedule with crontab event.
|
8
8
|
"""
|
9
9
|
from __future__ import annotations
|
10
10
|
|
@@ -63,9 +63,9 @@ def interval2crontab(
|
|
63
63
|
return f"{h} {m} {'1' if interval == 'monthly' else '*'} * {d}"
|
64
64
|
|
65
65
|
|
66
|
-
class
|
67
|
-
"""
|
68
|
-
and generate CronRunner object from this crontab value.
|
66
|
+
class Crontab(BaseModel):
|
67
|
+
"""Cron event model (Warped the CronJob object by Pydantic model) to keep
|
68
|
+
crontab value and generate CronRunner object from this crontab value.
|
69
69
|
|
70
70
|
Methods:
|
71
71
|
- generate: is the main use-case of this schedule object.
|
@@ -117,6 +117,7 @@ class On(BaseModel):
|
|
117
117
|
passing["cronjob"] = interval2crontab(
|
118
118
|
**{v: value[v] for v in value if v in ("interval", "day", "time")}
|
119
119
|
)
|
120
|
+
print(passing)
|
120
121
|
return cls(extras=extras | passing.pop("extras", {}), **passing)
|
121
122
|
|
122
123
|
@classmethod
|
@@ -127,7 +128,7 @@ class On(BaseModel):
|
|
127
128
|
extras: DictData | None = None,
|
128
129
|
) -> Self:
|
129
130
|
"""Constructor from the name of config loader that will use loader
|
130
|
-
object for getting the `
|
131
|
+
object for getting the `Crontab` data.
|
131
132
|
|
132
133
|
:param name: (str) A name of config that will get from loader.
|
133
134
|
:param extras: (DictData) An extra parameter that use to override core
|
@@ -171,7 +172,7 @@ class On(BaseModel):
|
|
171
172
|
def __prepare_values(cls, data: Any) -> Any:
|
172
173
|
"""Extract tz key from value and change name to timezone key.
|
173
174
|
|
174
|
-
:param data: (DictData) A data that want to pass for create an
|
175
|
+
:param data: (DictData) A data that want to pass for create an Crontab
|
175
176
|
model.
|
176
177
|
|
177
178
|
:rtype: DictData
|
@@ -264,9 +265,9 @@ class On(BaseModel):
|
|
264
265
|
return runner
|
265
266
|
|
266
267
|
|
267
|
-
class
|
268
|
-
"""
|
269
|
-
some data schedule tools like AWS Glue.
|
268
|
+
class CrontabYear(Crontab):
|
269
|
+
"""Cron event with enhance Year Pydantic model for limit year matrix that
|
270
|
+
use by some data schedule tools like AWS Glue.
|
270
271
|
"""
|
271
272
|
|
272
273
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
@@ -9,16 +9,16 @@ annotate for handle error only.
|
|
9
9
|
"""
|
10
10
|
from __future__ import annotations
|
11
11
|
|
12
|
-
from typing import TypedDict
|
12
|
+
from typing import Literal, TypedDict, overload
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
|
15
|
+
class ErrorData(TypedDict):
|
16
|
+
"""Error data type dict for typing necessary keys of return of to_dict func
|
17
|
+
and method.
|
18
|
+
"""
|
19
|
+
|
20
|
+
name: str
|
21
|
+
message: str
|
22
22
|
|
23
23
|
|
24
24
|
def to_dict(exception: Exception) -> ErrorData: # pragma: no cov
|
@@ -29,20 +29,41 @@ def to_dict(exception: Exception) -> ErrorData: # pragma: no cov
|
|
29
29
|
:rtype: ErrorData
|
30
30
|
"""
|
31
31
|
return {
|
32
|
-
"class": exception,
|
33
32
|
"name": exception.__class__.__name__,
|
34
33
|
"message": str(exception),
|
35
34
|
}
|
36
35
|
|
37
36
|
|
38
37
|
class BaseWorkflowException(Exception):
|
38
|
+
"""Base Workflow exception class will implement the `refs` argument for
|
39
|
+
making an error context to the result context.
|
40
|
+
"""
|
41
|
+
|
42
|
+
def __init__(self, message: str, *, refs: str | None = None):
|
43
|
+
super().__init__(message)
|
44
|
+
self.refs: str | None = refs
|
45
|
+
|
46
|
+
@overload
|
47
|
+
def to_dict(
|
48
|
+
self, with_refs: Literal[True] = ...
|
49
|
+
) -> dict[str, ErrorData]: ... # pragma: no cov
|
50
|
+
|
51
|
+
@overload
|
52
|
+
def to_dict(
|
53
|
+
self, with_refs: Literal[False] = ...
|
54
|
+
) -> ErrorData: ... # pragma: no cov
|
39
55
|
|
40
|
-
def to_dict(
|
56
|
+
def to_dict(
|
57
|
+
self, with_refs: bool = False
|
58
|
+
) -> ErrorData | dict[str, ErrorData]:
|
41
59
|
"""Return ErrorData data from the current exception object.
|
42
60
|
|
43
61
|
:rtype: ErrorData
|
44
62
|
"""
|
45
|
-
|
63
|
+
data: ErrorData = to_dict(self)
|
64
|
+
if with_refs and (self.refs is not None and self.refs != "EMPTY"):
|
65
|
+
return {self.refs: data}
|
66
|
+
return data
|
46
67
|
|
47
68
|
|
48
69
|
class UtilException(BaseWorkflowException): ...
|