Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 dict 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 If True 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 (with out 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 True of one of the parameters is a BLOB or CLOB. Otherwise, returns False. 

93 

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

95 

96 :rtype: bool 

97 """ 

98 raise NotImplementedError() 

99 

100 # ------------------------------------------------------------------------------------------------------------------ 

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

102 """ 

103 Returns a complete wrapper method. 

104 

105 :param dict[str,*] routine: The routine metadata. 

106 

107 :rtype: str 

108 """ 

109 if self._lob_as_string_flag: 

110 return self._write_routine_method_without_lob(routine) 

111 else: 

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

113 return self._write_routine_method_with_lob(routine) 

114 else: 

115 return self._write_routine_method_without_lob(routine) 

116 

117 # ------------------------------------------------------------------------------------------------------------------ 

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

119 """ 

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

121 

122 :param dict routine: The metadata of the stored routine. 

123 """ 

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

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

126 

127 # ------------------------------------------------------------------------------------------------------------------ 

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

129 """ 

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

131 

132 :param dict routine: The metadata of the stored routine. 

133 """ 

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

135 self._write_line('') 

136 

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

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

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

140 param['parameter_name'], 

141 lines[0])) 

142 del lines[0] 

143 

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

145 indent = ' ' * len(tmp) 

146 for line in lines: 

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

148 

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

150 

151 # ------------------------------------------------------------------------------------------------------------------ 

152 def __write_docstring_return_type(self) -> None: 

153 """ 

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

155 """ 

156 rtype = self._get_docstring_return_type() 

157 if rtype: 

158 self._write_line('') 

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

160 

161 # ------------------------------------------------------------------------------------------------------------------ 

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

163 """ 

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

165 

166 :param dict routine: The metadata of the stored routine. 

167 """ 

168 self._write_line('"""') 

169 

170 self.__write_docstring_description(routine) 

171 self._write_docstring_parameters(routine) 

172 self.__write_docstring_return_type() 

173 

174 self._write_line('"""') 

175 

176 # ------------------------------------------------------------------------------------------------------------------ 

177 @abc.abstractmethod 

178 def _get_docstring_return_type(self) -> str: 

179 """ 

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

181 

182 :rtype: str 

183 """ 

184 

185 # ------------------------------------------------------------------------------------------------------------------ 

186 @abc.abstractmethod 

187 def _return_type_hint(self) -> str: 

188 """ 

189 Returns the return type hint of the wrapper method. 

190 

191 :rtype: str 

192 """ 

193 

194 # ------------------------------------------------------------------------------------------------------------------ 

195 @abc.abstractmethod 

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

197 """ 

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

199 """ 

200 raise NotImplementedError() 

201 

202 # ------------------------------------------------------------------------------------------------------------------ 

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

204 return self._write_routine_method_without_lob(routine) 

205 

206 # ------------------------------------------------------------------------------------------------------------------ 

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

208 

209 self._write_line() 

210 self._write_separator() 

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

212 str(self._get_wrapper_args(routine)), 

213 str(self._return_type_hint()))) 

214 self.__write_docstring(routine) 

215 self._write_result_handler(routine) 

216 

217 return self._code 

218 

219 # ------------------------------------------------------------------------------------------------------------------ 

220 @staticmethod 

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

222 """ 

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

224 

225 :param dict[str,*] routine: The routine metadata. 

226 

227 :rtype: str 

228 """ 

229 ret = 'self' 

230 

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

232 if ret: 

233 ret += ', ' 

234 

235 ret += parameter_info['parameter_name'] 

236 

237 if parameter_info['python_type_hint']: 

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

239 

240 return ret 

241 

242# ----------------------------------------------------------------------------------------------------------------------