Coverage for src/tkinterquickhelper/funcwin/function_helper.py: 71%

105 statements  

« prev     ^ index     » next       coverage.py v7.1.0, created at 2024-04-25 05:39 +0200

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

2""" 

3@file 

4@brief Various function needed when using the windows used to ask for parameters 

5""" 

6import sys 

7import re 

8import inspect 

9import datetime 

10from pyquickhelper.loghelper.flog import guess_machine_parameter 

11 

12 

13def get_function_list(module): 

14 """ 

15 Extracts all functions in a module. 

16 

17 @param module a object module 

18 @return the list of function included in a module, dictionary { name, object } 

19 """ 

20 res = {} 

21 d = module.__dict__ 

22 for k, v in d.items(): 

23 if isinstance(v, get_function_list.__class__): 

24 res[k] = v 

25 return res 

26 

27 

28def has_unknown_parameters(func): 

29 """ 

30 Returns True if the function contains a parameter like ``**params``. 

31 

32 @param func function 

33 @return True if the function contains something like ``**params`` 

34 """ 

35 # de = func.__defaults__ 

36 # na = func.__code__.co_varnames 

37 keys = inspect.signature(func) 

38 return "**" in str(keys) 

39 

40 

41def extract_function_information(function): 

42 """ 

43 Extracts information about a function. 

44 The function assumes all parameters receive a default value. 

45 

46 @param function function object 

47 @return dictionary { info : value } 

48 

49 The returned dictionary will be composed as follows: 

50 - name: name of the function 

51 - nbpar: number of parameters 

52 - param: list of parameters (dictionary) and their default value 

53 - types: type of parameters (dictionary), if the default value does not exist, 

54 the function will look in the help looking for the following: 

55 @code 

56 param name (type) 

57 @endcode 

58 - help: documentation of the function 

59 - helpparam: help associated to each parameters (dictionary), 

60 assuming they are described in the documentation using 

61 the same format as this docstring 

62 - module: module which defines the function 

63 """ 

64 if function.__doc__ is None: 

65 raise RuntimeError( 

66 "the function given to FrameFunction should be documented: help is displayed," 

67 " if you want parameter to be described, use javadoc format to do so: " 

68 "@<tag> param_name param_meaning with tag=param") 

69 

70 res = dict() 

71 res["name"] = function.__name__ 

72 nbp = function.__code__.co_argcount 

73 par = function.__code__.co_varnames[:nbp] 

74 res["nbpar"] = len(par) 

75 defd = function.__defaults__ if function.__defaults__ is not None else [] 

76 dec = len(par) - len(defd) 

77 

78 typ = {} 

79 p = {} 

80 for pos, a in enumerate(par): 

81 if a == 'fLOG': 

82 continue 

83 p2 = pos - dec 

84 if p2 >= 0: 

85 b = defd[p2] 

86 typ[a] = b.__class__ 

87 else: 

88 b = "" 

89 typ[a] = None 

90 if not a.startswith("_"): 

91 p[a] = b 

92 

93 res["types"] = typ 

94 res["param"] = p 

95 res["help"] = function.__doc__ 

96 

97 mod = function.__module__ 

98 mod = sys.modules.get(mod, None) 

99 res["module"] = mod 

100 

101 regex = re.compile("@" + "param +([a-zA-Z0-9_]+) +(.+)") 

102 alls = regex.findall(res["help"]) 

103 p = {} 

104 for a, b in alls: 

105 a = a.strip() 

106 if a == "fLOG": 

107 continue 

108 p[a] = b.strip() 

109 res["helpparam"] = p 

110 

111 reg = re.compile( 

112 "@" + "param +([a-zA-Z_][a-zA-Z_0-9]*?) +[(]([a-zA-Z]+?)[)]") 

113 alls = reg.findall(res["help"]) 

114 typ = {k: v for k, v in alls} # pylint: disable=R1721 

115 keys = list(res["types"]) 

116 for a in keys: 

117 b = res["types"][a] 

118 if b is None or isinstance(None, b): 

119 b = typ.get(a, None) 

120 if b is not None: 

121 if "|" in b: 

122 e, ee = b.split("|") 

123 e = eval(e) 

124 ee = eval(ee) 

125 res["types"][a] = lambda v, e=e, ee=ee: ee if ( 

126 len(v) == 0 or v == str(ee)) else e(v) 

127 elif b == "datetime": 

128 res["types"][a] = datetime.datetime 

129 else: 

130 res["types"][a] = eval(b) 

131 

132 # If no default value, we assume the type is str. 

133 keys = list(res["types"]) 

134 for a in keys: 

135 b = res["types"][a] 

136 if b is None: 

137 res[b] = str 

138 

139 return res 

140 

141 

142def private_adjust_parameters(param): 

143 """ 

144 Change the value of some parameters when they are NULL: 

145 *user*. Changes the parameters inplace. 

146 

147 @param param list of parameters 

148 """ 

149 res = guess_machine_parameter() 

150 for k in param: 

151 if param[k] is None and k.lower() in ["user", "username"]: 

152 res[k] = res.get("USERNAME", res["USER"]) 

153 

154 

155def private_get_function(function_name): 

156 """ 

157 Returns the function object from its name, the name 

158 must contains a dot "." otherwise the function will assume 

159 it is defined in module @see md default_functions. 

160 

161 @param function_name name of the function 

162 @return object 

163 """ 

164 if "." in function_name: 

165 module = function_name.split(".") 

166 name = module[-1] 

167 fname = ".".join(module[:-1]) 

168 

169 if fname in sys.modules: 

170 mod = sys.modules[fname] 

171 else: 

172 mod = __import__(fname, globals(), locals(), [], 0) 

173 

174 if name not in mod.__dict__: 

175 raise KeyError("module %s, function %s not in %s (path %s)" % 

176 (module, name, str(mod.__dict__.keys()), mod.__file__)) 

177 return mod.__dict__[name] 

178 else: 

179 from .default_functions import file_grep, file_list, file_split, file_head, test_regular_expression 

180 if function_name == "file_grep": 

181 return file_grep 

182 elif function_name == "file_list": 

183 return file_list 

184 elif function_name == "file_split": 

185 return file_split 

186 elif function_name == "file_head": 

187 return file_head 

188 elif function_name == "test_regular_expression": 

189 return test_regular_expression 

190 else: 

191 raise NameError("unknown exception " + function_name)