DbusDocument.Analyze()   F
last analyzed

Complexity

Conditions 11

Size

Total Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
dl 0
loc 67
rs 3.75
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like DbusDocument.Analyze() 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
import os
2
3
import dbus.service  # Ignore PyImportSortBear
4
5
from coalib.misc.Exceptions import get_exitcode
6
from coalib.output.Interactions import fail_acquire_settings
7
from coalib.output.printers.ListLogPrinter import ListLogPrinter
8
from coalib.parsing.Globbing import fnmatch
9
from coalib.processes.Processing import execute_section
10
from coalib.results.HiddenResult import HiddenResult
11
from coalib.settings.ConfigurationGathering import (
12
    find_user_config, gather_configuration)
13
from coalib.settings.Setting import glob_list
14
15
16
class DbusDocument(dbus.service.Object):
17
    interface = "org.coala_analyzer.v1"
18
19
    def __init__(self, doc_id, path=""):
20
        """
21
        Creates a new dbus object-path for every document that a
22
        DbusApplication wants coala to analyze. It stores the information
23
        (path) of the document and the config file to use when analyzing the
24
        given document.
25
26
        :param doc_id: An id for the document.
27
        :param path:   The path to the document.
28
        """
29
        dbus.service.Object.__init__(self)
30
31
        self.config_file = ""
32
        self.path = path
33
        self.doc_id = doc_id
34
35
    @dbus.service.method(interface,
36
                         in_signature="",
37
                         out_signature="s")
38
    def FindConfigFile(self):
39
        """
40
        This method uses the path of the document to identify a user config
41
        file for it
42
43
        :return: The config file path
44
        """
45
        if self.path == "":
46
            return ""
47
48
        self.config_file = find_user_config(self.path)
49
        return self.config_file
50
51
    @dbus.service.method(interface,
52
                         in_signature="s",
53
                         out_signature="s")
54
    def SetConfigFile(self, config_file):
55
        """
56
        This method sets the config file to use. It has to be an absolute path,
57
        as otherwise it is difficult to find it.
58
59
        :param config_file: The path fo the config file to use. This has to be
60
                            an absolute path
61
        :return:            The config path which has been used
62
        """
63
        self.config_file = config_file
64
        return self.config_file
65
66
    @dbus.service.method(interface,
67
                         in_signature="",
68
                         out_signature="s")
69
    def GetConfigFile(self):
70
        """
71
        This method gets the config file which is being used
72
73
        :return: The config path which is being used
74
        """
75
        return self.config_file
76
77
    # Signature explanation:
78
    # s -> string
79
    # b -> boolean
80
    # i -> integer (32bit)
81
    # a -> array (list of tuple in python)
82
    # () -> structure (or tuple in python)
83
    # a{ss} -> dictionary with string keys and string values
84
    @dbus.service.method(interface,
85
                         in_signature="",
86
                         out_signature="(iaa{ss}a(sbaa{ss}))")
87
    def Analyze(self):
88
        """
89
        This method analyzes the document and sends back the result
90
91
        :return: The output is structure which has 3 items:
92
                 -  The exitcode from the analysis.
93
                 -  List of logs from the analysis.
94
                 -  List of information about each section that contains:
95
96
                    -  The name of the section.
97
                    -  Boolean which is true if all bears in the section
98
                       executed successfully.
99
                    -  List of results where each result is a string
100
                       dictionary which contains:
101
                       id, origin, message, file, line_nr, severity
102
        """
103
        retval = []
104
        if self.path == "" or self.config_file == "":
105
            return retval
106
107
        args = ["--config=" + self.config_file]
108
109
        log_printer = ListLogPrinter()
110
        exitcode = 0
111
        try:
112
            yielded_results = False
113
            (sections,
114
             local_bears,
115
             global_bears,
116
             targets) = gather_configuration(fail_acquire_settings,
117
                                             log_printer,
118
                                             arg_list=args)
119
120
            for section_name in sections:
121
                section = sections[section_name]
122
123
                if not section.is_enabled(targets):
124
                    continue
125
126
                if any([fnmatch(self.path, file_pattern)
127
                        for file_pattern in glob_list(section["files"])]):
128
129
                    section["files"].value = self.path
130
                    # TODO: Integrate with caching
131
                    section_result = execute_section(
132
                        section=section,
133
                        global_bear_list=global_bears[section_name],
134
                        local_bear_list=local_bears[section_name],
135
                        print_results=lambda *args: True,
136
                        cache=None,
137
                        log_printer=log_printer)
138
                    yielded_results = yielded_results or section_result[0]
139
140
                    retval.append(
141
                        DbusDocument.results_to_dbus_struct(section_result,
142
                                                            section_name))
143
144
            if yielded_results:
145
                exitcode = 1
146
        except BaseException as exception:  # pylint: disable=broad-except
147
            exitcode = exitcode or get_exitcode(exception, log_printer)
148
149
        logs = [log.to_string_dict() for log in log_printer.logs]
150
        return (exitcode, logs, retval)
151
152
    @staticmethod
153
    def results_to_dbus_struct(section_result, section_name):
154
        """
155
        Converts the result tuple given by execute_section() - which has
156
        dictionaries and classes inside it - into a purely array based format
157
        as dbus protocol only allows arrays.
158
159
        :param section_result: The result tuple given by execute_section()
160
                               for a section
161
        :param section_name:   The name of the section
162
        :return:               The result for a section in the form of an
163
                               array which is sendable through dbus.
164
        """
165
        results_for_section = []
166
        for i in range(1, 3):  # Loop over bear types - local, global
167
168
            # Loop over every file affected for local bears
169
            # and every bear for global bears
170
            for key, value in section_result[i].items():
171
172
                # Loop over every result for a file
173
                results_for_section += [result.to_string_dict()
174
                                        for result in filter(
175
                        lambda x: not isinstance(x, HiddenResult),
176
                        value)]
177
178
        return [section_name, section_result[0], results_for_section]
179
180
    @property
181
    def path(self):
182
        return self._path
183
184
    @path.setter
185
    def path(self, new_path):
186
        if new_path:
187
            new_path = os.path.abspath(os.path.expanduser(new_path))
188
        self._path = new_path
189