ddeutil-workflow 0.0.58__py3-none-any.whl → 0.0.60__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/logs.py CHANGED
@@ -3,40 +3,44 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- # [x] Use dynamic config
7
6
  # [x] Use fix config for `get_logger`, and Model initialize step.
8
- """A Logs module contain Trace dataclass and Audit Pydantic model.
7
+ """A Logs module contain Trace and Audit Pydantic models for process log from
8
+ the core workflow engine. I separate part of log to 2 types:
9
+ - Trace: A stdout and stderr log
10
+ - Audit: An audit release log for tracking incremental running workflow.
9
11
  """
10
12
  from __future__ import annotations
11
13
 
12
14
  import json
13
15
  import logging
14
16
  import os
17
+ import re
15
18
  from abc import ABC, abstractmethod
16
19
  from collections.abc import Iterator
17
- from dataclasses import field
18
20
  from datetime import datetime
19
21
  from functools import lru_cache
20
22
  from inspect import Traceback, currentframe, getframeinfo
21
23
  from pathlib import Path
22
24
  from threading import get_ident
25
+ from types import FrameType
23
26
  from typing import ClassVar, Literal, Optional, TypeVar, Union
24
27
 
25
- from pydantic import BaseModel, Field
26
- from pydantic.dataclasses import dataclass
28
+ from pydantic import BaseModel, ConfigDict, Field
27
29
  from pydantic.functional_validators import model_validator
28
30
  from typing_extensions import Self
29
31
 
30
- from .__types import DictData, DictStr
32
+ from .__types import DictData
31
33
  from .conf import config, dynamic
32
34
  from .utils import cut_id, get_dt_now, prepare_newline
33
35
 
36
+ METADATA: str = "metadata.json"
37
+
34
38
 
35
39
  @lru_cache
36
40
  def get_logger(name: str):
37
41
  """Return logger object with an input module name.
38
42
 
39
- :param name: A module name that want to log.
43
+ :param name: (str) A module name that want to log.
40
44
  """
41
45
  lg = logging.getLogger(name)
42
46
 
@@ -71,13 +75,55 @@ def get_dt_tznow() -> datetime: # pragma: no cov
71
75
 
72
76
 
73
77
  PREFIX_LOGS: dict[str, dict] = {
74
- "CALLER": {"emoji": ""},
75
- "STAGE": {"emoji": ""},
76
- "JOB": {"emoji": ""},
77
- "WORKFLOW": {"emoji": "🏃"},
78
- "RELEASE": {"emoji": ""},
79
- "POKE": {"emoji": ""},
78
+ "CALLER": {
79
+ "emoji": "📍",
80
+ "desc": "logs from any usage from custom caller function.",
81
+ },
82
+ "STAGE": {"emoji": "⚙️", "desc": "logs from stages module."},
83
+ "JOB": {"emoji": "⛓️", "desc": "logs from job module."},
84
+ "WORKFLOW": {"emoji": "🏃", "desc": "logs from workflow module."},
85
+ "RELEASE": {"emoji": "📅", "desc": "logs from release workflow method."},
86
+ "POKING": {"emoji": "⏰", "desc": "logs from poke workflow method."},
80
87
  } # pragma: no cov
88
+ PREFIX_DEFAULT: str = "CALLER"
89
+ PREFIX_LOGS_REGEX: re.Pattern[str] = re.compile(
90
+ rf"(^\[(?P<name>{'|'.join(PREFIX_LOGS)})]:\s?)?(?P<message>.*)",
91
+ re.MULTILINE | re.DOTALL | re.ASCII | re.VERBOSE,
92
+ ) # pragma: no cov
93
+
94
+
95
+ class PrefixMsg(BaseModel):
96
+ """Prefix Message model for receive grouping dict from searching prefix data
97
+ from logging message.
98
+ """
99
+
100
+ name: Optional[str] = Field(default=None)
101
+ message: Optional[str] = Field(default=None)
102
+
103
+ def prepare(self, extras: Optional[DictData] = None) -> str:
104
+ """Prepare message with force add prefix before writing trace log.
105
+
106
+ :rtype: str
107
+ """
108
+ name: str = self.name or PREFIX_DEFAULT
109
+ emoji: str = (
110
+ f"{PREFIX_LOGS[name]['emoji']} "
111
+ if (extras or {}).get("log_add_emoji", True)
112
+ else ""
113
+ )
114
+ return f"{emoji}[{name}]: {self.message}"
115
+
116
+
117
+ def extract_msg_prefix(msg: str) -> PrefixMsg:
118
+ """Extract message prefix from an input message.
119
+
120
+ :param msg: A message that want to extract.
121
+
122
+ :rtype: PrefixMsg
123
+ """
124
+ return PrefixMsg.model_validate(
125
+ obj=PREFIX_LOGS_REGEX.search(msg).groupdict()
126
+ )
81
127
 
82
128
 
83
129
  class TraceMeta(BaseModel): # pragma: no cov
@@ -86,6 +132,7 @@ class TraceMeta(BaseModel): # pragma: no cov
86
132
  """
