Coverage for hookee/util.py: 93.65%

63 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-06 15:28 +0000

1import inspect 

2import json 

3import logging 

4import os 

5import sys 

6 

7import click 

8 

9__author__ = "Alex Laird" 

10__copyright__ = "Copyright 2023, Alex Laird" 

11__version__ = "2.0.8" 

12 

13from defusedxml.minidom import parseString 

14 

15logger = logging.getLogger(__name__) 

16 

17 

18class PrintUtil: 

19 """ 

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

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

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

23 

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

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

26 the console: 

27 

28 .. code-block:: python 

29 

30 import logging 

31 

32 logger = logging.getLogger("hookee") 

33 logger.setLevel(logging.INFO) 

34 logging.getLogger().addHandler(logging.StreamHandler()) 

35 

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

37 :vartype config: Config 

38 """ 

39 

40 def __init__(self, config): 

41 self.config = config 

42 

43 @property 

44 def console_width(self): 

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

46 

47 @property 

48 def header_color(self): 

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

50 

51 @property 

52 def default_color(self): 

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

54 

55 @property 

56 def request_color(self): 

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

58 

59 def print_config_update(self, msg): 

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

61 

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

63 """ 

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

65 

66 :param title: The header title. 

67 :type title: str 

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

69 :type delimiter: str, optional 

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

71 :type color: str, optional 

72 """ 

73 if color is None: 

74 color = self.header_color 

75 

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

77 

78 self.print_basic() 

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

80 self.print_basic() 

81 

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

83 """ 

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

85 

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

87 :type delimiter: str 

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

89 :type color: str, optional 

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

91 :type blank_line: bool 

92 """ 

93 if color is None: 

94 color = self.header_color 

95 

96 if blank_line: 

97 self.print_basic() 

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

99 

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

101 """ 

102 Log formatted dictionary data. 

103 

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

105 :type title: str 

106 :param data: A dictionary. 

107 :type data: dict 

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

109 :type color: str, optional 

110 """ 

111 if color is None: 

112 color = self.default_color 

113 

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

115 

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

117 """ 

118 Log formatted XML. 

119 

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

121 :type title: str 

122 :param data: An XML string. 

123 :type data: str 

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

125 :type color: str, optional 

126 """ 

127 if color is None: 

128 color = self.default_color 

129 

130 self.print_basic("{}: {}".format(title, parseString(data).toprettyxml()), color=color) 

131 

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

133 """ 

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

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

136 

137 :param msg: The update to print. 

138 :type msg: str, optional 

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

140 :type color: str, optional 

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

142 :type bold: bool, optional 

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

144 console instead of appending to the logger. 

145 :type print_when_logging: bool, optional 

146 """ 

147 if color is None: 

148 color = self.default_color 

149 

150 if self.config.click_logging: 

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

152 elif not print_when_logging: 

153 logger.info(msg) 

154 else: 

155 print(msg) 

156 

157 

158def get_functions(mod): 

159 """ 

160 Get a list of functions for the given module. 

161 

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

163 :type mod: types.ModuleType 

164 :return: The list of functions. 

165 :rtype: list[types.FunctionType] 

166 """ 

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

168 

169 

170def get_args(func): 

171 """ 

172 Get a list of args for the given function. 

173 

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

175 :type func: types.FunctionType 

176 :return: The list of args. 

177 :rtype: list[str] 

178 """ 

179 return inspect.getfullargspec(func)[0] 

180 

181 

182def get_module_name(module): 

183 """ 

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

185 

186 :param module: The module. 

187 :type module: types.ModuleType 

188 :return: The base name of the module. 

189 :rtype: str 

190 """ 

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