Passed
Push — master ( 55d9b5...a0853f )
by Jan
01:38 queued 11s
created

graph.oval_graph.OvalNode.change_position()   C

Complexity

Conditions 11

Size

Total Lines 35
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 11

Importance

Changes 0
Metric Value
eloc 31
dl 0
loc 35
ccs 29
cts 29
cp 1
rs 5.4
c 0
b 0
f 0
cc 11
nop 3
crap 11

How to fix   Complexity   

Complexity

Complex classes like graph.oval_graph.OvalNode.change_position() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
'''
2
    Modules form my lib and for create ID
3
'''
4 1
import graph.xml_parser
5 1
import graph.evaluate
6 1
import uuid
7 1
import collections
8
9
'''
10
    This module contains methods and classes for
11
    constructing and controlling an oval tree.
12
'''
13
14
15 1
class OvalNode():
16
    '''
17
    The OvalNode object is one node of oval graph.
18
19
    Args:
20
        node_id (str|int): identifies node
21
        input_node_type (str): type of node (value or operator)
22
        input_value (str): value of node
23
        children ([OvalNode]): array of children of node
24
25
    Attributes:
26
        node_id (str): id of node
27
        node_type (str): type node
28
        value (str): value of node for operator and,
29
        or, one etc... and for value true, false, error etc...
30
        children ([OvalNode]): children of node
31
    '''
32
33 1
    def __init__(self, node_id, input_node_type, input_value, children=None):
34 1
        self.node_id = node_id
35 1
        value = input_value.lower()
36 1
        node_type = input_node_type.lower()
37 1
        if node_type == "value" or node_type == "operator":
38 1
            self.node_type = node_type
39
        else:
40 1
            raise ValueError("err- unknown type")
41 1
        allowed_operators = [
42
            "or",
43
            "and",
44
            "one",
45
            "xor"]
46 1
        allowed_values = [
47
            "true",
48
            "false",
49
            "error",
50
            "unknown",
51
            "noteval",
52
            "notappl"]
53 1
        if self.node_type == "value":
54 1
            if value in allowed_values:
55 1
                self.value = value
56
            else:
57 1
                raise ValueError("err- unknown value")
58 1
        if self.node_type == "operator":
59 1
            if value in allowed_operators:
60 1
                self.value = value
61
            else:
62 1
                raise ValueError("err- unknown operator")
63 1
        self.children = []
64 1
        if children is not None:
65 1
            for child in children:
66 1
                self.add_child(child)
67
        else:
68 1
            if self.node_type == "operator":
69 1
                raise ValueError('err- OR, XOR, ONE, AND have child!')
70
71 1
    def __repr__(self):
72 1
        return self.value
73
74 1
    def add_child(self, node):
75 1
        if self.node_type == "operator":
76 1
            assert isinstance(node, OvalNode)
77 1
            self.children.append(node)
78
        else:
79 1
            self.children = None
80 1
            raise ValueError(
81
                "err- true, false, error, unknown. noteval, notappl have not child!")
82
83 1
    def get_result_counts(self):
84 1
        result = {
85
            'true_cnt': 0,
86
            'false_cnt': 0,
87
            'error_cnt': 0,
88
            'unknown_cnt': 0,
89
            'noteval_cnt': 0,
90
            'notappl_cnt': 0
91
        }
92
93 1
        for child in self.children:
94 1
            if child.value == 'true':
95 1
                result['true_cnt'] += 1
96 1
            elif child.value == 'false':
97 1
                result['false_cnt'] += 1
98 1
            elif child.value == 'error':
99 1
                result['error_cnt'] += 1
100 1
            elif child.value == 'unknown':
101 1
                result['unknown_cnt'] += 1
102 1
            elif child.value == 'noteval':
103 1
                result['noteval_cnt'] += 1
104 1
            elif child.value == 'notappl':
105 1
                result['notappl_cnt'] += 1
106
            else:
107 1
                if self.node_type == "operator":
108 1
                    result[child.evaluate_tree() + "_cnt"] += 1
109 1
        return result
110
111 1
    def evaluate_tree(self):
112 1
        result = self.get_result_counts()
113
114 1
        if result['notappl_cnt'] > 0\
115
                and graph.evaluate.eq_zero(result, 'false_cnt')\
