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

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
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 """
11 # ------------------------------------------------------------------------------------------------------------------
12 def __init__(self, routine: Dict[str, Any], lob_as_string_flag: bool):
13 """
14 Object constructor.
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 """
24 self._code: str = ''
25 """
26 Buffer for the generated code.
27 """
29 self.__indent_level: int = 1
30 """
31 The current level of indentation in the generated code.
32 """
34 self._routine: Dict[str, Any] = routine
35 """
36 The metadata of the stored routine.
37 """
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 """
44 # ------------------------------------------------------------------------------------------------------------------
45 def _write(self, text: str) -> None:
46 """
47 Appends a part of code to the generated code.
49 :param str text: The part of code that must be appended.
50 """
51 self._code += str(text)
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.
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")
72 # ------------------------------------------------------------------------------------------------------------------
73 def _indent_level_down(self, levels: int = 1) -> None:
74 """
75 Decrements the indent level of the generated code.
77 :param levels: The number of levels indent level of the generated code must be decremented.
78 """
79 self.__indent_level -= int(levels)
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))
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.
94 :param parameters: The parameters of a stored routine.
96 :rtype: bool
97 """
98 raise NotImplementedError()
100 # ------------------------------------------------------------------------------------------------------------------
101 def write_routine_method(self, routine: Dict[str, Any]) -> str:
102 """
103 Returns a complete wrapper method.
105 :param dict[str,*] routine: The routine metadata.
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)
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.
122 :param dict routine: The metadata of the stored routine.
123 """
124 if routine['pydoc']['description']:
125 self._write_line(routine['pydoc']['description'])
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.
132 :param dict routine: The metadata of the stored routine.
133 """
134 if routine['pydoc']['parameters']:
135 self._write_line('')
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]
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))
149 self._write_line('{0} {1}'.format(indent, param['data_type_descriptor']))
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))
161 # ------------------------------------------------------------------------------------------------------------------
162 def __write_docstring(self, routine: Dict[str, Any]) -> None:
163 """
164 Writes the docstring for the wrapper method of a stored routine.
166 :param dict routine: The metadata of the stored routine.
167 """
168 self._write_line('"""')
170 self.__write_docstring_description(routine)
171 self._write_docstring_parameters(routine)
172 self.__write_docstring_return_type()
174 self._write_line('"""')
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.
182 :rtype: str
183 """
185 # ------------------------------------------------------------------------------------------------------------------
186 @abc.abstractmethod
187 def _return_type_hint(self) -> str:
188 """
189 Returns the return type hint of the wrapper method.
191 :rtype: str
192 """
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()
202 # ------------------------------------------------------------------------------------------------------------------
203 def _write_routine_method_with_lob(self, routine: Dict[str, Any]) -> str:
204 return self._write_routine_method_without_lob(routine)
206 # ------------------------------------------------------------------------------------------------------------------
207 def _write_routine_method_without_lob(self, routine: Dict[str, Any]) -> str:
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)
217 return self._code
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.
225 :param dict[str,*] routine: The routine metadata.
227 :rtype: str
228 """
229 ret = 'self'
231 for parameter_info in routine['pydoc']['parameters']:
232 if ret:
233 ret += ', '
235 ret += parameter_info['parameter_name']
237 if parameter_info['python_type_hint']:
238 ret += ': ' + parameter_info['python_type_hint']
240 return ret
242# ----------------------------------------------------------------------------------------------------------------------