Coverage for csvforwkt/custom_logging.py: 92%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

51 statements  

1# -*- coding: utf-8 -*- 

2# csvForWKT - csvForWKT is a python script that creates a WKT-crs for some bodies from the solar system. The content that is filled in the WKT-crs comes from the report of IAU Working Group on Cartographic. 

3# Copyright (C) 2022 - CNES (Jean-Christophe Malapert for Pôle Surfaces Planétaires) 

4# 

5# This file is part of csvForWKT. 

6# 

7# csvForWKT is free software: you can redistribute it and/or modify 

8# it under the terms of the GNU Lesser General Public License v3 as published by 

9# the Free Software Foundation, either version 3 of the License, or 

10# (at your option) any later version. 

11# 

12# csvForWKT is distributed in the hope that it will be useful, 

13# but WITHOUT ANY WARRANTY; without even the implied warranty of 

14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

15# GNU Lesser General Public License v3 for more details. 

16# 

17# You should have received a copy of the GNU Lesser General Public License v3 

18# along with csvForWKT. If not, see <https://www.gnu.org/licenses/>. 

19"""Module for customizing ths logs.""" 

20import logging 

21from typing import Optional 

22 

23 

24class UtilsLogs: # pylint: disable=R0903 

25 """Utility class for logs.""" 

26 

27 @staticmethod 

28 def add_logging_level( 

29 level_name: str, level_num: int, method_name: Optional[str] = None 

30 ) -> None: 

31 """Add a new logging level to the `logging` module. 

32 

33 Parameters 

34 ---------- 

35 level_name: str 

36 level name of the logging 

37 level_num: int 

38 level number related to the level name 

39 method_name: Optional[str] 

40 method for both `logging` itself and the class returned by 

41 `logging.Logger` 

42 

43 Returns 

44 ------- 

45 None 

46 

47 Raises 

48 ------ 

49 AttributeError 

50 If this levelName or methodName is already defined in the 

51 logger. 

52 

53 """ 

54 if not method_name: 

55 method_name = level_name.lower() 

56 

57 def log_for_level(self, message, *args, **kwargs): 

58 if self.isEnabledFor(level_num): 

59 self._log( # pylint: disable=W0212 

60 level_num, message, args, **kwargs 

61 ) 

62 

63 def log_to_root(message, *args, **kwargs): 

64 logging.log(level_num, message, *args, **kwargs) 

65 

66 logging.addLevelName(level_num, level_name) 

67 setattr(logging, level_name, level_num) 

68 setattr(logging.getLoggerClass(), method_name, log_for_level) 

69 setattr(logging, method_name, log_to_root) 

70 

71 

72class LogRecord(logging.LogRecord): # pylint: disable=R0903 

73 """Specific class to handle output in logs.""" 

74 

75 def getMessage(self) -> str: 

76 """Returns the message. 

77 

78 Format the message according to the type of the message. 

79 

80 Returns: 

81 str: Returns the message 

82 """ 

83 msg = self.msg 

84 if self.args: 

85 if isinstance(self.args, dict): 

86 msg = msg.format(**self.args) 

87 else: 

88 msg = msg.format(*self.args) 

89 return msg 

90 

91 

92class CustomColorFormatter(logging.Formatter): 

93 """Color formatter.""" 

94 

95 UtilsLogs.add_logging_level("TRACE", 15) 

96 # Reset 

97 color_Off = "\033[0m" # Text Reset 

98 

99 log_colors = { 

100 logging.TRACE: "\033[0;36m", # type: ignore # pylint: disable=no-member # cyan 

101 logging.DEBUG: "\033[1;34m", # blue 

102 logging.INFO: "\033[0;32m", # green 

103 logging.WARNING: "\033[1;33m", # yellow 

104 logging.ERROR: "\033[1;31m", # red 

105 logging.CRITICAL: "\033[1;41m", # red reverted 

106 } 

107 

108 def format(self, record) -> str: 

109 """Format the log. 

110 

111 Args: 

112 record: the log record 

113 

114 Returns: 

115 str: the formatted log record 

116 """ 

117 record.levelname = "{}{}{}".format( 

118 CustomColorFormatter.log_colors[record.levelno], 

119 record.levelname, 

120 CustomColorFormatter.color_Off, 

121 ) 

122 record.msg = "{}{}{}".format( 

123 CustomColorFormatter.log_colors[record.levelno], 

124 record.msg, 

125 CustomColorFormatter.color_Off, 

126 ) 

127 

128 # Select the formatter according to the log if several handlers are 

129 # attached to the logger 

130 my_formatter = logging.Formatter 

131 my_handler = None 

132 handlers = logging.getLogger(__name__).handlers 

133 for handler in handlers: 

134 handler_level = handler.level 

135 if ( 

136 handler_level 

137 == logging.getLogger(__name__).getEffectiveLevel() 

138 ): 

139 if handler.formatter: 

140 my_formatter._fmt = ( # pylint: disable=W0212 

141 handler.formatter._fmt # pylint: disable=W0212 

142 ) 

143 my_handler = handler 

144 break 

145 if my_handler is not None: 

146 for handler in handlers: 

147 if handler != my_handler: 

148 logging.getLogger(__name__).removeHandler(handler) 

149 return my_formatter.format(self, record) # type: ignore 

150 

151 

152class ShellColorFormatter(CustomColorFormatter): 

153 """Shell Color formatter.""" 

154 

155 def format(self, record) -> str: 

156 """Format the log. 

157 

158 Args: 

159 record: the log record 

160 

161 Returns: 

162 str: the formatted log record 

163 """ 

164 record.msg = "{}{}{}".format( 

165 CustomColorFormatter.log_colors[logging.INFO], 

166 record.msg, 

167 CustomColorFormatter.color_Off, 

168 ) 

169 return record.msg