Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import logging 

2import tempfile 

3from collections.abc import MutableMapping 

4from logging.handlers import RotatingFileHandler 

5from os.path import dirname 

6from pathlib import Path 

7from pkgutil import iter_modules 

8from textwrap import TextWrapper, dedent, fill, indent 

9from typing import Dict, Optional, Tuple 

10 

11from colorama import Fore, init 

12 

13init() 

14 

15 

16class _MessageWhiteList(logging.Filter): 

17 _modules: Optional[Tuple[str]] = None 

18 

19 def filter(self, record): 

20 if not _MessageWhiteList._modules: 

21 pkgpath = dirname(dirname(__file__)) 

22 modules = tuple(name for _, name, _ in iter_modules([pkgpath])) 

23 _MessageWhiteList._modules = ( 

24 tuple( 

25 "__main__", 

26 ) 

27 + modules 

28 ) 

29 

30 return record.name.startswith(_MessageWhiteList._modules) 

31 

32 

33class _MessageConfig(MutableMapping): 

34 def __init__(self, *args, **kwargs): 

35 self._store: Dict = dict(*args, **kwargs) 

36 

37 def __getitem__(self, key: str): 

38 return self._store[self._keytransform(key)] 

39 

40 def __setitem__(self, key: str, value): 

41 self._store[self._keytransform(key)] = value 

42 # (python 3.8) 'force' option should be preferred. 

43 logging.root.handlers = [] 

44 logging.basicConfig(**self._store) 

45 

46 def __delitem__(self, key: str): 

47 del self._store[self._keytransform(key)] 

48 

49 def __iter__(self): 

50 return iter(self._store) 

51 

52 def __len__(self): 

53 return len(self._store) 

54 

55 def _keytransform(self, key: str): 

56 return key 

57 

58 

59class _Message: 

60 def __init__(self): 

61 temp = Path(tempfile.gettempdir()) / "defects4cpp.log" 

62 self._config = _MessageConfig( 

63 { 

64 "format": "%(levelname)s[%(name)s]: %(message)s", 

65 "level": logging.INFO, 

66 "handlers": [self._create_file_handler(temp)], 

67 # "force": True, # (python 3.8) Some third party libraries might have touched it. 

68 } 

69 ) 

70 logging.root.handlers = [] 

71 logging.basicConfig(**self._config) 

72 self._wrapper = TextWrapper() 

73 

74 # Disable information about where calls were made from. 

75 logging._srcfile = None 

76 # Disable threading information. 

77 logging.logThreads = 0 

78 # Disable process information. 

79 logging.logProcesses = 0 

80 

81 @property 

82 def path(self) -> str: 

83 return logging.getLoggerClass().root.handlers[0].baseFilename 

84 

85 @path.setter 

86 def path(self, path: Path): 

87 if path.is_dir(): 

88 path /= "defects4cpp.log" 

89 self._config["handlers"] = [self._create_file_handler(path)] 

90 

91 @staticmethod 

92 def _create_file_handler(path: Path) -> RotatingFileHandler: 

93 handler = RotatingFileHandler(path, maxBytes=100_000, backupCount=5) 

94 handler.addFilter(_MessageWhiteList()) 

95 return handler 

96 

97 @staticmethod 

98 def critical(module_name: str, msg: str): 

99 logging.getLogger(module_name).critical(msg) 

100 

101 @staticmethod 

102 def error(module_name: str, msg: str): 

103 logging.getLogger(module_name).error(msg) 

104 

105 @staticmethod 

106 def warning(module_name: str, msg: str): 

107 logging.getLogger(module_name).warning(msg) 

108 

109 @staticmethod 

110 def debug(module_name: str, msg: str): 

111 logging.getLogger(module_name).debug(msg) 

112 

113 @staticmethod 

114 def info(module_name: str, msg: str): 

115 logging.getLogger(module_name).info(msg) 

116 

117 @staticmethod 

118 def stdout_title(msg: str): 

119 print(f"{Fore.BLUE}{msg}{Fore.RESET}") 

120 

121 def stdout_bullet(self, msg: str): 

122 print( 

123 f"{Fore.GREEN}" 

124 f"{fill(dedent(msg), initial_indent='* ', subsequent_indent=' ', width=self._wrapper.width)}" 

125 f"{Fore.RESET}" 

126 ) 

127 

128 def stdout_paragraph(self, msg: str): 

129 print( 

130 f"{Fore.WHITE}" 

131 f"{indent(self._wrapper.fill(msg), prefix=' ', predicate=lambda line: True)}" 

132 f"{Fore.RESET}" 

133 ) 

134 

135 @staticmethod 

136 def stdout_progress(msg: str): 

137 print(f"{Fore.CYAN}{msg}{Fore.RESET}") 

138 

139 @staticmethod 

140 def stdout_progress_detail(msg: str): 

141 print(f" {Fore.GREEN}{msg}{Fore.RESET}") 

142 

143 @staticmethod 

144 def stdout_progress_error(msg: str): 

145 print(f"{Fore.RED}{msg}{Fore.RESET}") 

146 

147 @staticmethod 

148 def stdout_argparse_error(msg: str): 

149 print(f"{Fore.YELLOW}{msg}{Fore.RESET}") 

150 

151 @staticmethod 

152 def stdout_search_error(msg: str): 

153 print(f"{Fore.YELLOW}{msg}{Fore.RESET}") 

154 

155 @staticmethod 

156 def stdout_error(msg: str): 

157 print(f"{Fore.RED}{msg}{Fore.RESET}") 

158 

159 @staticmethod 

160 def stdout_stream(msg: str): 

161 print(f"{Fore.LIGHTBLUE_EX}{msg}{Fore.RESET}", end="") 

162 

163 

164message = _Message()