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.
@@ -1 +1 @@
1
- __version__: str = "0.0.48"
1
+ __version__: str = "0.0.49"
@@ -32,8 +32,11 @@ from .job import (
32
32
  )
33
33
  from .logs import (
34
34
  Audit,
35
+ AuditModel,
36
+ Trace,
35
37
  TraceData,
36
- TraceLog,
38
+ TraceMeta,
39
+ TraceModel,
37
40
  get_audit,
38
41
  get_dt_tznow,
39
42
  get_trace,
@@ -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, get_trace_obj
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 get_trace_obj().find_logs()
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
- get_trace_obj()
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 self.root_path / env("CORE_CONF_PATH", "conf")
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 gen_id_simple_mode(self) -> bool:
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 regis_call(self) -> list[str]:
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 regis_filter(self) -> list[str]:
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 log_path(self) -> Path:
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 job_default_id(self) -> bool:
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(cls, file: Path, conf_path: Path) -> bool:
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
- return is_ignored(file, read_ignore(conf_path / ".confignore"))
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 included:
395
- :param excluded:
396
- :param path:
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(self, output: DictData, to: DictData) -> DictData:
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 not dynamic(
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 str(len(to["jobs"]) + 1)
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 fix config
7
- """A Logs module contain TraceLog dataclass and AuditLog model.
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, ValidationInfo
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, TupleStr
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 BaseTraceLog(ABC): # pragma: no cov
174
- """Base Trace Log dataclass object."""
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 FileTraceLog(BaseTraceLog): # pragma: no cov
322
- """Trace Log object that write file to the local storage."""
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 find_logs(
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("log_path", extras=extras)).glob("./run_id=*"),
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 find_log_with_id(
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("log_path", extras=extras)
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("log_path", extras=self.extras)
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 SQLiteTraceLog(BaseTraceLog): # pragma: no cov
457
- """Trace Log object that write trace log to the SQLite database file."""
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 find_logs(cls) -> Iterator[DictStr]: ...
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 find_log_with_id(cls, run_id: str) -> DictStr: ...
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
- TraceLog = Union[
484
- FileTraceLog,
485
- SQLiteTraceLog,
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
- ) -> TraceLog: # pragma: no cov
495
- """Get dynamic TraceLog object from the setting config.
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 config.
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("log_path", extras=extras).is_file():
504
- return SQLiteTraceLog(
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 FileTraceLog(
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, info: ValidationInfo) -> 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=info.data.get("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: TraceLog = get_trace(self.run_id, self.parent_run_id)
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: TraceLog = get_trace(self.run_id, self.parent_run_id)
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
- class RemoteFileAudit(FileAudit): # pragma: no cov
744
- """Remote File Audit Pydantic Model."""
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[Audit]: # pragma: no cov
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.
@@ -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 TraceLog, get_dt_tznow, get_trace
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[TraceLog] = field(default=None, compare=False, repr=False)
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: TraceLog = get_trace(
117
- self.run_id, self.parent_run_id, extras=self.extras
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: TraceLog = get_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