pystratum_common.wrapper.Wrapper   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 241
Duplicated Lines 97.51 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 31
eloc 93
dl 235
loc 241
ccs 0
cts 87
cp 0
rs 9.92
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A Wrapper.__init__() 29 29 1
A Wrapper._get_wrapper_args() 21 21 4
A Wrapper._write_docstring_parameters() 22 22 4
A Wrapper._write() 7 7 1
A Wrapper._write_line() 17 17 5
A Wrapper.__write_docstring() 13 13 1
A Wrapper.write_routine_method() 15 15 3
A Wrapper._write_result_handler() 6 6 1
A Wrapper._indent_level_down() 7 7 1
A Wrapper._return_type_hint() 3 3 1
A Wrapper.__write_docstring_description() 8 8 2
A Wrapper._write_routine_method_with_lob() 2 2 1
A Wrapper.is_lob_parameter() 9 9 1
A Wrapper._get_docstring_return_type() 3 3 1
A Wrapper._write_separator() 6 6 1
A Wrapper.__write_docstring_return_type() 8 8 2
A Wrapper._write_routine_method_without_lob() 11 11 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
import abc
2
import os
3
from typing import Any, Dict, Optional
4
5
6 View Code Duplication
class Wrapper(metaclass=abc.ABCMeta):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
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
# ----------------------------------------------------------------------------------------------------------------------
243