ddeutil-workflow 0.0.56__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.56 → ddeutil_workflow-0.0.57}/PKG-INFO +41 -35
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/README.md +38 -32
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/pyproject.toml +4 -3
- ddeutil_workflow-0.0.57/src/ddeutil/workflow/__about__.py +1 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__cron.py +26 -12
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__types.py +1 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/conf.py +20 -8
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/event.py +1 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/exceptions.py +33 -12
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/job.py +81 -57
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/logs.py +13 -5
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/result.py +9 -4
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/scheduler.py +6 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/stages.py +370 -147
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/utils.py +37 -6
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/workflow.py +205 -230
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/PKG-INFO +41 -35
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/SOURCES.txt +2 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/requires.txt +2 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test__cron.py +28 -16
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_conf.py +81 -10
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_event.py +25 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_job.py +20 -21
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_job_exec.py +93 -68
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_job_exec_strategy.py +9 -20
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_params.py +1 -4
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_release.py +7 -20
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_release_queue.py +1 -1
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_result.py +16 -28
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_stage_handler_exec.py +220 -182
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_utils.py +28 -1
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_workflow.py +12 -2
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_workflow_exec.py +158 -137
- {ddeutil_workflow-0.0.56 → 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.56 → ddeutil_workflow-0.0.57}/tests/test_workflow_task.py +34 -13
- ddeutil_workflow-0.0.56/src/ddeutil/workflow/__about__.py +0 -1
- 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.57}/LICENSE +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__init__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/__main__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/__init__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/logs.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/__init__.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/job.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/logs.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/schedules.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/routes/workflows.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/api/utils.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/params.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil/workflow/reusables.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test__regex.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_logs_audit.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_logs_trace.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_reusables_call_tag.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_reusables_template.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_reusables_template_filter.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_schedule.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_schedule_pending.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_schedule_tasks.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_schedule_workflow.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_scheduler_control.py +0 -0
- {ddeutil_workflow-0.0.56 → ddeutil_workflow-0.0.57}/tests/test_stage.py +0 -0
- {ddeutil_workflow-0.0.56 → 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",
|
@@ -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.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
|
|
@@ -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
|
@@ -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
|
@@ -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): ...
|