1#!/usr/bin/env python3
2"""
3
4"""
5# ruff: noqa:
6
7# Imports:
8from __future__ import annotations
9
10# ##-- stdlib imports
11import datetime
12import enum
13import functools as ftz
14import itertools as itz
15import logging as logmod
16import pathlib as pl
17import re
18import time
19import types
20import collections
21import contextlib
22import hashlib
23from copy import deepcopy
24from uuid import UUID, uuid1
25from weakref import ref
26import atexit # for @atexit.register
27import faulthandler
28# ##-- end stdlib imports
29
30# ##-- types
31# isort: off
32import abc
33import collections.abc
34from typing import TYPE_CHECKING, cast, assert_type, assert_never
35from typing import Generic, NewType, Never
36# Protocols:
37from typing import Protocol, runtime_checkable
38# Typing Decorators:
39from typing import no_type_check, final, override, overload
40
41if TYPE_CHECKING:
42 from jgdv import Maybe, DateTime
43 from typing import Final
44 from typing import ClassVar, Any, LiteralString
45 from typing import Self, Literal
46 from typing import TypeGuard
47 from collections.abc import Iterable, Iterator, Callable, Generator
48 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
49
50 from doot.workflow._interface import TaskName_p
51 type Logger = logmod.Logger
52##--|
53
54# isort: on
55# ##-- end types
56
57##-- logging
58logging = logmod.getLogger(__name__)
59##-- end logging
60
61# Vars:
62SEGMENT_SIZES : Final[tuple[int,int,int]] = (1, 3, 1)
63GAP : Final[str] = " "*SEGMENT_SIZES[1]
64##-- segment dicts
65TRACE_LINES_ASCII : Final[dict[str, str|tuple]] = {
66 "root" : "T",
67 "wait" : "|",
68 "branch" : ("|", "->=", "["),
69 "act" : ("|", "", "::"),
70 "inactive" : ":",
71 "begin" : ("|", "...", "Y"),
72 "return" : ("", "=", "<]"),
73 "pause" : ("", "-", "<]"),
74 "resume" : ("|", "->-", "["),
75 "result" : ("|", "<<<", "]"),
76 "fail" : ("|", "...", "X:"),
77 "finished" : "⟘",
78 "gap" : (" "*SEGMENT_SIZES[1]),
79 "just_char" : " ",
80}
81
82##-- end segment dicts
83
84# eg: {┣─}{╮}
85LINE_PASS_FMT : Final[str] = "{ctx}{act}"
86# eg: {┊ ┊ }{┃} [{blah}] : {bloo}
87LINE_MSG_FMT : Final[str] = "{ctx}{act}{gap}[{info}]{gap2}: {detail}"
88TIME_FMT : Final[str] = "%H:%M"
89
90ACT_SPACING : Final[int] = 4
91MSG_SPACING : Final[int] = 6
92# Body:
93
[docs]
94class TraceRecord_d:
95 """ For Storing what happened, where, and why """
96
97 __slots__ = ("what", "when", "where", "why")
98
99 def __init__(self, *, what:str, where:str, why:str, when:DateTime) -> None:
100 self.what = what
101 self.where = where
102 self.why = why
103 self.when = when
104
[docs]
105class ReportStackEntry_d:
106 """ Data for storing the context of the reporter """
107 __slots__ = ("data", "depth", "extra", "log_extra", "log_level", "prefix", "state")
108 log_extra : dict
109 log_level : int
110 depth : int
111 state : str
112 data : dict
113 prefix : list[str]
114 extra : dict
115
116 def __init__(self, **kwargs:Any) -> None:
117 # Required args:
118 self.log_extra = kwargs.pop("log_extra")
119 self.log_level = kwargs.pop("log_level")
120 self.state = kwargs.pop("state")
121 self.data = kwargs.pop("data")
122 # Optional Args:
123 self.prefix = kwargs.pop("prefix", [])
124 self.depth = kwargs.pop("depth", 1)
125 self.extra = dict(kwargs)
126
127 @override
128 def __repr__(self) -> str:
129 return f"<{self.__class__.__name__}({self.depth}): level:{self.log_level}>"
130
131# Sub Protocols
132
133##--|
134
[docs]
135@runtime_checkable
136class ReportGroup_p(Protocol):
137
[docs]
138 def _out(self, key:str, *, info:Maybe=None, msg:Maybe=None, level:int=0) -> None: ...
139
[docs]
140class WorkflowGroup_p(ReportGroup_p, Protocol):
141 """
142 A Re-entrant ctx manager,
143 used for reporting user-level information about a
144 task workflow run.
145
146 """
147
[docs]
148 def root(self) -> Self: ...
149
[docs]
150 def wait(self) -> Self: ...
151
[docs]
152 def act(self, info:str, msg:str) -> Self: ...
153
[docs]
154 def fail(self, *, info:Maybe[str]=None, msg:Maybe[str]=None) -> Self: ...
155
[docs]
156 def branch(self, name:str|TaskName_p, info:Maybe[str]=None) -> Self: ...
157
[docs]
158 def pause (self, reason:str) -> Self: ...
159
[docs]
160 def result(self, state:list[str], info:Maybe[str]=None) -> Self: ...
161
[docs]
162 def resume(self, name:str|TaskName_p) -> Self: ...
163
[docs]
164 def finished(self) -> Self: ...
165
[docs]
166 def queue(self, num:int) -> Self: ...
167
[docs]
168 def state_result(self, *vals:str) -> Self: ...
169
[docs]
170 def line(self, msg:Maybe[str]=None, char:Maybe[str]=None) -> Self: ...
171
[docs]
172class GeneralGroup_p(ReportGroup_p, Protocol):
173 """ Reporter Methods for general user facing messages """
174
176
[docs]
177 def user(self, msg:str, *rest:Any, **kwargs:Any) -> Self: ...
178
[docs]
179 def trace(self, msg:str, *rest:Any, **kwargs:Any) -> Self: ...
180
[docs]
181 def failure(self, msg:str, *rest:Any, **kwargs:Any) -> Self: ...
182
[docs]
183 def detail(self, msg:str, *rest:Any, **kwargs:Any) -> Self: ...
184
[docs]
185 def warn(self, msg:str, *rest:Any, **kwargs:Any) -> Self: ...
186
[docs]
187 def error(self, msg:str, *rest:Any, **kwargs:Any) -> Self: ...
188 ##--|
189
[docs]
190 def line(self, msg:Maybe[str]=None, char:Maybe[str]=None) -> Self: ...
191
[docs]
192 def gap(self) -> Self: ...
193
194# Main Protocols
195
[docs]
196class TreeGroup_p(ReportGroup_p, Protocol):
197 pass
198
[docs]
199class SummaryGroup_p(ReportGroup_p, Protocol):
200
[docs]
201 def start(self) -> None: ...
202
[docs]
203 def finish(self) -> None: ...
204
[docs]
205 def add(self, key:str, *vals:Any) -> Self: ...
206
[docs]
207 def summarise(self) -> Self: ...
208
209 pass
210##--|
211
[docs]
212@runtime_checkable
213class Reporter_p(Protocol):
214 """
215 Reporters provide attr access to any registered ReportGroup_p's,
216 for formatted printing of workflow information
217 """
218 _entry_count : int
219 _fmt : ReportFormatter_p
220 _logger : Logger
221 _stack : list[ReportStackEntry_d]
222
[docs]
223 @property
224 def state(self) -> ReportStackEntry_d: ...
225
[docs]
226 @property
227 def wf(self) -> WorkflowGroup_p: ...
228
[docs]
229 @property
230 def gen(self) -> GeneralGroup_p: ...
231
[docs]
232 @property
233 def tree(self) -> TreeGroup_p: ...
234
[docs]
235 @property
236 def summary(self) -> SummaryGroup_p: ...
237
238 ##--|
239
240 def __enter__(self) -> Self: ...
241
242 def __exit__(self, *exc:Any) -> bool: ...
243
[docs]
244 def push_state(self, state:str, **kwargs:Any) -> Self: ...
245
[docs]
246 def pop_state(self) -> Self: ...
247
[docs]
248 def active_level(self, level:int) -> None: ...
249