87
133
 
88
134
  mode: Literal["stdout", "stderr"] = Field(description="A meta mode.")
135
+ level: str = Field(description="A log level.")
89
136
  datetime: str = Field(description="A datetime in string format.")
90
137
  process: int = Field(description="A process ID.")
91
138
  thread: int = Field(description="A thread ID.")
@@ -93,29 +140,54 @@ class TraceMeta(BaseModel): # pragma: no cov
93
140
  filename: str = Field(description="A filename of this log.")
94
141
  lineno: int = Field(description="A line number of this log.")
95
142
 
143
+ @classmethod
144
+ def dynamic_frame(
145
+ cls, frame: FrameType, *, extras: Optional[DictData] = None
146
+ ) -> Traceback:
147
+ """Dynamic Frame information base on the `logs_trace_frame_layer` config
148
+ value that was set from the extra parameter.
149
+
150
+ :param frame: (FrameType) The current frame that want to dynamic.
151
+ :param extras: (DictData) An extra parameter that want to get the
152
+ `logs_trace_frame_layer` config value.
153
+ """
154
+ extras: DictData = extras or {}
155
+ layer: int = extras.get("logs_trace_frame_layer", 4)
156
+ for _ in range(layer):
157
+ _frame: Optional[FrameType] = frame.f_back
158
+ if _frame is None:
159
+ raise ValueError(
160
+ f"Layer value does not valid, the maximum frame is: {_ + 1}"
161
+ )
162
+ frame: FrameType = _frame
163
+ return getframeinfo(frame)
164
+
96
165
  @classmethod
97
166
  def make(
98
167
  cls,
99
168
  mode: Literal["stdout", "stderr"],
100
169
  message: str,
170
+ level: str,
101
171
  *,
102
172
  extras: Optional[DictData] = None,
103
173
  ) -> Self:
104
- """Make the current TraceMeta instance that catching local state.
174
+ """Make the current metric for contract this TraceMeta model instance
175
+ that will catch local states like PID, thread identity.
105
176
 
106
- :param mode: A metadata mode.
107
- :param message: A message.
177
+ :param mode: (Literal["stdout", "stderr"]) A metadata mode.
178
+ :param message: (str) A message.
179
+ :param level: (str) A log level.
108
180
  :param extras: (DictData) An extra parameter that want to override core
109
181
  config values.
110
182
 
111
183
  :rtype: Self
112
184
  """
113
- frame_info: Traceback = getframeinfo(
114
- currentframe().f_back.f_back.f_back
115
- )
185
+ frame: FrameType = currentframe()
186
+ frame_info: Traceback = cls.dynamic_frame(frame, extras=extras)
116
187
  extras: DictData = extras or {}
117
188
  return cls(
118
189
  mode=mode,
190
+ level=level,
119
191
  datetime=(
120
192
  get_dt_now(tz=dynamic("tz", extras=extras)).strftime(
121
193
  dynamic("log_datetime_format", extras=extras)
@@ -150,38 +222,45 @@ class TraceData(BaseModel): # pragma: no cov
150
222
 
151
223
  :rtype: Self
152
224
  """
153
- data: DictStr = {"stdout": "", "stderr": "", "meta": []}
225
+ data: DictData = {"stdout": "", "stderr": "", "meta": []}
154
226
 
155
227
  for mode in ("stdout", "stderr"):
156
228
  if (file / f"{mode}.txt").exists():