116
                and graph.evaluate.error_unknown_noteval_eq_zero(result)\
117
                and graph.evaluate.eq_zero(result, 'true_cnt'):
118 1
            return "notappl"
119
        else:
120 1
            if self.value == "or":
121 1
                return graph.evaluate.oval_operator_or(result)
122 1
            elif self.value == "and":
123 1
                return graph.evaluate.oval_operator_and(result)
124 1
            elif self.value == "one":
125 1
                return graph.evaluate.oval_operator_one(result)
126 1
            elif self.value == "xor":
127 1
                return graph.evaluate.oval_operator_xor(result)
128
129 1
    def save_tree_to_dict(self):
130 1
        if not self.children:
131 1
            return {
132
                'node_id': self.node_id,
133
                'type': self.node_type,
134
                'value': self.value,
135
                'child': None
136
            }
137 1
        return {
138
            'node_id': self.node_id,
139
            'type': self.node_type,
140
            'value': self.value,
141
            'child': [child.save_tree_to_dict() for child in self.children]
142
        }
143
144 1
    def find_node_with_ID(self, node_id):
145 1
        if self.node_id == node_id:
146 1
            return self
147
        else:
148 1
            for child in self.children:
149 1
                if child.node_id == node_id:
150 1
                    return child
151 1
            for child in self.children:
152 1
                if child.children != []:
153 1
                    return child.find_node_with_ID(node_id)
154
155 1
    def add_to_tree(self, node_id, newNode):
156 1
        self.find_node_with_ID(node_id).add_child(newNode)
157
158 1
    def change_tree_value(self, node_id, value):
159 1
        self.find_node_with_ID(node_id).value = value
160
161
    # Methods for interpreting oval tree with SigmaJS
162
163 1
    def _get_label(self):
164 1
        if self.node_type == 'value':
165 1
            return \
166
                str(self.node_id).\
167
                replace('xccdf_org.ssgproject.content_rule_', '').\
168
                replace('oval:ssg-', '').\
169
                replace(':def:1', '').\
170
                replace(':tst:1', '').\
171
                replace('test_', '')
172
        else:
173 1
            if str(self.node_id).startswith(
174
                    'xccdf_org.ssgproject.content_rule_'):
175 1
                return \
176
                    str(self.node_id).\
177
                    replace('xccdf_org.ssgproject.content_', '')
178 1
            return self.value
179
180 1
    def _get_node_color(self):
181 1
        value = self.evaluate_tree()
182 1
        if value is None:
183 1
            value = self.value
184 1
        VALUE_TO_COLOR = {
185
            "true": "#00ff00",
186
            "false": "#ff0000",
187
            "error": "#000000",
188
            "unknown": "#000000",
189
            "noteval": "#000000",
190
            "notappl": "#000000"
191
        }
192 1
        return VALUE_TO_COLOR[value]
193
194 1
    def _get_node_title(self):
195 1
        value = self.evaluate_tree()
196 1
        if value is None:
197 1
            value = self.value
198 1
        if value == 'true' or value == 'false':
199 1
            return self.node_id
200 1
        return str(self.node_id) + ' ' + self.value
201
202 1
    def _create_node(self, x, y):
203
        # print(self.evaluate_tree(),self.value)
204 1
        return {
205
            'id': self.node_id,
206
            'label': self._get_label(),
207
            'url': 'null',
208
            'text': 'null',
209
            'title': self._get_node_title(),
210
            "x": x,
211
            "y": y,
212
            "size": 3,
213
            "color": self._get_node_color()}
214
215 1
    def _create_edge(self, id_source, id_target, target_node):
216 1
        return {
217
            "id": str(uuid.uuid4()),
218
            "source": id_source,
219
            "target": id_target,
220
            "color": self._get_color_edge(target_node)
221
        }
222
223 1
    def _get_color_edge(self, target_node):
224 1
        return target_node['color']
225
226 1
    def create_list_of_id(self, array_of_ids=None):
227 1
        if array_of_ids is None:
228 1
            array_of_ids = []
229 1
            array_of_ids.append(self.node_id)
230 1
        for child in self.children:
231 1
            if child.node_type != "operator":
232 1
                array_of_ids.append(child.node_id)
233
            else:
234 1
                array_of_ids.append(child.node_id)
