Coverage for hookee/util.py: 93.85%

65 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-12-06 15:08 +0000

1import inspect 

2import json 

3import logging 

4import os 

5import sys 

6import xml.dom.minidom 

7 

8import click 

9 

10__author__ = "Alex Laird" 

11__copyright__ = "Copyright 2020, Alex Laird" 

12__version__ = "2.0.0" 

13 

14logger = logging.getLogger(__name__) 

15 

16 

17class PrintUtil: 

18 """ 

19 An object that provides helper methods for logging output. If :class:`~hookee.conf.Config`'s ``click_logging`` is 

20 ``True`` (which will happen by default if a :class:`click.Context` is found to be active), this logging will be 

21 done through ``click``, otherwise the ``hookee`` logger will be used. 

22 

23 If ``click_logging`` is disabled, output sent through this utility can still be interacted with by ensuring the a 

24 logger is setup. For example, this would add a handler to the ``hookee`` logger that just logs output back to 

25 the console: 

26 

27 .. code-block:: python 

28 

29 import logging 

30 

31 logger = logging.getLogger("hookee") 

32 logger.setLevel(logging.INFO) 

33 logging.getLogger().addHandler(logging.StreamHandler()) 

34 

35 :var config: The ``hookee`` configuration. 

36 :vartype config: Config 

37 """ 

38 

39 def __init__(self, config): 

40 self.config = config 

41 

42 @property 

43 def console_width(self): 

44 return self.config.get("console_width") 

45 

46 @property 

47 def header_color(self): 

48 return self.config.get("header_color") 

49 

50 @property 

51 def default_color(self): 

52 return self.config.get("default_color") 

53 

54 @property 

55 def request_color(self): 

56 return self.config.get("request_color") 

57 

58 def print_config_update(self, msg): 

59 self.print_basic("\n--> {}\n".format(msg), color=self.header_color) 

60 

61 def print_open_header(self, title, delimiter="-", color=None): 

62 """ 

63 Log an opening header with a title and a new line before and after. 

64 

65 :param title: The header title. 

66 :type title: str 

67 :param delimiter: The title of the XML blob. 

68 :type delimiter: str, optional 

69 :param color: The color to make the text. 

70 :type color: str, optional 

71 """ 

72 if color is None: 

73 color = self.header_color 

74 

75 width = int((self.console_width - len(title)) / 2) 

76 

77 self.print_basic() 

78 self.print_basic("{}{}{}".format(delimiter * width, title, delimiter * width), color=color, bold=True) 

79 self.print_basic() 

80 

81 def print_close_header(self, delimiter="-", color=None, blank_line=True): 

82 """ 

83 Log a closing header with an optional new line before. 

84 

85 :param delimiter: The title of the XML blob. 

86 :type delimiter: str 

87 :param color: The color to make the text. 

88 :type color: str, optional 

89 :param blank_line: ``True`` if a blank line should precede the closing header. 

90 :type blank_line: bool 

91 """ 

92 if color is None: 

93 color = self.header_color 

94 

95 if blank_line: 

96 self.print_basic() 

97 self.print_basic(delimiter * self.console_width, color=color, bold=True) 

98 

99 def print_dict(self, title, data, color=None): 

100 """ 

101 Log formatted dictionary data. 

102 

103 :param title: The title of the XML blob. 

104 :type title: str 

105 :param data: A dictionary. 

106 :type data: dict 

107 :param color: The color to make the text. 

108 :type color: str, optional 

109 """ 

110 if color is None: 

111 color = self.default_color 

112 

113 self.print_basic("{}: {}".format(title, json.dumps(data, indent=4)), color=color) 

114 

115 def print_xml(self, title, data, color=None): 

116 """ 

117 Log formatted XML. 

118 

119 :param title: The title of the XML blob. 

120 :type title: str 

121 :param data: An XML string. 

122 :type data: str 

123 :param color: The color to make the text. 

124 :type color: str, optional 

125 """ 

126 if color is None: 

127 color = self.default_color 

128 

129 self.print_basic("{}: {}".format(title, xml.dom.minidom.parseString(data).toprettyxml()), color=color) 

130 

131 def print_basic(self, msg="", color=None, bold=False, print_when_logging=False): 

132 """ 

133 Log a basic message. The message will be logged via ``click``, if ``click_logging`` is enabled in 

134 :class:`~hookee.conf.Config`, or appended to the logger. 

135 

136 :param msg: The update to print. 

137 :type msg: str, optional 

138 :param color: The color to make the text. 

139 :type color: str, optional 

140 :param bold: ``True`` if the output should be bold. 

141 :type bold: bool, optional 

142 :param print_when_logging: ``True`` if, when ``click_logging`` is ``False``, ``msg`` should print to the 

143 console instead of appending to the logger. 

144 :type print_when_logging: bool, optional 

145 """ 

146 if color is None: 

147 color = self.default_color 

148 

149 if self.config.click_logging: 

150 click.secho(msg, fg=color, bold=bold) 

151 elif not print_when_logging: 

152 logger.info(msg) 

153 else: 

154 print(msg) 

155 

156 

157def python36_gte(): 

158 """ 

159 Check if running on a Python 3.6 or higher interpreter. 

160 

161 :return: ``True`` if Python 3.6 or higher. 

162 :rtype: bool 

163 """ 

164 return sys.version_info >= (3, 6) 

165 

166 

167def get_functions(mod): 

168 """ 

169 Get a list of functions for the given module. 

170 

171 :param mod: The module to inspect for functions. 

172 :type mod: types.ModuleType 

173 :return: The list of functions. 

174 :rtype: list[types.FunctionType] 

175 """ 

176 return [o[0] for o in inspect.getmembers(mod, inspect.isfunction)] 

177 

178 

179def get_args(func): 

180 """ 

181 Get a list of args for the given function. 

182 

183 :param func: The function to inspect for args. 

184 :type func: types.FunctionType 

185 :return: The list of args. 

186 :rtype: list[str] 

187 """ 

188 return inspect.getfullargspec(func)[0] 

189 

190 

191def get_module_name(module): 

192 """ 

193 Get the name of the module from the basename of its path. 

194 

195 :param module: The module. 

196 :type module: types.ModuleType 

197 :return: The base name of the module. 

198 :rtype: str 

199 """ 

200 return os.path.splitext(os.path.basename(module.__file__))[0]