157
229
  data[mode] = (file / f"{mode}.txt").read_text(encoding="utf-8")
158
230
 
159
- if (file / "metadata.json").exists():
231
+ if (file / METADATA).exists():
160
232
  data["meta"] = [
161
233
  json.loads(line)
162
234
  for line in (
163
- (file / "metadata.json")
164
- .read_text(encoding="utf-8")
165
- .splitlines()
235
+ (file / METADATA).read_text(encoding="utf-8").splitlines()
166
236
  )
167
237
  ]
168
238
 
169
239
  return cls.model_validate(data)
170
240
 
171
241
 
172
- @dataclass(frozen=True)
173
- class BaseTrace(ABC): # pragma: no cov
174
- """Base Trace dataclass with abstraction class property."""
242
+ class BaseTrace(BaseModel, ABC): # pragma: no cov
243
+ """Base Trace model with abstraction class property."""
244
+
245
+ model_config = ConfigDict(frozen=True)
175
246
 
176
- run_id: str
177
- parent_run_id: Optional[str] = field(default=None)
178
- extras: DictData = field(default_factory=dict, compare=False, repr=False)
247
+ run_id: str = Field(default="A running ID")
248
+ parent_run_id: Optional[str] = Field(
249
+ default=None, description="A parent running ID"
250
+ )
251
+ extras: DictData = Field(
252
+ default_factory=dict,
253
+ description=(
254
+ "An extra parameter that want to override on the core config "
255
+ "values."
256
+ ),
257
+ )
179
258
 
180
259
  @classmethod
181
260
  @abstractmethod
182
261
  def find_traces(
183
262
  cls,
184
- path: Path | None = None,
263
+ path: Optional[Path] = None,
185
264
  extras: Optional[DictData] = None,
186
265
  ) -> Iterator[TraceData]: # pragma: no cov
187
266
  raise NotImplementedError(
@@ -195,7 +274,7 @@ class BaseTrace(ABC): # pragma: no cov
195
274
  run_id: str,
196
275
  force_raise: bool = True,
197
276
  *,
198
- path: Path | None = None,
277
+ path: Optional[Path] = None,
199
278
  extras: Optional[DictData] = None,
200
279
  ) -> TraceData:
201
280
  raise NotImplementedError(
@@ -204,24 +283,30 @@ class BaseTrace(ABC): # pragma: no cov
204
283
  )
205
284
 
206
285
  @abstractmethod
207
- def writer(self, message: str, is_err: bool = False) -> None:
286
+ def writer(self, message: str, level: str, is_err: bool = False) -> None:
208
287
  """Write a trace message after making to target pointer object. The
209
288
  target can be anything be inherited this class and overwrite this method
210
289
  such as file, console, or database.
211
290
 
212
- :param message: A message after making.
213
- :param is_err: A flag for writing with an error trace or not.
291
+ :param message: (str) A message after making.
292
+ :param level: (str) A log level.
293
+ :param is_err: (bool) A flag for writing with an error trace or not.
294
+ (Default be False)
214
295
  """
215
296
  raise NotImplementedError(
216
297
  "Create writer logic for this trace object before using."
217
298
  )
218
299
 
219
300
  @abstractmethod
220
- async def awriter(self, message: str, is_err: bool = False) -> None:
301
+ async def awriter(
302
+ self, message: str, level: str, is_err: bool = False
303
+ ) -> None:
221
304
  """Async Write a trace message after making to target pointer object.
222
305
 
223
- :param message:
224
- :param is_err:
306
+ :param message: (str) A message after making.
307
+ :param level: (str) A log level.
308
+ :param is_err: (bool) A flag for writing with an error trace or not.
309
+ (Default be False)
225
310
  """
