Coverage for pystratum_common/wrapper/Wrapper.py: 0%

91 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-13 08:46 +0200

1import abc 

2import os 

3from typing import Any, Dict, Optional 

4 

5 

6class Wrapper(metaclass=abc.ABCMeta): 

7 """ 

8 Parent class for classes that generate Python code, i.e. wrappers, for calling a stored procedures and functions. 

9 """ 

10 

11 # ------------------------------------------------------------------------------------------------------------------ 

12 def __init__(self, routine: Dict[str, Any], lob_as_string_flag: bool): 

13 """ 

14 Object constructor. 

15 

16 :param routine: The metadata of the stored routine. 

17 :param bool lob_as_string_flag: If 'True' LOBs must be treated as strings/bytes. 

18 """ 

19 self._page_width: int = 120 

20 """ 

21 The maximum number of columns in the source code. 

22 """ 

23 

24 self._code: str = '' 

25 """ 

26 Buffer for the generated code. 

27 """ 

28 

29 self.__indent_level: int = 1 

30 """ 

31 The current level of indentation in the generated code. 

32 """ 

33 

34 self._routine: Dict[str, Any] = routine 

35 """ 

36 The metadata of the stored routine. 

37 """ 

38 

39 self._lob_as_string_flag: bool = lob_as_string_flag == 'True' 

40 """ 

41 Whether BLOBs and CLOBs must be treated as strings. 

42 """ 

43 

44 # ------------------------------------------------------------------------------------------------------------------ 

45 def _write(self, text: str) -> None: 

46 """ 

47 Appends a part of code to the generated code. 

48 

49 :param str text: The part of code that must be appended. 

50 """ 

51 self._code += str(text) 

52 

53 # ------------------------------------------------------------------------------------------------------------------ 

54 def _write_line(self, line: Optional[str] = None) -> None: 

55 """ 

56 Appends a line of code to the generated code and adjust the indent level of the generated code. 

57 

58 :param line: The line of code (without LF) that must be appended. 

59 """ 

60 if line is None: 

61 self._write("\n") 

62 if self.__indent_level > 1: 

63 self.__indent_level -= 1 

64 elif line == '': 

65 self._write("\n") 

66 else: 

67 line = (' ' * 4 * self.__indent_level) + line 

68 if line[-1:] == ':': 

69 self.__indent_level += 1 

70 self._write(line + "\n") 

71 

72 # ------------------------------------------------------------------------------------------------------------------ 

73 def _indent_level_down(self, levels: int = 1) -> None: 

74 """ 

75 Decrements the indent level of the generated code. 

76 

77 :param levels: The number of levels indent level of the generated code must be decremented. 

78 """ 

79 self.__indent_level -= int(levels) 

80 

81 # ------------------------------------------------------------------------------------------------------------------ 

82 def _write_separator(self) -> None: 

83 """ 

84 Inserts a horizontal (commented) line tot the generated code. 

85 """ 

86 tmp = self._page_width - ((4 * self.__indent_level) + 2) 

87 self._write_line('# ' + ('-' * tmp)) 

88 

89 # ------------------------------------------------------------------------------------------------------------------ 

90 def is_lob_parameter(self, parameters: Dict[str, Any]) -> bool: 

91 """ 

92 Returns Whether one of the parameters is a BLOB or CLOB. 

93 

94 :param parameters: The parameters of a stored routine. 

95 """ 

96 raise NotImplementedError() 

97 

98 # ------------------------------------------------------------------------------------------------------------------ 

99 def write_routine_method(self, routine: Dict[str, Any]) -> str: 

100 """ 

101 Returns a complete wrapper method. 

102 

103 :param routine: The routine metadata. 

104 """ 

105 if self._lob_as_string_flag: 

106 return self._write_routine_method_without_lob(routine) 

107 else: 

108 if self.is_lob_parameter(routine['parameters']): 

109 return self._write_routine_method_with_lob(routine) 

110 else: 

111 return self._write_routine_method_without_lob(routine) 

112 

113 # ------------------------------------------------------------------------------------------------------------------ 

114 def __write_docstring_description(self, routine: Dict[str, Any]) -> None: 

115 """ 

116 Writes the description part of the docstring for the wrapper method of a stored routine. 

117 

118 :param routine: The metadata of the stored routine. 

119 """ 

120 if routine['pydoc']['description']: 

