Passed
Pull Request — master (#108)
by Jan
02:03
created

oval_graph._xml_parser_test_info   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 188
Duplicated Lines 0 %

Test Coverage

Coverage 99.17%

Importance

Changes 0
Metric Value
eloc 154
dl 0
loc 188
ccs 120
cts 121
cp 0.9917
rs 7.44
c 0
b 0
f 0
wmc 52

22 Methods

Rating   Name   Duplication   Size   Complexity  
A _XmlParserTestInfo._get_collected_objects_info() 0 15 4
A _XmlParserTestInfo._get_oval_definitions() 0 4 1
A _XmlParserTestInfo._get_key_for_element() 0 2 2
A _XmlParserTestInfo._get_item_ref() 0 2 2
A _XmlParserTestInfo._get_system_data() 0 9 2
A _XmlParserTestInfo._get_objects() 0 7 2
A _XmlParserTestInfo._get_collected_objects() 0 9 2
A _XmlParserTestInfo._get_tests() 0 4 1
A _XmlParserTestInfo._xml_element_to_dict() 0 14 2
A _XmlParserTestInfo.__init__() 0 8 1
A _XmlParserTestInfo._find_item_ref() 0 5 1
A _XmlParserTestInfo._get_unique_key() 0 2 1
A _XmlParserTestInfo._get_unique_id_in_dict() 0 5 2
A _XmlParserTestInfo._get_object_items() 0 9 4
A _XmlParserTestInfo._get_ref_var() 0 13 5
A _XmlParserTestInfo._get_item() 0 7 4
A _XmlParserTestInfo._get_tests_info() 0 15 4
A _XmlParserTestInfo.get_info_about_test() 0 4 3
A _XmlParserTestInfo._fix_message() 0 5 3
A _XmlParserTestInfo._get_object_info() 0 5 1
A _XmlParserTestInfo._collected_object_is_not_none_and_contain_var_ref() 0 5 3
A _XmlParserTestInfo._find_item_by_id() 0 4 2

How to fix   Complexity   

Complexity

Complex classes like oval_graph._xml_parser_test_info 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 1
import uuid
2
3 1
ns = {
4
    'XMLSchema': 'http://oval.mitre.org/XMLSchema/oval-results-5',
5
    'xccdf': 'http://checklists.nist.gov/xccdf/1.2',
6
    'arf': 'http://scap.nist.gov/schema/asset-reporting-format/1.1',
7
    'oval-definitions': 'http://oval.mitre.org/XMLSchema/oval-definitions-5',
8
    'scap': 'http://scap.nist.gov/schema/scap/source/1.2',
9
    'oval-characteristics': 'http://oval.mitre.org/XMLSchema/oval-system-characteristics-5',
10
}
11
12
13 1
class _XmlParserTestInfo:
14 1
    def __init__(self, report_data):
15 1
        self.report_data = report_data
16 1
        self.oval_definitions = self._get_oval_definitions()
17 1
        self.tests = self._get_tests()
18 1
        self.objects = self._get_objects()
19 1
        self.collected_objects = self._get_collected_objects()
20 1
        self.system_data = self._get_system_data()
21 1
        self.tests_info = self._get_tests_info()
22
23 1
    def _get_collected_objects(self):
24 1
        data = self.report_data.find(
25
            ('.//XMLSchema:oval_results/XMLSchema:results/'
26
             'XMLSchema:system/oval-characteristics:oval_system_characteristics'
27
             '/oval-characteristics:collected_objects'), ns)
28 1
        out = {}
29 1
        for item in data:
30 1
            out[item.attrib.get('id')] = item
31 1
        return out
32
33 1
    def _get_system_data(self):
34 1
        data = self.report_data.find(
35
            ('.//XMLSchema:oval_results/XMLSchema:results/'
36
             'XMLSchema:system/oval-characteristics:oval_system_characteristics'
37
             '/oval-characteristics:system_data'), ns)
38 1
        out = {}
39 1
        for item in data:
40 1
            out[item.attrib.get('id')] = item
41 1
        return out
42
43 1
    def _get_oval_definitions(self):
44 1
        data = self.report_data.find(
45
            ('.//XMLSchema:oval_results/oval-definitions:oval_definitions'), ns)
46 1
        return data
47
48 1
    def _get_tests(self):
49 1
        data = self.oval_definitions.find(
50
            ('.//oval-definitions:tests'), ns)
51 1
        return data
52
53 1
    def _get_objects(self):
54 1
        data = self.oval_definitions.find(
55
            ('.//oval-definitions:objects'), ns)
56 1
        out = {}
57 1
        for item in data:
58 1
            out[item.attrib.get('id')] = item
59 1
        return out
60
61 1
    def _get_key_for_element(self, element):
62 1
        return element.tag.split('}')[1] if '}' in element.tag else element.tag
63
64 1
    def _find_item_ref(self, object_):
65 1
        return list(
66
            filter(
67
                None, [
68
                    self._get_item_ref(item) for item in object_]))
69
70 1
    def _get_item_ref(self, item):
71 1
        return item.get('item_ref') if item.get('item_ref') else None
72
73 1
    def _get_unique_key(self, key):
74 1
        return key + '@' + str(uuid.uuid4())
75
76 1
    def _get_unique_id_in_dict(self, object_, dict_):
77 1
        if self._get_key_for_element(object_) in dict_:
78 1
            return self._get_unique_key(self._get_key_for_element(object_))
79
        else:
80 1
            return self._get_key_for_element(object_)
81
82 1
    def _get_collected_objects_info(self, collected_object, object_):
83 1
        out = {}
84 1
        if len(collected_object) == 0:
85 1
            out[self._get_unique_id_in_dict(object_, out)
86
                ] = self._get_object_items(object_, collected_object)
87
        else:
88 1
            item_refs = self._find_item_ref(collected_object)
89 1
            if item_refs:
90 1
                for item_id in item_refs:
91 1
                    out[self._get_unique_id_in_dict(
92
                        object_, out)] = self._get_item(item_id)
93
            else:
94 1
                out[self._get_unique_id_in_dict(
95
                    object_, out)] = self._get_object_items(object_, collected_object)
96 1
        return out
97
98 1
    def _xml_element_to_dict(self, object_, collected_object):
99 1
        result = {}
100 1
        if collected_object is not None:
101 1
            result[
102
                collected_object.attrib.get('id')
103
            ] = collected_object.attrib.get('flag')
104 1
            out = {}
105 1
            result.update(
106
                self._get_collected_objects_info(collected_object, object_))
107
        else:
108 1
            result[object_.attrib.get('id')] = "does not exist"
109 1
            result[self._get_unique_id_in_dict(
110
                object_, result)] = self._get_object_items(object_, collected_object)
111 1
        return result
112
113 1
    def _get_object_items(self, object_, collected_object):
114 1
        out = {}
115 1
        for element in object_.iterchildren():
116 1
            if element.text and element.text.strip():
117 1
                out[self._get_unique_id_in_dict(element, out)] = element.text
118
            else:
119 1
                out[self._get_unique_id_in_dict(element, out)] = self._get_ref_var(
120
                    element, collected_object)
121 1
        return out
122
123 1
    def _get_ref_var(self, element, collected_object):
124 1
        variable_value = ''
125 1
        if self._collected_object_is_not_none_and_contain_var_ref(
126
                element, collected_object):
127 1
            var_id = element.attrib.get('var_ref')
128 1
            for item in collected_object:
129 1
                if var_id == item.attrib.get('variable_id'):
130 1
                    variable_value += item.text
131 1
                elif self._get_key_for_element(item) == 'message':
132 1
                    variable_value += self._fix_message(item, var_id) + '<br>'
133
        else:
134 1
            variable_value = 'no value'
135 1
        return variable_value
136
137 1
    def _fix_message(self, item, var_id):
138 1
        if len(
139
                item.text) == 99 and var_id[:99 - item.text.find('(')] in var_id:
140 1
            return item.text[:item.text.find('(') + 1] + var_id + ')'
141
        return item.text
142
143 1
    def _collected_object_is_not_none_and_contain_var_ref(
144
            self, element, collected_object):
145 1
        if collected_object is not None and 'var_ref' in element.attrib:
146 1
            return len(collected_object)
147 1
        return False
148
149 1
    def _get_item(self, item_ref):
150 1
        item = self._find_item_by_id(self.system_data, item_ref)
151 1
        out = {}
152 1
        for element in item.iterchildren():
153 1
            if element.text and element.text.strip():
154 1
                out[self._get_unique_id_in_dict(element, out)] = element.text
155 1
        return out
156
157 1
    def _find_item_by_id(self, items, id):
158 1
        if id in items.keys():
159 1
            return items[id]
160 1
        return None
161
162 1
    def _get_object_info(self, id_object):
163 1
        object_ = self._find_item_by_id(self.objects, id_object)
164 1
        object_collected = self._find_item_by_id(
165
            self.collected_objects, id_object)
166 1
        return self._xml_element_to_dict(object_, object_collected)
167
168 1
    def _get_tests_info(self):
169 1
        out = []
170 1
        for test in self.tests:
171 1
            objects = []
172 1
            for item in test:
173 1
                object_id = item.attrib.get('object_ref')
174 1
                if object_id:
175 1
                    objects.append(self._get_object_info(object_id))
176 1
            out.append(
177
                dict(
178
                    id=test.attrib.get('id'),
179
                    comment=test.attrib.get('comment'),
180
                    objects=objects,
181
                ))
182 1
        return out
183
184 1
    def get_info_about_test(self, id):
185 1
        for test in self.tests_info:
186 1
            if test['id'] == id:
187
                return test
188