226
311
  raise NotImplementedError(
227
312
  "Create async writer logic for this trace object before using."
@@ -247,12 +332,14 @@ class BaseTrace(ABC): # pragma: no cov
247
332
 
248
333
  :param message: (str) A message that want to log.
249
334
  """
250
- msg: str = prepare_newline(self.make_message(message))
335
+ msg: str = prepare_newline(
336
+ self.make_message(extract_msg_prefix(message).prepare(self.extras))
337
+ )
251
338
 
252
339
  if mode != "debug" or (
253
340
  mode == "debug" and dynamic("debug", extras=self.extras)
254
341
  ):
255
- self.writer(msg, is_err=is_err)
342
+ self.writer(msg, level=mode, is_err=is_err)
256
343
 
257
344
  getattr(logger, mode)(msg, stacklevel=3)
258
345
 
@@ -304,12 +391,14 @@ class BaseTrace(ABC): # pragma: no cov
304
391
 
305
392
  :param message: (str) A message that want to log.
306
393
  """
307
- msg: str = prepare_newline(self.make_message(message))
394
+ msg: str = prepare_newline(
395
+ self.make_message(extract_msg_prefix(message).prepare(self.extras))
396
+ )
308
397
 
309
398
  if mode != "debug" or (
310
399
  mode == "debug" and dynamic("debug", extras=self.extras)
311
400
  ):
312
- await self.awriter(msg, is_err=is_err)
401
+ await self.awriter(msg, level=mode, is_err=is_err)
313
402
 
314
403
  getattr(logger, mode)(msg, stacklevel=3)
315
404
 
@@ -360,7 +449,7 @@ class FileTrace(BaseTrace): # pragma: no cov
360
449
  @classmethod
361
450
  def find_traces(
362
451
  cls,
363
- path: Path | None = None,
452
+ path: Optional[Path] = None,
364
453
  extras: Optional[DictData] = None,
365
454
  ) -> Iterator[TraceData]: # pragma: no cov
366
455
  """Find trace logs.
@@ -380,7 +469,7 @@ class FileTrace(BaseTrace): # pragma: no cov
380
469
  run_id: str,
381
470
  *,
382
471
  force_raise: bool = True,
383
- path: Path | None = None,
472
+ path: Optional[Path] = None,
384
473
  extras: Optional[DictData] = None,
385
474
  ) -> TraceData:
386
475
  """Find trace log with an input specific run ID.
@@ -399,7 +488,7 @@ class FileTrace(BaseTrace): # pragma: no cov
399
488
  f"Trace log on path {base_path}, does not found trace "
400
489
  f"'run_id={run_id}'."
401
490
  )
402
- return {}
491
+ return TraceData(stdout="", stderr="")
403
492
 
404
493
  @property
405
494
  def pointer(self) -> Path:
@@ -433,7 +522,7 @@ class FileTrace(BaseTrace): # pragma: no cov
433
522
  """
434
523
  return f"({self.cut_id}) {message}"
435
524
 
436
- def writer(self, message: str, is_err: bool = False) -> None:
525
+ def writer(self, message: str, level: str, is_err: bool = False) -> None:
437
526
  """Write a trace message after making to target file and write metadata
438
527
  in the same path of standard files.
439
528
 
@@ -443,28 +532,29 @@ class FileTrace(BaseTrace): # pragma: no cov
443
532
  ... ./logs/run_id=<run-id>/stdout.txt
444
533
  ... ./logs/run_id=<run-id>/stderr.txt
445
534
 
446
- :param message: A message after making.
535
+ :param message: (str) A message after making.
536
+ :param level: (str) A log level.
447
537
  :param is_err: A flag for writing with an error trace or not.
