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
« 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
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 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 Whether 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 (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")
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 Whether one of the parameters is a BLOB or CLOB.
94 :param parameters: The parameters of a stored routine.
95 """
96 raise NotImplementedError()
98 # ------------------------------------------------------------------------------------------------------------------
99 def write_routine_method(self, routine: Dict[str, Any]) -> str:
100 """
101 Returns a complete wrapper method.
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)
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.
118 :param routine: The metadata of the stored routine.
119 """
120 if routine['pydoc']['description']:
121 self._write_line(routine['pydoc']['description'])
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.
128 :param routine: The metadata of the stored routine.
129 """
130 if routine['pydoc']['parameters']:
131 self._write_line('')
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]
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))
145 self._write_line('{0} {1}'.format(indent, param['data_type_descriptor']))
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))
157 # ------------------------------------------------------------------------------------------------------------------
158 def __write_docstring(self, routine: Dict[str, Any]) -> None:
159 """
160 Writes the docstring for the wrapper method of a stored routine.
162 :param routine: The metadata of the stored routine.
163 """
164 self._write_line('"""')
166 self.__write_docstring_description(routine)
167 self._write_docstring_parameters(routine)
168 self.__write_docstring_return_type()
170 self._write_line('"""')
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()
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()
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()
196 # ------------------------------------------------------------------------------------------------------------------
197 def _write_routine_method_with_lob(self, routine: Dict[str, Any]) -> str:
198 return self._write_routine_method_without_lob(routine)
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)
210 return self._code
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.
218 :param routine: The routine metadata.
219 """
220 ret = 'self'
222 for parameter_info in routine['pydoc']['parameters']:
223 if ret:
224 ret += ', '
226 ret += parameter_info['parameter_name']
228 if parameter_info['python_type_hint']:
229 ret += ': ' + parameter_info['python_type_hint']
231 return ret
233# ----------------------------------------------------------------------------------------------------------------------