馃悕馃悕馃悕
at main 4.4 kB view raw
1 2import sys 3import inspect 4import traceback 5import time 6 7from dataclasses import dataclass 8from typing import Optional 9 10reset_color = "\033[0m" 11 12def _log(tag, content, mode, indent): 13 final_color = reset_color 14 if mode == "error": 15 tag_color = "\033[31m" 16 elif mode == "success": 17 tag_color = "\033[92m" 18 elif mode == "warning": 19 tag_color = "\033[33m" 20 else: 21 tag_color = "\033[96m" 22 print(f"{tag_color}{' '*indent}[{tag}]{reset_color} {content}{final_color}") 23 24def _input(prompt, mode, indent): 25 tag_color = "\033[35m" 26 return input(f"{tag_color}{' '*indent}{prompt} {reset_color}") 27 28 29@dataclass 30class Logger: 31 _mode: str = "standard" 32 _indent: int = 0 33 _tag: Optional[str] = None 34 35 def indented(self, n=4): 36 return Logger(_indent=self._indent + n, _tag=self._tag, _mode=self._mode) 37 38 def tag(self, tag: Optional[str]): 39 return Logger(_indent=self._indent, _tag=tag, _mode=self._mode) 40 41 def mode(self, mode: str): 42 return Logger(_indent=self._indent, _tag=self._tag, _mode=mode) 43 44 def __call__(self, content, mode=None, indent=None, tag=None): 45 if mode is None: 46 mode = self._mode 47 if indent is None: 48 indent = self._indent 49 if tag is None: 50 tag = self._tag 51 if tag is None: 52 callsite = inspect.stack()[1] 53 filename = callsite[1].split("/")[-1] 54 tag = f"{filename} {callsite[2]}" 55 _log(tag, content, mode, indent) 56 return self 57 58 def trace(self, source=None): 59 exception_type, exception, trace = sys.exc_info() 60 trace_frames = traceback.extract_tb(trace) 61 tag = "error" if self._tag is None else self._tag 62 exception_content = f"{exception_type.__name__}: {exception}" 63 _log(tag, exception_content, mode="error", indent=self._indent) 64 for frame in trace_frames[::-1]: 65 file, line_number, function, line = frame 66 if file == "<string>" and source is not None: 67 file = inspect.getfile(source) 68 lines, first_line = inspect.getsourcelines(source) 69 if line_number < len(lines): 70 line = lines[line_number-1].strip() 71 line_number = first_line + line_number - 1 72 else: 73 # TODO fix this!! 74 _log(f"SNAKEPYT", "TRACING ERROR", mode="error", indent=self._indent+8) 75 file_end = file.split("/")[-1] 76 _log(f"in {file_end} {line_number}", line, mode="error", indent=self._indent+4) 77 return self 78 79 def log(self, content, mode=None, indent=None, tag=None): 80 return self(content, mode, indent, tag) 81 82 def blank(self): 83 print() 84 return self 85 86 def input(self, username=None): 87 if username is None: 88 username = ":" 89 return _input(f"{username}:", mode="user", indent=self._indent) 90 91 92def inner_log(source, indent): 93 def log(content, mode="standard"): 94 callsite = inspect.stack()[1] 95 file = callsite[1] 96 line_number = callsite[2] 97 if file == "<string>" and source is not None: 98 file = inspect.getfile(source) 99 lines, first_line = inspect.getsourcelines(source) 100 line_number += first_line - 1 101 filename = file.split("/")[-1] 102 _log(f"{filename} {line_number}", content, mode, indent) 103 return log 104 105 106def trace(indent=0, source=None): 107 exception_type, exception, trace = sys.exc_info() 108 trace_frames = traceback.extract_tb(trace) 109 _log("error", exception_type.__name__, mode="error", indent=indent) 110 for frame in trace_frames[::-1]: 111 file, line_number, function, line = frame 112 if file == "<string>" and source is not None: 113 file = inspect.getfile(source) 114 lines, first_line = inspect.getsourcelines(source) 115 line = lines[line_number-1].strip() 116 line_number = first_line + line_number - 1 117 file_end = file.split("/")[-1] 118 _log(f"in {file_end} {line_number}", line, mode="error", indent=indent+4) 119 120class Timer(object): 121 def __init__(self, name): 122 self.name = name 123 124 def __enter__(self): 125 self.t = time.perf_counter() 126 127 def __exit__(self, *args): 128 print(f"{self.name}: {time.perf_counter() - self.t}") 129