448
538
  """
449
539
  if not dynamic("enable_write_log", extras=self.extras):
450
540
  return
451
541
 
452
- write_file: str = "stderr" if is_err else "stdout"
453
- trace_meta: TraceMeta = TraceMeta.make(mode=write_file, message=message)
542
+ mode: Literal["stdout", "stderr"] = "stderr" if is_err else "stdout"
543
+ trace_meta: TraceMeta = TraceMeta.make(
544
+ mode=mode, level=level, message=message, extras=self.extras
545
+ )
454
546
 
455
- with (self.pointer / f"{write_file}.txt").open(
547
+ with (self.pointer / f"{mode}.txt").open(
456
548
  mode="at", encoding="utf-8"
457
549
  ) as f:
458
550
  fmt: str = dynamic("log_format_file", extras=self.extras)
459
551
  f.write(f"{fmt}\n".format(**trace_meta.model_dump()))
460
552
 
461
- with (self.pointer / "metadata.json").open(
462
- mode="at", encoding="utf-8"
463
- ) as f:
553
+ with (self.pointer / METADATA).open(mode="at", encoding="utf-8") as f:
464
554
  f.write(trace_meta.model_dump_json() + "\n")
465
555
 
466
556
  async def awriter(
467
- self, message: str, is_err: bool = False
557
+ self, message: str, level: str, is_err: bool = False
468
558
  ) -> None: # pragma: no cov
469
559
  """Write with async mode."""
470
560
  if not dynamic("enable_write_log", extras=self.extras):
@@ -475,17 +565,19 @@ class FileTrace(BaseTrace): # pragma: no cov
475
565
  except ImportError as e:
476
566
  raise ImportError("Async mode need aiofiles package") from e
477
567
 
478
- write_file: str = "stderr" if is_err else "stdout"
479
- trace_meta: TraceMeta = TraceMeta.make(mode=write_file, message=message)
568
+ mode: Literal["stdout", "stderr"] = "stderr" if is_err else "stdout"
569
+ trace_meta: TraceMeta = TraceMeta.make(
570
+ mode=mode, level=level, message=message, extras=self.extras
571
+ )
480
572
 
481
573
  async with aiofiles.open(
482
- self.pointer / f"{write_file}.txt", mode="at", encoding="utf-8"
574
+ self.pointer / f"{mode}.txt", mode="at", encoding="utf-8"
483
575
  ) as f:
484
576
  fmt: str = dynamic("log_format_file", extras=self.extras)
485
577
  await f.write(f"{fmt}\n".format(**trace_meta.model_dump()))
486
578
 
487
579
  async with aiofiles.open(
488
- self.pointer / "metadata.json", mode="at", encoding="utf-8"
580
+ self.pointer / METADATA, mode="at", encoding="utf-8"
489
581
  ) as f:
490
582
  await f.write(trace_meta.model_dump_json() + "\n")
491
583
 
@@ -507,7 +599,7 @@ class SQLiteTrace(BaseTrace): # pragma: no cov
507
599
  @classmethod
508
600
  def find_traces(
509
601
  cls,
510
- path: Path | None = None,
602
+ path: Optional[Path] = None,
511
603
  extras: Optional[DictData] = None,
512
604
  ) -> Iterator[TraceData]: ...
513
605
 
@@ -517,15 +609,19 @@ class SQLiteTrace(BaseTrace): # pragma: no cov
517
609
  run_id: str,
518
610
  force_raise: bool = True,
519
611
  *,
520
- path: Path | None = None,
612
+ path: Optional[Path] = None,
521
613
  extras: Optional[DictData] = None,
522
614
  ) -> TraceData: ...
523
615
 
524
616
  def make_message(self, message: str) -> str: ...
525
617
 
526
- def writer(self, message: str, is_err: bool = False) -> None: ...
618
+ def writer(
619
+ self, message: str, level: str, is_err: bool = False
620
+ ) -> None: ...
527
621
 
528
- def awriter(self, message: str, is_err: bool = False) -> None: ...
622
+ def awriter(
623
+ self, message: str, level: str, is_err: bool = False
624
+ ) -> None: ...
529
625
 
530
626
 
531
627
  Trace = TypeVar("Trace", bound=BaseTrace)
@@ -538,7 +634,7 @@ TraceModel = Union[
538
634
  def get_trace(
539
635
  run_id: str,
540
636
  *,
541
- parent_run_id: str | None = None,
637
+ parent_run_id: Optional[str] = None,
542
638
  extras: Optional[DictData] = None,
543
639
  ) -> TraceModel: # pragma: no cov
544
640
  """Get dynamic Trace instance from the core config (it can override by an
@@ -553,9 +649,11 @@ def get_trace(
553
649
  """
554
650
  if dynamic("trace_path", extras=extras).is_file():
555
651
  return SQLiteTrace(
556
- run_id, parent_run_id=parent_run_id, extras=(extras or {})
652
+ run_id=run_id, parent_run_id=parent_run_id, extras=(extras or {})
557
653
  )
558
- return FileTrace(run_id, parent_run_id=parent_run_id, extras=(extras or {}))
654
+ return FileTrace(
655
+ run_id=run_id, parent_run_id=parent_run_id, extras=(extras or {})
656
+ )
559
657
 
560
658
 
561
659
  class BaseAudit(BaseModel, ABC):
@@ -619,7 +717,7 @@ class BaseAudit(BaseModel, ABC):
619
717
  def find_audit_with_release(
620
718
  cls,
621
719
  name: str,
622
- release: datetime | None = None,
720
+ release: Optional[datetime] = None,
623
721
  *,
624
722
  extras: Optional[DictData] = None,
625
723
  ) -> Self:
@@ -631,7 +729,7 @@ class BaseAudit(BaseModel, ABC):
631
729
  """To something before end up of initial log model."""
632
730
 
633
731
  @abstractmethod
634
- def save(self, excluded: list[str] | None) -> None: # pragma: no cov
732
+ def save(self, excluded: Optional[list[str]]) -> None: # pragma: no cov
635
733
  """Save this model logging to target logging store."""
636
734
  raise NotImplementedError("Audit should implement ``save`` method.")
637
735
 
@@ -676,7 +774,7 @@ class FileAudit(BaseAudit):
676
774
  def find_audit_with_release(
677
775
  cls,
678
776
  name: str,
679
- release: datetime | None = None,
777
+ release: Optional[datetime] = None,
680
778
  *,
681
779
  extras: Optional[DictData] = None,
682
780
  ) -> Self:
@@ -749,7 +847,7 @@ class FileAudit(BaseAudit):
749
847
  "audit_path", extras=self.extras
750
848
  ) / self.filename_fmt.format(name=self.name, release=self.release)
751
849
 
752
- def save(self, excluded: list[str] | None) -> Self:
850
+ def save(self, excluded: Optional[list[str]]) -> Self:
753
851
  """Save logging data that receive a context data from a workflow
754
852
  execution result.
755
853
 
@@ -758,7 +856,7 @@ class FileAudit(BaseAudit):
758
856
 
759
857
  :rtype: Self
760
858
  """
761
- trace: Trace = get_trace(
859
+ trace: TraceModel = get_trace(
762
860
  self.run_id,
763
861
  parent_run_id=self.parent_run_id,
764
862
  extras=self.extras,
@@ -818,16 +916,16 @@ class SQLiteAudit(BaseAudit): # pragma: no cov
818
916
  def find_audit_with_release(
819
917
  cls,
820
918
  name: str,
821
- release: datetime | None = None,
919
+ release: Optional[datetime] = None,
822
920
  *,
823
921
  extras: Optional[DictData] = None,
824
922
  ) -> Self: ...
825
923
 
826
- def save(self, excluded: list[str] | None) -> SQLiteAudit:
924
+ def save(self, excluded: Optional[list[str]]) -> SQLiteAudit:
827
925
  """Save logging data that receive a context data from a workflow
828
926
  execution result.
829
927
  """
830
- trace: Trace = get_trace(
928
+ trace: TraceModel = get_trace(
831
929
  self.run_id,
832
930
  parent_run_id=self.parent_run_id,
833
931
  extras=self.extras,
@@ -82,7 +82,9 @@ class DateParam(DefaultParam): # pragma: no cov
82
82
  description="A default date that make from the current date func.",
83
83
  )
84
84
 
85
- def receive(self, value: Optional[str | datetime | date] = None) -> date:
85
+ def receive(
86
+ self, value: Optional[Union[str, datetime, date]] = None
87
+ ) -> date:
86
88
  """Receive value that match with date. If an input value pass with
87
89
  None, it will use default value instead.
88
90
 
@@ -121,7 +123,9 @@ class DatetimeParam(DefaultParam):
121
123
  ),
122
124
  )
