ddeutil-workflow 0.0.48__py3-none-any.whl → 0.0.49__py3-none-any.whl
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/__about__.py +1 -1
- ddeutil/workflow/__init__.py +4 -1
- ddeutil/workflow/api/routes/logs.py +6 -5
- ddeutil/workflow/conf.py +31 -31
- ddeutil/workflow/job.py +10 -5
- ddeutil/workflow/logs.py +144 -80
- ddeutil/workflow/result.py +8 -6
- ddeutil/workflow/reusables.py +3 -3
- ddeutil/workflow/scheduler.py +54 -44
- ddeutil/workflow/stages.py +278 -78
- ddeutil/workflow/utils.py +3 -3
- ddeutil/workflow/workflow.py +107 -87
- {ddeutil_workflow-0.0.48.dist-info → ddeutil_workflow-0.0.49.dist-info}/METADATA +3 -5
- ddeutil_workflow-0.0.49.dist-info/RECORD +31 -0
- ddeutil_workflow-0.0.48.dist-info/RECORD +0 -31
- {ddeutil_workflow-0.0.48.dist-info → ddeutil_workflow-0.0.49.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.48.dist-info → ddeutil_workflow-0.0.49.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.48.dist-info → ddeutil_workflow-0.0.49.dist-info}/top_level.txt +0 -0
ddeutil/workflow/__about__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__: str = "0.0.
|
1
|
+
__version__: str = "0.0.49"
|
ddeutil/workflow/__init__.py
CHANGED
@@ -10,7 +10,8 @@ from fastapi import APIRouter, Path, Query
|
|
10
10
|
from fastapi import status as st
|
11
11
|
from fastapi.responses import UJSONResponse
|
12
12
|
|
13
|
-
from ...logs import get_audit
|
13
|
+
from ...logs import get_audit
|
14
|
+
from ...result import Result
|
14
15
|
|
15
16
|
log_route = APIRouter(
|
16
17
|
prefix="/logs",
|
@@ -33,6 +34,7 @@ async def get_traces(
|
|
33
34
|
"""Return all trace logs from the current trace log path that config with
|
34
35
|
`WORKFLOW_LOG_PATH` environment variable name.
|
35
36
|
"""
|
37
|
+
result = Result()
|
36
38
|
return {
|
37
39
|
"message": (
|
38
40
|
f"Getting trace logs with offset: {offset} and limit: {limit}"
|
@@ -44,7 +46,7 @@ async def get_traces(
|
|
44
46
|
exclude_unset=True,
|
45
47
|
exclude_defaults=True,
|
46
48
|
)
|
47
|
-
for trace in
|
49
|
+
for trace in result.trace.find_traces()
|
48
50
|
],
|
49
51
|
}
|
50
52
|
|
@@ -63,12 +65,11 @@ async def get_trace_with_id(run_id: str):
|
|
63
65
|
- **run_id**: A running ID that want to search a trace log from the log
|
64
66
|
path.
|
65
67
|
"""
|
68
|
+
result = Result()
|
66
69
|
return {
|
67
70
|
"message": f"Getting trace log with specific running ID: {run_id}",
|
68
71
|
"trace": (
|
69
|
-
|
70
|
-
.find_log_with_id(run_id)
|
71
|
-
.model_dump(
|
72
|
+
result.trace.find_trace_with_id(run_id).model_dump(
|
72
73
|
by_alias=True,
|
73
74
|
exclude_none=True,
|
74
75
|
exclude_unset=True,
|
ddeutil/workflow/conf.py
CHANGED
@@ -11,7 +11,7 @@ from collections.abc import Iterator
|
|
11
11
|
from datetime import timedelta
|
12
12
|
from functools import cached_property
|
13
13
|
from pathlib import Path
|
14
|
-
from typing import Optional, TypeVar
|
14
|
+
from typing import Final, Optional, TypeVar
|
15
15
|
from zoneinfo import ZoneInfo
|
16
16
|
|
17
17
|
from ddeutil.core import str2bool
|
@@ -21,12 +21,15 @@ from ddeutil.io.paths import glob_files, is_ignored, read_ignore
|
|
21
21
|
from .__types import DictData, TupleStr
|
22
22
|
|
23
23
|
T = TypeVar("T")
|
24
|
-
PREFIX: str = "WORKFLOW"
|
24
|
+
PREFIX: Final[str] = "WORKFLOW"
|
25
25
|
|
26
26
|
|
27
27
|
def env(var: str, default: str | None = None) -> str | None: # pragma: no cov
|
28
28
|
"""Get environment variable with uppercase and adding prefix string.
|
29
29
|
|
30
|
+
:param var: (str) A env variable name.
|
31
|
+
:param default: (str | None) A default value if an env var does not set.
|
32
|
+
|
30
33
|
:rtype: str | None
|
31
34
|
"""
|
32
35
|
return os.getenv(f"{PREFIX}_{var.upper().replace(' ', '_')}", default)
|
@@ -51,22 +54,13 @@ class Config: # pragma: no cov
|
|
51
54
|
"""
|
52
55
|
|
53
56
|
# NOTE: Core
|
54
|
-
@property
|
55
|
-
def root_path(self) -> Path:
|
56
|
-
"""Root path or the project path for this workflow engine that use for
|
57
|
-
combine with `conf_path` value.
|
58
|
-
|
59
|
-
:rtype: Path
|
60
|
-
"""
|
61
|
-
return Path(env("CORE_ROOT_PATH", "."))
|
62
|
-
|
63
57
|
@property
|
64
58
|
def conf_path(self) -> Path:
|
65
59
|
"""Config path that keep all workflow template YAML files.
|
66
60
|
|
67
61
|
:rtype: Path
|
68
62
|
"""
|
69
|
-
return
|
63
|
+
return Path(env("CORE_CONF_PATH", "./conf"))
|
70
64
|
|
71
65
|
@property
|
72
66
|
def tz(self) -> ZoneInfo:
|
@@ -78,12 +72,12 @@ class Config: # pragma: no cov
|
|
78
72
|
return ZoneInfo(env("CORE_TIMEZONE", "UTC"))
|
79
73
|
|
80
74
|
@property
|
81
|
-
def
|
75
|
+
def generate_id_simple_mode(self) -> bool:
|
82
76
|
return str2bool(env("CORE_GENERATE_ID_SIMPLE_MODE", "true"))
|
83
77
|
|
84
78
|
# NOTE: Register
|
85
79
|
@property
|
86
|
-
def
|
80
|
+
def registry_caller(self) -> list[str]:
|
87
81
|
"""Register Caller that is a list of importable string for the call
|
88
82
|
stage model can get.
|
89
83
|
|
@@ -93,7 +87,7 @@ class Config: # pragma: no cov
|
|
93
87
|
return [r.strip() for r in regis_call_str.split(",")]
|
94
88
|
|
95
89
|
@property
|
96
|
-
def
|
90
|
+
def registry_filter(self) -> list[str]:
|
97
91
|
"""Register Filter that is a list of importable string for the filter
|
98
92
|
template.
|
99
93
|
|
@@ -106,7 +100,7 @@ class Config: # pragma: no cov
|
|
106
100
|
|
107
101
|
# NOTE: Log
|
108
102
|
@property
|
109
|
-
def
|
103
|
+
def trace_path(self) -> Path:
|
110
104
|
return Path(env("LOG_TRACE_PATH", "./logs"))
|
111
105
|
|
112
106
|
@property
|
@@ -165,11 +159,7 @@ class Config: # pragma: no cov
|
|
165
159
|
return str2bool(env("CORE_JOB_RAISE_ERROR", "true"))
|
166
160
|
|
167
161
|
@property
|
168
|
-
def
|
169
|
-
return str2bool(env("CORE_JOB_DEFAULT_ID", "false"))
|
170
|
-
|
171
|
-
@property
|
172
|
-
def max_on_per_workflow(self) -> int:
|
162
|
+
def max_cron_per_workflow(self) -> int:
|
173
163
|
"""The maximum on value that store in workflow model.
|
174
164
|
|
175
165
|
:rtype: int
|
@@ -305,23 +295,31 @@ class SimLoad:
|
|
305
295
|
)
|
306
296
|
|
307
297
|
@classmethod
|
308
|
-
def is_ignore(
|
298
|
+
def is_ignore(
|
299
|
+
cls,
|
300
|
+
file: Path,
|
301
|
+
conf_path: Path,
|
302
|
+
*,
|
303
|
+
ignore_filename: Optional[str] = None,
|
304
|
+
) -> bool:
|
309
305
|
"""Check this file was ignored.
|
310
306
|
|
311
307
|
:param file: (Path) A file path that want to check.
|
312
308
|
:param conf_path: (Path) A config path that want to read the config
|
313
309
|
ignore file.
|
310
|
+
:param ignore_filename: (str) An ignore filename.
|
314
311
|
|
315
312
|
:rtype: bool
|
316
313
|
"""
|
317
|
-
|
314
|
+
ignore_filename: str = ignore_filename or ".confignore"
|
315
|
+
return is_ignored(file, read_ignore(conf_path / ignore_filename))
|
318
316
|
|
319
317
|
@classmethod
|
320
318
|
def filter_yaml(cls, file: Path, name: str | None = None) -> DictData:
|
321
319
|
"""Read a YAML file context from an input file path and specific name.
|
322
320
|
|
323
|
-
:param file: (Path)
|
324
|
-
:param name: (str)
|
321
|
+
:param file: (Path) A file path that want to extract YAML context.
|
322
|
+
:param name: (str) A key name that search on a YAML context.
|
325
323
|
|
326
324
|
:rtype: DictData
|
327
325
|
"""
|
@@ -374,8 +372,8 @@ def dynamic(
|
|
374
372
|
class Loader(SimLoad):
|
375
373
|
"""Loader Object that get the config `yaml` file from current path.
|
376
374
|
|
377
|
-
:param name: A name of config data that will read by Yaml Loader object.
|
378
|
-
:param externals: An external parameters
|
375
|
+
:param name: (str) A name of config data that will read by Yaml Loader object.
|
376
|
+
:param externals: (DictData) An external parameters
|
379
377
|
"""
|
380
378
|
|
381
379
|
@classmethod
|
@@ -383,17 +381,19 @@ class Loader(SimLoad):
|
|
383
381
|
cls,
|
384
382
|
obj: object,
|
385
383
|
*,
|
384
|
+
path: Path | None = None,
|
386
385
|
included: list[str] | None = None,
|
387
386
|
excluded: list[str] | None = None,
|
388
|
-
path: Path | None = None,
|
389
387
|
**kwargs,
|
390
388
|
) -> Iterator[tuple[str, DictData]]:
|
391
389
|
"""Override the find class method from the Simple Loader object.
|
392
390
|
|
393
391
|
:param obj: An object that want to validate matching before return.
|
394
|
-
:param
|
395
|
-
:param excluded
|
396
|
-
|
392
|
+
:param path: (Path) A override config path.
|
393
|
+
:param included: An excluded list of data key that want to reject this
|
394
|
+
data if any key exist.
|
395
|
+
:param excluded: An included list of data key that want to filter from
|
396
|
+
data.
|
397
397
|
|
398
398
|
:rtype: Iterator[tuple[str, DictData]]
|
399
399
|
"""
|
ddeutil/workflow/job.py
CHANGED
@@ -483,7 +483,13 @@ class Job(BaseModel):
|
|
483
483
|
except Exception as err:
|
484
484
|
raise JobException(f"{err.__class__.__name__}: {err}") from err
|
485
485
|
|
486
|
-
def set_outputs(
|
486
|
+
def set_outputs(
|
487
|
+
self,
|
488
|
+
output: DictData,
|
489
|
+
to: DictData,
|
490
|
+
*,
|
491
|
+
job_id: Optional[None] = None,
|
492
|
+
) -> DictData:
|
487
493
|
"""Set an outputs from execution process to the received context. The
|
488
494
|
result from execution will pass to value of `strategies` key.
|
489
495
|
|
@@ -511,22 +517,21 @@ class Job(BaseModel):
|
|
511
517
|
|
512
518
|
:param output: An output context.
|
513
519
|
:param to: A context data that want to add output result.
|
520
|
+
:param job_id: A job ID if the id field does not set.
|
514
521
|
|
515
522
|
:rtype: DictData
|
516
523
|
"""
|
517
524
|
if "jobs" not in to:
|
518
525
|
to["jobs"] = {}
|
519
526
|
|
520
|
-
if self.id is None and
|
521
|
-
"job_default_id", extras=self.extras
|
522
|
-
):
|
527
|
+
if self.id is None and job_id is None:
|
523
528
|
raise JobException(
|
524
529
|
"This job do not set the ID before setting execution output."
|
525
530
|
)
|
526
531
|
|
527
532
|
# NOTE: If the job ID did not set, it will use index of jobs key
|
528
533
|
# instead.
|
529
|
-
_id: str = self.id or
|
534
|
+
_id: str = self.id or job_id
|
530
535
|
|
531
536
|
errors: DictData = (
|
532
537
|
{"errors": output.pop("errors", {})} if "errors" in output else {}
|
ddeutil/workflow/logs.py
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
# Licensed under the MIT License. See LICENSE in the project root for
|
4
4
|
# license information.
|
5
5
|
# ------------------------------------------------------------------------------
|
6
|
-
# [x] Use
|
7
|
-
|
6
|
+
# [x] Use dynamic config
|
7
|
+
# [x] Use fix config for `get_logger`, and Model initialize step.
|
8
|
+
"""A Logs module contain Trace dataclass and Audit Pydantic model.
|
8
9
|
"""
|
9
10
|
from __future__ import annotations
|
10
11
|
|
@@ -19,14 +20,14 @@ from functools import lru_cache
|
|
19
20
|
from inspect import Traceback, currentframe, getframeinfo
|
20
21
|
from pathlib import Path
|
21
22
|
from threading import get_ident
|
22
|
-
from typing import ClassVar, Literal, Optional, Union
|
23
|
+
from typing import ClassVar, Literal, Optional, TypeVar, Union
|
23
24
|
|
24
|
-
from pydantic import BaseModel, Field
|
25
|
+
from pydantic import BaseModel, Field
|
25
26
|
from pydantic.dataclasses import dataclass
|
26
27
|
from pydantic.functional_validators import model_validator
|
27
28
|
from typing_extensions import Self
|
28
29
|
|
29
|
-
from .__types import DictData, DictStr
|
30
|
+
from .__types import DictData, DictStr
|
30
31
|
from .conf import config, dynamic
|
31
32
|
from .utils import cut_id, get_dt_now
|
32
33
|
|
@@ -60,22 +61,6 @@ def get_logger(name: str):
|
|
60
61
|
|
61
62
|
logger = get_logger("ddeutil.workflow")
|
62
63
|
|
63
|
-
__all__: TupleStr = (
|
64
|
-
"FileTraceLog",
|
65
|
-
"SQLiteTraceLog",
|
66
|
-
"TraceData",
|
67
|
-
"TraceMeta",
|
68
|
-
"TraceLog",
|
69
|
-
"get_dt_tznow",
|
70
|
-
"get_logger",
|
71
|
-
"get_trace",
|
72
|
-
"get_trace_obj",
|
73
|
-
"get_audit",
|
74
|
-
"FileAudit",
|
75
|
-
"SQLiteAudit",
|
76
|
-
"Audit",
|
77
|
-
)
|
78
|
-
|
79
64
|
|
80
65
|
def get_dt_tznow() -> datetime: # pragma: no cov
|
81
66
|
"""Return the current datetime object that passing the config timezone.
|
@@ -170,13 +155,39 @@ class TraceData(BaseModel): # pragma: no cov
|
|
170
155
|
|
171
156
|
|
172
157
|
@dataclass(frozen=True)
|
173
|
-
class
|
174
|
-
"""Base Trace
|
158
|
+
class BaseTrace(ABC): # pragma: no cov
|
159
|
+
"""Base Trace dataclass with abstraction class property."""
|
175
160
|
|
176
161
|
run_id: str
|
177
162
|
parent_run_id: Optional[str] = field(default=None)
|
178
163
|
extras: DictData = field(default_factory=dict, compare=False, repr=False)
|
179
164
|
|
165
|
+
@classmethod
|
166
|
+
@abstractmethod
|
167
|
+
def find_traces(
|
168
|
+
cls,
|
169
|
+
path: Path | None = None,
|
170
|
+
extras: Optional[DictData] = None,
|
171
|
+
) -> Iterator[TraceData]: # pragma: no cov
|
172
|
+
raise NotImplementedError(
|
173
|
+
"Trace dataclass should implement `find_traces` class-method."
|
174
|
+
)
|
175
|
+
|
176
|
+
@classmethod
|
177
|
+
@abstractmethod
|
178
|
+
def find_trace_with_id(
|
179
|
+
cls,
|
180
|
+
run_id: str,
|
181
|
+
force_raise: bool = True,
|
182
|
+
*,
|
183
|
+
path: Path | None = None,
|
184
|
+
extras: Optional[DictData] = None,
|
185
|
+
) -> TraceData:
|
186
|
+
raise NotImplementedError(
|
187
|
+
"Trace dataclass should implement `find_trace_with_id` "
|
188
|
+
"class-method."
|
189
|
+
)
|
190
|
+
|
180
191
|
@abstractmethod
|
181
192
|
def writer(self, message: str, is_err: bool = False) -> None:
|
182
193
|
"""Write a trace message after making to target pointer object. The
|
@@ -318,11 +329,11 @@ class BaseTraceLog(ABC): # pragma: no cov
|
|
318
329
|
logger.exception(msg, stacklevel=2)
|
319
330
|
|
320
331
|
|
321
|
-
class
|
322
|
-
"""Trace
|
332
|
+
class FileTrace(BaseTrace): # pragma: no cov
|
333
|
+
"""File Trace dataclass that write file to the local storage."""
|
323
334
|
|
324
335
|
@classmethod
|
325
|
-
def
|
336
|
+
def find_traces(
|
326
337
|
cls,
|
327
338
|
path: Path | None = None,
|
328
339
|
extras: Optional[DictData] = None,
|
@@ -333,13 +344,13 @@ class FileTraceLog(BaseTraceLog): # pragma: no cov
|
|
333
344
|
:param extras: An extra parameter that want to override core config.
|
334
345
|
"""
|
335
346
|
for file in sorted(
|
336
|
-
(path or dynamic("
|
347
|
+
(path or dynamic("trace_path", extras=extras)).glob("./run_id=*"),
|
337
348
|
key=lambda f: f.lstat().st_mtime,
|
338
349
|
):
|
339
350
|
yield TraceData.from_path(file)
|
340
351
|
|
341
352
|
@classmethod
|
342
|
-
def
|
353
|
+
def find_trace_with_id(
|
343
354
|
cls,
|
344
355
|
run_id: str,
|
345
356
|
force_raise: bool = True,
|
@@ -354,7 +365,7 @@ class FileTraceLog(BaseTraceLog): # pragma: no cov
|
|
354
365
|
:param path:
|
355
366
|
:param extras: An extra parameter that want to override core config.
|
356
367
|
"""
|
357
|
-
base_path: Path = path or dynamic("
|
368
|
+
base_path: Path = path or dynamic("trace_path", extras=extras)
|
358
369
|
file: Path = base_path / f"run_id={run_id}"
|
359
370
|
if file.exists():
|
360
371
|
return TraceData.from_path(file)
|
@@ -368,7 +379,7 @@ class FileTraceLog(BaseTraceLog): # pragma: no cov
|
|
368
379
|
@property
|
369
380
|
def pointer(self) -> Path:
|
370
381
|
log_file: Path = (
|
371
|
-
dynamic("
|
382
|
+
dynamic("trace_path", extras=self.extras)
|
372
383
|
/ f"run_id={self.parent_run_id or self.run_id}"
|
373
384
|
)
|
374
385
|
if not log_file.exists():
|
@@ -453,8 +464,8 @@ class FileTraceLog(BaseTraceLog): # pragma: no cov
|
|
453
464
|
await f.write(trace_meta.model_dump_json() + "\n")
|
454
465
|
|
455
466
|
|
456
|
-
class
|
457
|
-
"""Trace
|
467
|
+
class SQLiteTrace(BaseTrace): # pragma: no cov
|
468
|
+
"""SQLite Trace dataclass that write trace log to the SQLite database file."""
|
458
469
|
|
459
470
|
table_name: ClassVar[str] = "audits"
|
460
471
|
schemas: ClassVar[
|
@@ -468,10 +479,21 @@ class SQLiteTraceLog(BaseTraceLog): # pragma: no cov
|
|
468
479
|
"""
|
469
480
|
|
470
481
|
@classmethod
|
471
|
-
def
|
482
|
+
def find_traces(
|
483
|
+
cls,
|
484
|
+
path: Path | None = None,
|
485
|
+
extras: Optional[DictData] = None,
|
486
|
+
) -> Iterator[TraceData]: ...
|
472
487
|
|
473
488
|
@classmethod
|
474
|
-
def
|
489
|
+
def find_trace_with_id(
|
490
|
+
cls,
|
491
|
+
run_id: str,
|
492
|
+
force_raise: bool = True,
|
493
|
+
*,
|
494
|
+
path: Path | None = None,
|
495
|
+
extras: Optional[DictData] = None,
|
496
|
+
) -> TraceData: ...
|
475
497
|
|
476
498
|
def make_message(self, message: str) -> str: ...
|
477
499
|
|
@@ -480,47 +502,34 @@ class SQLiteTraceLog(BaseTraceLog): # pragma: no cov
|
|
480
502
|
def awriter(self, message: str, is_err: bool = False) -> None: ...
|
481
503
|
|
482
504
|
|
483
|
-
|
484
|
-
|
485
|
-
|
505
|
+
Trace = TypeVar("Trace", bound=BaseTrace)
|
506
|
+
TraceModel = Union[
|
507
|
+
FileTrace,
|
508
|
+
SQLiteTrace,
|
486
509
|
]
|
487
510
|
|
488
511
|
|
489
512
|
def get_trace(
|
490
513
|
run_id: str,
|
491
|
-
parent_run_id: str | None = None,
|
492
514
|
*,
|
515
|
+
parent_run_id: str | None = None,
|
493
516
|
extras: Optional[DictData] = None,
|
494
|
-
) ->
|
495
|
-
"""Get dynamic
|
517
|
+
) -> TraceModel: # pragma: no cov
|
518
|
+
"""Get dynamic Trace instance from the core config (it can override by an
|
519
|
+
extras argument) that passing running ID and parent running ID.
|
496
520
|
|
497
|
-
:param run_id: A running ID.
|
498
|
-
:param parent_run_id: A parent running ID.
|
499
|
-
:param extras: An extra parameter that want to override the core
|
521
|
+
:param run_id: (str) A running ID.
|
522
|
+
:param parent_run_id: (str) A parent running ID.
|
523
|
+
:param extras: (DictData) An extra parameter that want to override the core
|
524
|
+
config values.
|
500
525
|
|
501
526
|
:rtype: TraceLog
|
502
527
|
"""
|
503
|
-
if dynamic("
|
504
|
-
return
|
528
|
+
if dynamic("trace_path", extras=extras).is_file():
|
529
|
+
return SQLiteTrace(
|
505
530
|
run_id, parent_run_id=parent_run_id, extras=(extras or {})
|
506
531
|
)
|
507
|
-
return
|
508
|
-
run_id, parent_run_id=parent_run_id, extras=(extras or {})
|
509
|
-
)
|
510
|
-
|
511
|
-
|
512
|
-
def get_trace_obj(
|
513
|
-
extras: Optional[DictData] = None,
|
514
|
-
) -> type[TraceLog]: # pragma: no cov
|
515
|
-
"""Get trace object.
|
516
|
-
|
517
|
-
:param extras: An extra parameter that want to override the core config.
|
518
|
-
|
519
|
-
:rtype: type[TraceLog]
|
520
|
-
"""
|
521
|
-
if dynamic("log_path", extras=extras).is_file():
|
522
|
-
return SQLiteTraceLog
|
523
|
-
return FileTraceLog
|
532
|
+
return FileTrace(run_id, parent_run_id=parent_run_id, extras=(extras or {}))
|
524
533
|
|
525
534
|
|
526
535
|
class BaseAudit(BaseModel, ABC):
|
@@ -548,15 +557,50 @@ class BaseAudit(BaseModel, ABC):
|
|
548
557
|
execution_time: float = Field(default=0, description="An execution time.")
|
549
558
|
|
550
559
|
@model_validator(mode="after")
|
551
|
-
def __model_action(self
|
560
|
+
def __model_action(self) -> Self:
|
552
561
|
"""Do before the Audit action with WORKFLOW_AUDIT_ENABLE_WRITE env variable.
|
553
562
|
|
554
563
|
:rtype: Self
|
555
564
|
"""
|
556
|
-
if dynamic("enable_write_audit", extras=
|
565
|
+
if dynamic("enable_write_audit", extras=self.extras):
|
557
566
|
self.do_before()
|
558
567
|
return self
|
559
568
|
|
569
|
+
@classmethod
|
570
|
+
@abstractmethod
|
571
|
+
def is_pointed(
|
572
|
+
cls,
|
573
|
+
name: str,
|
574
|
+
release: datetime,
|
575
|
+
*,
|
576
|
+
extras: Optional[DictData] = None,
|
577
|
+
) -> bool:
|
578
|
+
raise NotImplementedError(
|
579
|
+
"Audit should implement `is_pointed` class-method"
|
580
|
+
)
|
581
|
+
|
582
|
+
@classmethod
|
583
|
+
@abstractmethod
|
584
|
+
def find_audits(
|
585
|
+
cls, name: str, *, extras: Optional[DictData] = None
|
586
|
+
) -> Iterator[Self]:
|
587
|
+
raise NotImplementedError(
|
588
|
+
"Audit should implement `find_audits` class-method"
|
589
|
+
)
|
590
|
+
|
591
|
+
@classmethod
|
592
|
+
@abstractmethod
|
593
|
+
def find_audit_with_release(
|
594
|
+
cls,
|
595
|
+
name: str,
|
596
|
+
release: datetime | None = None,
|
597
|
+
*,
|
598
|
+
extras: Optional[DictData] = None,
|
599
|
+
) -> Self:
|
600
|
+
raise NotImplementedError(
|
601
|
+
"Audit should implement `find_audit_with_release` class-method"
|
602
|
+
)
|
603
|
+
|
560
604
|
def do_before(self) -> None: # pragma: no cov
|
561
605
|
"""To something before end up of initial log model."""
|
562
606
|
|
@@ -688,7 +732,11 @@ class FileAudit(BaseAudit):
|
|
688
732
|
|
689
733
|
:rtype: Self
|
690
734
|
"""
|
691
|
-
trace:
|
735
|
+
trace: Trace = get_trace(
|
736
|
+
self.run_id,
|
737
|
+
parent_run_id=self.parent_run_id,
|
738
|
+
extras=self.extras,
|
739
|
+
)
|
692
740
|
|
693
741
|
# NOTE: Check environ variable was set for real writing.
|
694
742
|
if not dynamic("enable_write_audit", extras=self.extras):
|
@@ -726,11 +774,38 @@ class SQLiteAudit(BaseAudit): # pragma: no cov
|
|
726
774
|
primary key ( run_id )
|
727
775
|
"""
|
728
776
|
|
777
|
+
@classmethod
|
778
|
+
def is_pointed(
|
779
|
+
cls,
|
780
|
+
name: str,
|
781
|
+
release: datetime,
|
782
|
+
*,
|
783
|
+
extras: Optional[DictData] = None,
|
784
|
+
) -> bool: ...
|
785
|
+
|
786
|
+
@classmethod
|
787
|
+
def find_audits(
|
788
|
+
cls, name: str, *, extras: Optional[DictData] = None
|
789
|
+
) -> Iterator[Self]: ...
|
790
|
+
|
791
|
+
@classmethod
|
792
|
+
def find_audit_with_release(
|
793
|
+
cls,
|
794
|
+
name: str,
|
795
|
+
release: datetime | None = None,
|
796
|
+
*,
|
797
|
+
extras: Optional[DictData] = None,
|
798
|
+
) -> Self: ...
|
799
|
+
|
729
800
|
def save(self, excluded: list[str] | None) -> SQLiteAudit:
|
730
801
|
"""Save logging data that receive a context data from a workflow
|
731
802
|
execution result.
|
732
803
|
"""
|
733
|
-
trace:
|
804
|
+
trace: Trace = get_trace(
|
805
|
+
self.run_id,
|
806
|
+
parent_run_id=self.parent_run_id,
|
807
|
+
extras=self.extras,
|
808
|
+
)
|
734
809
|
|
735
810
|
# NOTE: Check environ variable was set for real writing.
|
736
811
|
if not dynamic("enable_write_audit", extras=self.extras):
|
@@ -740,19 +815,8 @@ class SQLiteAudit(BaseAudit): # pragma: no cov
|
|
740
815
|
raise NotImplementedError("SQLiteAudit does not implement yet.")
|
741
816
|
|
742
817
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
def save(self, excluded: list[str] | None) -> RemoteFileAudit: ...
|
747
|
-
|
748
|
-
|
749
|
-
class RedisAudit(BaseAudit): # pragma: no cov
|
750
|
-
"""Redis Audit Pydantic Model."""
|
751
|
-
|
752
|
-
def save(self, excluded: list[str] | None) -> RedisAudit: ...
|
753
|
-
|
754
|
-
|
755
|
-
Audit = Union[
|
818
|
+
Audit = TypeVar("Audit", bound=BaseAudit)
|
819
|
+
AuditModel = Union[
|
756
820
|
FileAudit,
|
757
821
|
SQLiteAudit,
|
758
822
|
]
|
@@ -760,7 +824,7 @@ Audit = Union[
|
|
760
824
|
|
761
825
|
def get_audit(
|
762
826
|
extras: Optional[DictData] = None,
|
763
|
-
) -> type[
|
827
|
+
) -> type[AuditModel]: # pragma: no cov
|
764
828
|
"""Get an audit class that dynamic base on the config audit path value.
|
765
829
|
|
766
830
|
:param extras: An extra parameter that want to override the core config.
|
ddeutil/workflow/result.py
CHANGED
@@ -21,7 +21,7 @@ from typing_extensions import Self
|
|
21
21
|
|
22
22
|
from .__types import DictData
|
23
23
|
from .conf import dynamic
|
24
|
-
from .logs import
|
24
|
+
from .logs import Trace, get_dt_tznow, get_trace
|
25
25
|
from .utils import default_gen_id, gen_id, get_dt_now
|
26
26
|
|
27
27
|
|
@@ -68,7 +68,7 @@ class Result:
|
|
68
68
|
parent_run_id: Optional[str] = field(default=None, compare=False)
|
69
69
|
ts: datetime = field(default_factory=get_dt_tznow, compare=False)
|
70
70
|
|
71
|
-
trace: Optional[
|
71
|
+
trace: Optional[Trace] = field(default=None, compare=False, repr=False)
|
72
72
|
extras: DictData = field(default_factory=dict, compare=False, repr=False)
|
73
73
|
|
74
74
|
@classmethod
|
@@ -113,8 +113,10 @@ class Result:
|
|
113
113
|
:rtype: Self
|
114
114
|
"""
|
115
115
|
if self.trace is None: # pragma: no cov
|
116
|
-
self.trace:
|
117
|
-
self.run_id,
|
116
|
+
self.trace: Trace = get_trace(
|
117
|
+
self.run_id,
|
118
|
+
parent_run_id=self.parent_run_id,
|
119
|
+
extras=self.extras,
|
118
120
|
)
|
119
121
|
return self
|
120
122
|
|
@@ -126,8 +128,8 @@ class Result:
|
|
126
128
|
:rtype: Self
|
127
129
|
"""
|
128
130
|
self.parent_run_id: str = running_id
|
129
|
-
self.trace:
|
130
|
-
self.run_id, running_id, extras=self.extras
|
131
|
+
self.trace: Trace = get_trace(
|
132
|
+
self.run_id, parent_run_id=running_id, extras=self.extras
|
131
133
|
)
|
132
134
|
return self
|
133
135
|
|