Failed Conditions
Pull Request — master (#1109)
by Abdeali
01:46
created

coalib.bearlib.abstractions.Lint._get_groupdict()   A

Complexity

Conditions 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
dl 0
loc 11
rs 9.4286
1
import subprocess
2
import tempfile
3
import re
4
import sys
5
6
from coalib.misc.Shell import escape_path_argument
7
from coalib.results.Result import Result
8
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
9
10
11
class Lint():
12
    """
13
    :param executable:   The executable to run the linter.
14
    :param arguments:    The arguments to supply to the linter, such
15
                         that the file name to be analyzed can be
16
                         appended to the end.
17
    :param output_regex: The regex which will match the output of the linter to
18
                         get results. Thie regex should give out the following
19
                         variables:
20
                          line - The line where the issue starts.
21
                          column - The column where the issue starts.
22
                          end_line - The line where the issue ends.
23
                          end_column - The column where the issue ends.
24
                          severity - The severity of the issue.
25
                          message - The message of the result.
26
    """
27
    executable = None
28
    arguments = ""
29
    output_regex = re.compile(r'(?P<line>\d+)\.(?P<column>\d+)\|'
30
                              r'(?P<severity>\d+): (?P<message>.*)')
31
    output_stream = "stdout"
32
33
    def lint(self, filename):
34
        """
35
        Takes a file and lints it using the linter variables defined apriori.
36
37
        :param filename: The name of the file to execute.
38
        """
39
        command = (self.executable + ' ' + self.arguments + ' '
40
                   + escape_path_argument(filename))
41
        stderr_file = tempfile.TemporaryFile()
42
        stdout_file = tempfile.TemporaryFile()
43
        process = subprocess.Popen(
44
            command,
45
            shell=True,
46
            stdout=stdout_file,
47
            stderr=stderr_file,
48
            universal_newlines=True)
49
        process.wait()
50
        if self.output_stream == "stdout":
51
            stdout_file.seek(0)
52
            output = stdout_file.read().decode(sys.stdout.encoding,
53
                                               errors="replace")
54
        elif self.output_stream == "stderr":
55
            stderr_file.seek(0)
56
            output = stderr_file.read().decode(sys.stdout.encoding,
57
                                               errors="replace")
58
        stdout_file.close()
59
        stderr_file.close()
60
        return self.process_output(output, filename)
61
62
    def process_output(self, output, filename):
63
        regex = self.output_regex
64
        if isinstance(regex, str):
65
            regex = regex % {"file_name": filename}
66
67
        for match in re.finditer(regex, output):
68
            yield self.match_to_result(match, filename)
69
70
    def _get_groupdict(self, match):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
71
        groups = match.groupdict()
72
        # Attempt to convert all values from string to int as regex only
73
        # matches strings.
74
        for key, value in groups.items():
75
            try:
76
                value = int(value)
77
                groups[key] = value
78
            except (TypeError, ValueError):
79
                pass
80
        return groups
81
82
    def match_to_result(self, match, filename):
83
        """
84
        Converts a regex match's groups into a result.
85
86
        :param match:    The match got from regex parsing.
87
        :param filename: The name of the file from which this match is got.
88
        """
89
        groups = self._get_groupdict(match)
90
91
        return Result.from_values(
92
            origin=self,
93
            message=groups.get("message", ""),
94
            file=filename,
95
            severity=groups.get("severity", RESULT_SEVERITY.NORMAL),
96
            line=groups.get("line"),
97
            column=groups.get("column", 0),
98
            end_line=groups.get("end_line", None),
99
            end_column=groups.get("end_column", None))
100