123
125
 
124
- def receive(self, value: str | datetime | date | None = None) -> datetime:
126
+ def receive(
127
+ self, value: Optional[Union[str, datetime, date]] = None
128
+ ) -> datetime:
125
129
  """Receive value that match with datetime. If an input value pass with
126
130
  None, it will use default value instead.
127
131
 
@@ -155,11 +159,11 @@ class StrParam(DefaultParam):
155
159
 
156
160
  type: Literal["str"] = "str"
157
161
 
158
- def receive(self, value: str | None = None) -> str | None:
162
+ def receive(self, value: Optional[str] = None) -> Optional[str]:
159
163
  """Receive value that match with str.
160
164
 
161
165
  :param value: A value that want to validate with string parameter type.
162
- :rtype: str | None
166
+ :rtype: Optional[str]
163
167
  """
164
168
  if value is None:
165
169
  return self.default
@@ -171,7 +175,7 @@ class IntParam(DefaultParam):
171
175
 
172
176
  type: Literal["int"] = "int"
173
177
 
174
- def receive(self, value: int | None = None) -> int | None:
178
+ def receive(self, value: Optional[int] = None) -> Optional[int]:
175
179
  """Receive value that match with int.
176
180
 
177
181
  :param value: A value that want to validate with integer parameter type.