121 self._write_line(routine['pydoc']['description']) 

122 

123 # ------------------------------------------------------------------------------------------------------------------ 

124 def _write_docstring_parameters(self, routine: Dict[str, Any]) -> None: 

125 """ 

126 Writes the parameters part of the docstring for the wrapper method of a stored routine. 

127 

128 :param routine: The metadata of the stored routine. 

129 """ 

130 if routine['pydoc']['parameters']: 

131 self._write_line('') 

132 

133 for param in routine['pydoc']['parameters']: 

134 lines = param['description'].split(os.linesep) 

135 self._write_line(':param {0} {1}: {2}'.format(param['python_type'], 

136 param['parameter_name'], 

137 lines[0])) 

138 del lines[0] 

139 

140 tmp = ':param {0} {1}:'.format(param['python_type'], param['parameter_name']) 

141 indent = ' ' * len(tmp) 

142 for line in lines: 

143 self._write_line('{0} {1}'.format(indent, line)) 

144 

145 self._write_line('{0} {1}'.format(indent, param['data_type_descriptor'])) 

146 

147 # ------------------------------------------------------------------------------------------------------------------ 

148 def __write_docstring_return_type(self) -> None: 

149 """ 

150 Writes the return type part of the docstring for the wrapper method of a stored routine. 

151 """ 

152 rtype = self._get_docstring_return_type() 

153 if rtype: 

154 self._write_line('') 

155 self._write_line(':rtype: {0}'.format(rtype)) 

156 

157 # ------------------------------------------------------------------------------------------------------------------ 

158 def __write_docstring(self, routine: Dict[str, Any]) -> None: 

159 """ 

160 Writes the docstring for the wrapper method of a stored routine. 

161 

162 :param routine: The metadata of the stored routine. 

163 """ 

164 self._write_line('"""') 

165 

166 self.__write_docstring_description(routine) 

167 self._write_docstring_parameters(routine) 

168 self.__write_docstring_return_type() 

169 

170 self._write_line('"""') 

171 

172 # ------------------------------------------------------------------------------------------------------------------ 

173 @abc.abstractmethod 

174 def _get_docstring_return_type(self) -> str: 

175 """ 

176 Returns the return type of the wrapper method to be used in the docstring. 

177 """ 

178 raise NotImplementedError() 

179 

180 # ------------------------------------------------------------------------------------------------------------------ 

181 @abc.abstractmethod 

182 def _return_type_hint(self) -> str: 

183 """ 

184 Returns the return type hint of the wrapper method. 

185 """ 

186 raise NotImplementedError() 

187 

188 # ------------------------------------------------------------------------------------------------------------------ 

189 @abc.abstractmethod 

190 def _write_result_handler(self, routine: Dict[str, Any]) -> None: 

191 """ 

192 Generates code for calling the stored routine in the wrapper method. 

193 """ 

194 raise NotImplementedError() 

195 

196 # ------------------------------------------------------------------------------------------------------------------ 

197 def _write_routine_method_with_lob(self, routine: Dict[str, Any]) -> str: 

198 return self._write_routine_method_without_lob(routine) 

199 

200 # ------------------------------------------------------------------------------------------------------------------ 

201 def _write_routine_method_without_lob(self, routine: Dict[str, Any]) -> str: 

202 self._write_line() 

203 self._write_separator() 

204 self._write_line('def {0!s}({1!s}) -> {2!s}:'.format(str(routine['routine_name']), 

205 str(self._get_wrapper_args(routine)), 

206 str(self._return_type_hint()))) 

207 self.__write_docstring(routine) 

208 self._write_result_handler(routine) 

209 

210 return self._code 

211 

212 # ------------------------------------------------------------------------------------------------------------------ 

213 @staticmethod 

214 def _get_wrapper_args(routine: Dict[str, Any]) -> str: 

215 """ 

216 Returns code for the parameters of the wrapper method for the stored routine. 

217 

218 :param routine: The routine metadata. 

219 """ 

220 ret = 'self' 

221 

222 for parameter_info in routine['pydoc']['parameters']: 

223 if ret: 

224 ret += ', ' 

225 

226 ret += parameter_info['parameter_name'] 

227 

228 if parameter_info['python_type_hint']: 

229 ret += ': ' + parameter_info['python_type_hint'] 

230 

231 return ret 

232 

233# ----------------------------------------------------------------------------------------------------------------------