235 1
                child.create_list_of_id(array_of_ids)
236 1
        return array_of_ids
237
238 1
    def _remove_Duplication(self, graph_data):
239 1
        array_of_ids = self.create_list_of_id()
240 1
        out = dict(nodes=[], edges=graph_data['edges'])
241 1
        duplicate_ids = [item for item, count in collections.Counter(
242
            array_of_ids).items() if count > 1]
243
244 1
        for node in graph_data['nodes']:
245 1
            if node['id'] not in duplicate_ids:
246 1
                out['nodes'].append(node)
247
248 1
        for id in duplicate_ids:
249 1
            for node in graph_data['nodes']:
250 1
                if node['id'] == id:
251 1
                    out['nodes'].append(node)
252 1
                    break
253 1
        return out
254
255 1
    def _fix_graph(self, preprocessed_graph_data):
256 1
        for node in preprocessed_graph_data['nodes']:
257 1
            for node1 in preprocessed_graph_data['nodes']:
258 1
                if node['x'] == node1['x'] and node['y'] == node1['y']:
259 1
                    node['x'] = node['x'] - 1
260 1
        return preprocessed_graph_data
261
262 1
    def _help_to_sigma_dict(self, x, y, preprocessed_graph_data=None):
263 1
        if preprocessed_graph_data is None:
264 1
            preprocessed_graph_data = dict(nodes=[], edges=[])
265 1
            preprocessed_graph_data['nodes'].append(self._create_node(x, y))
266 1
        y_row = y + 1
267 1
        x_row = x
268 1
        for node in self.children:
269 1
            preprocessed_graph_data['nodes'].append(
270
                node._create_node(x_row, y_row))
271 1
            preprocessed_graph_data['edges'].append(node._create_edge(
272
                self.node_id, node.node_id, preprocessed_graph_data['nodes'][-1]))
273 1
            x_row = x_row + 1
274 1
            if node.children is not None:
275 1
                preprocessed_graph_data = node._help_to_sigma_dict(
276
                    x_row + 1, y_row + 1, preprocessed_graph_data)
277 1
        return self._fix_graph(preprocessed_graph_data)
278
279 1
    def count_max_y(self, out):
280 1
        max_y = 0
281
282 1
        for node in out['nodes']:
283 1
            if max_y < node['y']:
284 1
                max_y = node['y']
285 1
        return max_y
286
287 1
    def create_nodes_in_rows(self, rows):
288 1
        nodes_in_rows = dict()
289
290 1
        for i in range(rows + 1):
291 1
            nodes_in_rows[i] = []
292 1
        return nodes_in_rows
293
294 1
    def push_nodes_to_nodes_in_row(self, out, nodes_in_rows):
295 1
        for node in out['nodes']:
296 1
            nodes_in_rows[node['y']].append(node)
297
298 1
    def remove_empty_rows(self, nodes_in_rows, max_y):
299 1
        for row in range(max_y + 1):
300 1
            if not nodes_in_rows[row]:
301 1
                del nodes_in_rows[row]
302
303 1
    def move_rows(self, nodes_in_rows):
304 1
        count = 0
305 1
        nodes_in_rows1 = dict()
306
307 1
        for row in nodes_in_rows:
308 1
            nodes_in_rows1[count] = nodes_in_rows[row]
309 1
            for node in nodes_in_rows1[count]:
310 1
                node['y'] = count
311 1
            count += 1
312 1
        return nodes_in_rows1
313
314 1
    def create_positions(self, nodes_in_rows):
315 1
        positions = []
316 1
        for row in nodes_in_rows:
317 1
            len_of_row = len(nodes_in_rows[row])
318 1
            if len_of_row > 1:
319 1
                if (len_of_row % 2) == 1:
320 1
                    len_of_row += 1
321
322 1
                for i in range((int(-(len_of_row / 2))) * 2,
323
                               (int(+(len_of_row / 2)) + 1) * 2, 2):
324 1
                    positions.append(i)
325
326 1
                if len_of_row == 2:
327 1
                    positions.remove(0)
328
329 1
                if len(nodes_in_rows[row]) < len(positions):
330 1
                    positions.pop()
331 1
                    if len(nodes_in_rows[row]) < len(positions):
332 1
                        positions.pop(0)
333
334 1
                count = 0
335
336 1
                for pos in positions:
337 1
                    nodes_in_rows[row][count]['x'] = pos
338 1
                    count += 1
339 1
                positions = []
340
            else:
341 1
                nodes_in_rows[row][0]['x'] = 0
342
343 1
        return positions
344
345 1
    def convert_nodes_in_rows_to_nodes(self, nodes_in_rows):
346 1
        nodes = []
347 1
        for row in nodes_in_rows:
348 1
            for node in nodes_in_rows[row]:
349 1
                nodes.append(node)
350 1
        return nodes
351
352 1
    def change_position(self, positions, nodes_in_rows):
353 1
        x = 0.6
354 1
        up_and_down = True
355 1
        down = False
356 1
        down_row = False
357 1
        save_x = 0
358 1
        continue_move = False
359
360 1
        for row in nodes_in_rows:
361 1
            for node in nodes_in_rows[row]:
362 1
                if (len(node['label']) > 6
363
                        and len(node['label']) < 40
364
                        or continue_move):
365 1
                    if up_and_down:
366 1
                        node['y'] = node['y'] + (0.6 * x)
367 1
                        up_and_down = False
368
                    else:
369 1
                        up_and_down = True
370 1
                    continue_move = True
371 1
                elif len(node['label']) > 30:
372 1
                    node['y'] = node['y'] + (0.6 * x)
373 1
                    x += 0.6
374 1
                    save_x = x
375 1
                    down = True
376
                else:
377 1
                    if down:
378 1
                        node['y'] = node['y'] + (0.6 * save_x)
379
380 1
                    if down_row:
381 1
                        node['y'] = node['y'] + (0.6 * save_x) - 0.7
382 1
            if down:
383 1
                down = False
384 1
                down_row = True
385 1
            continue_move = False
386 1
            x = 0.6
387
388 1
    def sort(self, array):
389 1
        less = []
390 1
        equal = []
391 1
        greater = []
392
393 1
        if len(array) > 1:
394 1
            pivot = array[0]['x']
395 1
            for node in array:
396 1
                if node['x'] < pivot:
397
                    less.append(node)
398 1
                if node['x'] == pivot:
399 1
                    equal.append(node)
400 1
                if node['x'] > pivot:
401 1
                    greater.append(node)
402 1
            return self.sort(less) + equal + self.sort(greater)
403
        else:
404 1
            return array
405
406 1
    def sort_nodes(self, nodes_in_rows):
407 1
        for row in nodes_in_rows:
408 1
            nodes_in_rows[row] = self.sort(nodes_in_rows[row])
409
410 1
    def center_graph(self, out):
411 1
        max_y = self.count_max_y(out)
412 1
        nodes_in_rows = self.create_nodes_in_rows(max_y)
413 1
        self.push_nodes_to_nodes_in_row(out, nodes_in_rows)
414 1
        self.remove_empty_rows(nodes_in_rows, max_y)
415 1
        nodes_in_rows = self.move_rows(nodes_in_rows)
416 1
        self.sort_nodes(nodes_in_rows)
417 1
        positions = self.create_positions(nodes_in_rows)
418 1
        self.change_position(positions, nodes_in_rows)
419 1
        out['nodes'] = self.convert_nodes_in_rows_to_nodes(nodes_in_rows)
420 1
        return out
421
422 1
    def to_sigma_dict(self, x, y):
423 1
        return self.center_graph(
424
            self._remove_Duplication(
425
                self._help_to_sigma_dict(
426
                    x, y)))
427
428
429 1
def build_nodes_form_xml(xml_src, rule_id):
430 1
    parser = graph.xml_parser.xml_parser(xml_src)
431 1
    return parser.get_oval_graph(rule_id)
432
433
434 1
def restore_dict_to_tree(dict_of_tree):
435 1
    if dict_of_tree["child"] is None:
436 1
        return OvalNode(
437
            dict_of_tree["node_id"],
438
            dict_of_tree["type"],
439
            dict_of_tree["value"])
440 1
    return OvalNode(
441
        dict_of_tree["node_id"],
442
        dict_of_tree["type"],
443
        dict_of_tree["value"],
444
        [restore_dict_to_tree(i) for i in dict_of_tree["child"]])
445