@@ -3,16 +3,16 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- # [x] Use dynamic config
7
- """Result module. It is the data context transfer objects that use by all object
8
- in this package. This module provide Status enum object and Result dataclass.
6
+ """A Result module. It is the data context transfer objects that use by all
7
+ object in this package. This module provide Status enum object and Result
8
+ dataclass.
9
9
  """
10
10
  from __future__ import annotations
11
11
 
12
12
  from dataclasses import field
13
13
  from datetime import datetime
14
14
  from enum import IntEnum
15
- from typing import Optional
15
+ from typing import Optional, Union
16
16
 
17
17
  from pydantic import ConfigDict
18
18
  from pydantic.dataclasses import dataclass
@@ -22,7 +22,7 @@ from typing_extensions import Self
22
22
  from .__types import DictData
23
23
  from .conf import dynamic
24
24
  from .exceptions import ResultException
25
- from .logs import Trace, get_dt_tznow, get_trace
25
+ from .logs import TraceModel, get_dt_tznow, get_trace
26
26
  from .utils import default_gen_id, gen_id, get_dt_now
27
27
 
28
28
 
@@ -31,14 +31,14 @@ class Status(IntEnum):
31
31
  Result dataclass object.
32
32
  """
33
33
 
34
- SUCCESS: int = 0
35
- FAILED: int = 1
36
- WAIT: int = 2
37
- SKIP: int = 3
38
- CANCEL: int = 4
34
+ SUCCESS = 0
35
+ FAILED = 1
36
+ WAIT = 2
37
+ SKIP = 3
38
+ CANCEL = 4
39
39
 
40
40
  @property
41
- def emoji(self) -> str:
41
+ def emoji(self) -> str: # pragma: no cov
42
42
  """Return the emoji value of this status.
43
43
 
44
44
  :rtype: str
@@ -75,16 +75,16 @@ class Result:
75
75
  parent_run_id: Optional[str] = field(default=None, compare=False)
76
76
  ts: datetime = field(default_factory=get_dt_tznow, compare=False)
77
77
 
78
- trace: Optional[Trace] = field(default=None, compare=False, repr=False)
78
+ trace: Optional[TraceModel] = field(default=None, compare=False, repr=False)
79
79
  extras: DictData = field(default_factory=dict, compare=False, repr=False)
80
80
 
81
81
  @classmethod
82
82
  def construct_with_rs_or_id(
83
83
  cls,
84
- result: Result | None = None,
85
- run_id: str | None = None,
86
- parent_run_id: str | None = None,
87
- id_logic: str | None = None,
84
+ result: Optional[Result] = None,
85
+ run_id: Optional[str] = None,
86
+ parent_run_id: Optional[str] = None,
87
+ id_logic: Optional[str] = None,
88
88
  *,
89
89
  extras: DictData | None = None,
90
90
  ) -> Self:
@@ -121,7 +121,7 @@ class Result:
121
121
  :rtype: Self
122
122
  """
123
123
  if self.trace is None: # pragma: no cov
124
- self.trace: Trace = get_trace(
124
+ self.trace: TraceModel = get_trace(
125
125
  self.run_id,
126
126
  parent_run_id=self.parent_run_id,
127
127
  extras=self.extras,
@@ -136,14 +136,14 @@ class Result:
136
136
  :rtype: Self
137
137
  """
138
138
  self.parent_run_id: str = running_id
139
- self.trace: Trace = get_trace(
139
+ self.trace: TraceModel = get_trace(
140
140
  self.run_id, parent_run_id=running_id, extras=self.extras
141
141
  )
142
142
  return self
143
143
 
144
144
  def catch(
145
145
  self,
146
- status: int | Status,
146
+ status: Union[int, Status],
147
147
  context: DictData | None = None,
148
148
  **kwargs,
149
149
  ) -> Self: