Source code for doot.reporters._interface

  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
[docs] 175 def header(self) -> Self: ...
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
[docs] 250@runtime_checkable 251class ReportFormatter_p(Protocol): 252 253 def __call__(self, key:str, *, info:Maybe[str]=None, msg:Maybe[str]=None, ctx:Maybe[list]=None) -> str: ... 254
[docs] 255 def get_segment(self, key:str) -> Maybe[str]: ...