timeit

Програмиране с Python

Курс във Факултета по Математика и Информатика към СУ

Решение на Статичен анализ на python код от Георги Данков

Обратно към всички решения

Към профила на Георги Данков

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 10 успешни тест(а)
  • 1 неуспешни тест(а)

Код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import ast
import re
from collections import defaultdict


class FunctionCrawler(ast.NodeVisitor):
    def __init__(self, tree):
        self.__tree = ast.parse(tree)
        self.__functions_arguments = {}
        self.__lines_in_functions = {}
        self.__method_count = {}
        self.__nestings = {}
        self.__indentations = {}

    @property
    def max_arity(self):
        return self.__functions_arguments

    @property
    def lines_per_function(self):
        return self.__lines_in_functions

    @property
    def nestings(self):
        return self.__nestings

    @property
    def indentations(self):
        return self.__indentations

    @property
    def method_count(self):
        return self.__method_count

    def visit_Lambda(self, node):
        self.__functions_arguments[node.lineno] = len(node.args.args)

    def visit_FunctionDef(self, node):
        self._find_nestings(node)
        self._find_indentations(node)
        self.__functions_arguments[node.lineno] = len(node.args.args)
        self.__lines_in_functions[node.lineno] = FunctionCrawler.lines_count(
            node)

        self.generic_visit(node)

    def visit_ClassDef(self, node):
        self.__method_count[node.lineno] = sum(
            1 for stmn in node.body
            if isinstance(stmn, ast.FunctionDef))

        self.generic_visit(node)

    def _find_indentations(self, finc):
        for node in finc.body:
            lineno = node.lineno
            col_offset = node.col_offset

            if(lineno not in self.__indentations or
                    col_offset < self.__indentations[lineno]):
                self.__indentations[lineno] = col_offset

            if hasattr(node, 'body'):
                self._find_indentations(node)

    def _find_nestings(self, node, current_depth=0):
        current_depth += 1
        for statement in node.body:
            self.__nestings[statement.lineno] = current_depth

            if(not isinstance(statement, ast.FunctionDef) and
                    not isinstance(statement, ast.ClassDef) and
                    hasattr(statement, 'body')):
                self._find_nestings(statement, current_depth)

    def get_nestings(self, max_nesting):
        issues = {}
        for linenum, depth in self.nestings.items():
            if depth > max_nesting:
                issues[linenum] = 'nesting too deep ({} > {})'.format(
                    depth, max_nesting)
        return issues

    def get_wrong_indentations(self, indentation_size):
        nestings = self._find_all_nestings(self.__tree)
        indentations = self._find_all_indentations(self.__tree)

        issues = {}
        for linenum, nesting in nestings.items():
            if not indentations[linenum] == nesting * indentation_size:
                issues[linenum] = 'indentation is {} instead of {}'.format(
                    indentations[linenum], nesting * indentation_size)
        return issues

    def _find_all_indentations(self, tree, result={}):
        for node in tree.body:
            lineno = node.lineno
            col_offset = node.col_offset

            if(lineno not in result or
                    col_offset < result[lineno]):
                result[lineno] = col_offset

            if hasattr(node, 'body'):
                self._find_all_indentations(node)
        return result

    def _find_all_nestings(self, tree, current_depth=0, result={}):
        for node in tree.body:
            result[node.lineno] = current_depth
            if hasattr(node, 'body'):
                self._find_all_nestings(node, current_depth + 1, result)
        return result

    @staticmethod
    def lines_count(node):
        count = 0
        for statement in node.body:
            count += 1
            if(hasattr(statement, 'body') and not
                    isinstance(statement, ast.FunctionDef)):
                count += FunctionCrawler.lines_count(statement)
        return count


def critic(code, **rules):
    if not isinstance(code, str):
        raise ValueError(
            "First argument must be a string! Yours was {}".format(type(code)))

    line_length = rules.get("line_length", 79)
    forbid_semicolons = rules.get("forbid_semicolons", True)
    forbid_trailing_whitespace = rules.get("forbid_trailing_whitespace", True)

    issues_log = defaultdict(set)
    for linenum, line in enumerate(code.splitlines()):
        if len(line) > line_length:
            issues_log[linenum + 1].add('line too long ({} > {})'.format(
                len(line), line_length))

        if forbid_semicolons and ';' in re.sub(r'([\'"]).*?\1', "''", line):
            issues_log[linenum + 1].add(
                'multiple expressions on the same line')

        if forbid_trailing_whitespace and re.search(r'\s+$', line):
            issues_log[linenum + 1].add('trailing whitespace')

    crawler = FunctionCrawler(code)
    crawler.visit(ast.parse(code))
    indentation_size = rules.get("indentation_size", 4)
    indentations = crawler.get_wrong_indentations(indentation_size)
    for linenum, message in indentations.items():
            issues_log[linenum].add(message)

    max_nesting = rules.get("max_nesting", None)
    if max_nesting is not None:
        nestings = crawler.get_nestings(max_nesting)
        for linenum, message in nestings.items():
            issues_log[linenum].add(message)

    methods_per_class = rules.get("methods_per_class", None)
    max_arity = rules.get("max_arity", None)
    max_lines_per_function = rules.get("max_lines_per_function", None)

    if methods_per_class is not None:
        for linenum, method_count in crawler.method_count.items():
            if method_count > methods_per_class:
                issues_log[linenum].add(
                    'too many methods in class({} > {})'.format(
                        method_count,
                        methods_per_class))

    if max_arity is not None:
        for linenum, arg_count in crawler.max_arity.items():
            if arg_count > max_arity:
                issues_log[linenum].add(
                    'too many arguments({} > {})'.format(arg_count,
                                                         max_arity))

    if max_lines_per_function is not None:
        for linenum, lines_count in crawler.lines_per_function.items():
            if lines_count > max_lines_per_function:
                issues_log[linenum].add(
                    'method with too many lines ({} > {})'.format(
                        lines_count,
                        max_lines_per_function))
    return issues_log

Лог от изпълнението

......F....
======================================================================
FAIL: test_multiple_issues_all_over_the_place (test.TestCritic)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/data/rails/pyfmi-2016/releases/20160307095126/lib/language/python/runner.py", line 67, in thread
    raise result
AssertionError: Items in the first set but not the second:
'method with too many lines (6 > 5)'

----------------------------------------------------------------------
Ran 11 tests in 0.107s

FAILED (failures=1)

История (3 версии и 0 коментара)

Георги обнови решението на 16.05.2016 11:54 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import ast
import re
from collections import defaultdict


class NestingFinder:
    def __init__(self, code):
        self.__tree = ast.parse(code)
        self.__nestings = {}
        self.__identitations = {}

    @property
    def nestings(self):
        if not self.__nestings:
            self._find_nestings(self.__tree)
        return self.__nestings

    @property
    def identitations(self):
        if not self.__identitations:
            self._find_identitations(self.__tree)
        return self.__identitations

    def _find_identitations(self, tree):
        for node in tree.body:
            lineno = node.lineno
            col_offset = node.col_offset

            if(lineno not in self.__identitations or
                    col_offset < self.__identitations[lineno]):
                self.__identitations[lineno] = col_offset

            if hasattr(node, 'body'):
                self._find_identitations(node)

    def _find_nestings(self, tree, current_depth=0):
        for node in tree.body:
            self.__nestings[node.lineno] = current_depth
            if hasattr(node, 'body'):
                self._find_nestings(node, current_depth + 1)

    def get_nestings(self, max_nesting):
        issues = {}
        for linenum, depth in self.nestings.items():
            if depth > max_nesting:
                issues[linenum] = 'nesting too deep ({} > {})'.format(
                    depth, max_nesting)
        return issues

    def get_wrong_identitations(self, identitation_size):
        nestings = self.nestings
        identations = self.identitations

        issues = {}
        for linenum, identation in identations.items():
            if not identation == identitation_size * nestings[linenum]:
                issues[linenum] = 'indentation is {} instead of {}'.format(
                    identation, identitation_size * nestings[linenum])
        return issues


class FunctionCrawler(ast.NodeVisitor):
    def __init__(self):
        self.__functions_arguments = {}
        self.__lines_in_functions = {}
        self.__method_count = {}

    @property
    def max_arity(self):
        return self.__functions_arguments

    @property
    def lines_per_function(self):
        return self.__lines_in_functions

    @property
    def method_count(self):
        return self.__method_count

    def visit_FunctionDef(self, node):
        # + kwargs etc?
        self.__functions_arguments[node.lineno] = len(node.args.args)
        self.__lines_in_functions[node.lineno] = FunctionCrawler.lines_count(
            node)

        self.generic_visit(node)

    def visit_ClassDef(self, node):
        self.__method_count[node.lineno] = sum(
            1 for stmn in node.body
            if isinstance(stmn, ast.FunctionDef))

        self.generic_visit(node)

    @staticmethod
    def lines_count(node):
        count = 0
        for statement in node.body:
            count += 1
            if hasattr(statement, 'body'):
                count += FunctionCrawler.lines_count(statement)
        return count


def critic(code, **rules):
    if not isinstance(code, str):
        raise ValueError(
            "First argument must be a string! Yours was {}".format(type(code)))

    line_length = rules.get("line_length", 79)
    forbid_semicolons = rules.get("forbid_semicolons", True)
    forbid_trailing_whitespace = rules.get("forbid_trailing_whitespace", True)

    issues_log = defaultdict(set)
    for linenum, line in enumerate(code.splitlines()):
        if len(line) > line_length:
            issues_log[linenum + 1].add('line too long ({} > {})'.format(
                len(line), line_length))

        if forbid_semicolons and ';' in re.sub(r'([\'"]).*?\1', "''", line):
            issues_log[linenum + 1].add(
                'multiple expressions on the same line')

        if forbid_trailing_whitespace and re.search(r'\s+$', line):
            issues_log[linenum + 1].add('trailing whitespace')

    indentation_size = rules.get("indentation_size", 4)
    finder = NestingFinder(code)
    indentations = finder.get_wrong_identitations(indentation_size)
    for linenum, message in indentations.items():
            issues_log[linenum].add(message)

    max_nesting = rules.get("max_nesting", None)
    if max_nesting is not None:
        nestings = finder.get_nestings(max_nesting)
        for linenum, message in nestings.items():
            issues_log[linenum].add(message)

    methods_per_class = rules.get("methods_per_class", None)
    max_arity = rules.get("max_arity", None)
    max_lines_per_function = rules.get("max_lines_per_function", None)

    if any([methods_per_class, max_arity, max_lines_per_function]):
        check_functions(code, methods_per_class, max_arity,
                        max_lines_per_function, issues_log)
    return issues_log


def check_functions(code, max_methods_per_class, max_arity,
                    max_lines_per_function, issues_log):
    crawler = FunctionCrawler()
    crawler.visit(code)

    if max_methods_per_class:
        for linenum, method_count in crawler.method_count():
            if method_count > max_methods_per_class:
                issues_log[linenum].add(
                    'too many methods in class({} > {})'.format(
                        method_count,
                        max_methods_per_class))

    if max_arity:
        for linenum, arg_count in crawler.max_arity.items():
            if arg_count > max_arity:
                issues_log[linenum].add(
                    'too many arguments({} > {})'.format(arg_count,
                                                         max_arity))

    if max_lines_per_function:
        for linenum, lines_count in crawler.lines_per_function():
            if lines_count > max_lines_per_function:
                issues_log[linenum].add(
                    'method with too many lines ({} > {})'.format(
                        lines_count,
                        max_lines_per_function))

Георги обнови решението на 18.05.2016 01:02 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import ast
import re
from collections import defaultdict


class FunctionCrawler(ast.NodeVisitor):
    def __init__(self):
        self.__functions_arguments = {}
        self.__lines_in_functions = {}
        self.__method_count = {}
        self.__nestings = {}
        self.__indentations = {}

    @property
    def max_arity(self):
        return self.__functions_arguments

    @property
    def lines_per_function(self):
        return self.__lines_in_functions

    @property
    def nestings(self):
        return self.__nestings

    @property
    def indentations(self):
        return self.__indentations

    @property
    def method_count(self):
        return self.__method_count

    def _find_indentations(self, tree):
        for node in tree.body:
            lineno = node.lineno
            col_offset = node.col_offset

            if(lineno not in self.__indentations or
                    col_offset < self.__indentations[lineno]):
                self.__indentations[lineno] = col_offset

            if hasattr(node, 'body'):
                self._find_indentations(node)

    def visit_FunctionDef(self, node):
        self._find_nestings(node)
        self._find_indentations(node)
        self.__functions_arguments[node.lineno] = len(node.args.args)
        self.__lines_in_functions[node.lineno] = FunctionCrawler.lines_count(
            node)

        self.generic_visit(node)

    def _find_nestings(self, node, current_depth=0):
        current_depth += 1
        for statement in node.body:
            self.__nestings[statement.lineno] = current_depth

            if(not isinstance(statement, ast.FunctionDef) and
                    not isinstance(statement, ast.ClassDef) and
                    hasattr(statement, 'body')):
                self._find_nestings(statement, current_depth)

    def visit_ClassDef(self, node):
        self.__method_count[node.lineno] = sum(
            1 for stmn in node.body
            if isinstance(stmn, ast.FunctionDef))

        self.generic_visit(node)

    def get_nestings(self, max_nesting):
        issues = {}
        for linenum, depth in self.nestings.items():
            if depth > max_nesting:
                issues[linenum] = 'nesting too deep ({} > {})'.format(
                    depth, max_nesting)
        return issues

    def get_wrong_indentations(self, indentation_size):
        nestings = self.nestings
        indentations = self.indentations

        issues = {}
        for linenum, indentation in indentations.items():
            if not indentation == indentation_size * nestings[linenum]:
                issues[linenum] = 'indentation is {} instead of {}'.format(
                    indentation, indentation_size * nestings[linenum])
        return issues

    @staticmethod
    def lines_count(node):
        count = 0
        for statement in node.body:
            count += 1
        return count


def critic(code, **rules):
    if not isinstance(code, str):
        raise ValueError(
            "First argument must be a string! Yours was {}".format(type(code)))

    line_length = rules.get("line_length", 79)
    forbid_semicolons = rules.get("forbid_semicolons", True)
    forbid_trailing_whitespace = rules.get("forbid_trailing_whitespace", True)

    issues_log = defaultdict(set)
    for linenum, line in enumerate(code.splitlines()):
        if len(line) > line_length:
            issues_log[linenum + 1].add('line too long ({} > {})'.format(
                len(line), line_length))

        if forbid_semicolons and ';' in re.sub(r'([\'"]).*?\1', "''", line):
            issues_log[linenum + 1].add(
                'multiple expressions on the same line')

        if forbid_trailing_whitespace and re.search(r'\s+$', line):
            issues_log[linenum + 1].add('trailing whitespace')

    crawler = FunctionCrawler()
    crawler.visit(ast.parse(code))
    indentation_size = rules.get("indentation_size", 4)
    indentations = crawler.get_wrong_indentations(indentation_size)
    for linenum, message in indentations.items():
            issues_log[linenum].add(message)

    max_nesting = rules.get("max_nesting", None)
    if max_nesting is not None:
        nestings = crawler.get_nestings(max_nesting)
        for linenum, message in nestings.items():
            issues_log[linenum].add(message)

    methods_per_class = rules.get("methods_per_class", None)
    max_arity = rules.get("max_arity", None)
    max_lines_per_function = rules.get("max_lines_per_function", None)

    if methods_per_class:
        for linenum, method_count in crawler.method_count():
            if method_count > methods_per_class:
                issues_log[linenum].add(
                    'too many methods in class({} > {})'.format(
                        method_count,
                        methods_per_class))

    if max_arity:
        for linenum, arg_count in crawler.max_arity.items():
            if arg_count > max_arity:
                issues_log[linenum].add(
                    'too many arguments({} > {})'.format(arg_count,
                                                         max_arity))

    if max_lines_per_function:
        for linenum, lines_count in crawler.lines_per_function():
            if lines_count > max_lines_per_function:
                issues_log[linenum].add(
                    'method with too many lines ({} > {})'.format(
                        lines_count,
                        max_lines_per_function))

    return issues_log

Георги обнови решението на 18.05.2016 11:59 (преди над 1 година)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import ast
import re
from collections import defaultdict


class FunctionCrawler(ast.NodeVisitor):
    def __init__(self, tree):
        self.__tree = ast.parse(tree)
        self.__functions_arguments = {}
        self.__lines_in_functions = {}
        self.__method_count = {}
        self.__nestings = {}
        self.__indentations = {}

    @property
    def max_arity(self):
        return self.__functions_arguments

    @property
    def lines_per_function(self):
        return self.__lines_in_functions

    @property
    def nestings(self):
        return self.__nestings

    @property
    def indentations(self):
        return self.__indentations

    @property
    def method_count(self):
        return self.__method_count

    def visit_Lambda(self, node):
        self.__functions_arguments[node.lineno] = len(node.args.args)

    def visit_FunctionDef(self, node):
        self._find_nestings(node)
        self._find_indentations(node)
        self.__functions_arguments[node.lineno] = len(node.args.args)
        self.__lines_in_functions[node.lineno] = FunctionCrawler.lines_count(
            node)

        self.generic_visit(node)

    def visit_ClassDef(self, node):
        self.__method_count[node.lineno] = sum(
            1 for stmn in node.body
            if isinstance(stmn, ast.FunctionDef))

        self.generic_visit(node)

    def _find_indentations(self, finc):
        for node in finc.body:
            lineno = node.lineno
            col_offset = node.col_offset

            if(lineno not in self.__indentations or
                    col_offset < self.__indentations[lineno]):
                self.__indentations[lineno] = col_offset

            if hasattr(node, 'body'):
                self._find_indentations(node)

    def _find_nestings(self, node, current_depth=0):
        current_depth += 1
        for statement in node.body:
            self.__nestings[statement.lineno] = current_depth

            if(not isinstance(statement, ast.FunctionDef) and
                    not isinstance(statement, ast.ClassDef) and
                    hasattr(statement, 'body')):
                self._find_nestings(statement, current_depth)

    def get_nestings(self, max_nesting):
        issues = {}
        for linenum, depth in self.nestings.items():
            if depth > max_nesting:
                issues[linenum] = 'nesting too deep ({} > {})'.format(
                    depth, max_nesting)
        return issues

    def get_wrong_indentations(self, indentation_size):
        nestings = self._find_all_nestings(self.__tree)
        indentations = self._find_all_indentations(self.__tree)

        issues = {}
        for linenum, nesting in nestings.items():
            if not indentations[linenum] == nesting * indentation_size:
                issues[linenum] = 'indentation is {} instead of {}'.format(
                    indentations[linenum], nesting * indentation_size)
        return issues

    def _find_all_indentations(self, tree, result={}):
        for node in tree.body:
            lineno = node.lineno
            col_offset = node.col_offset

            if(lineno not in result or
                    col_offset < result[lineno]):
                result[lineno] = col_offset

            if hasattr(node, 'body'):
                self._find_all_indentations(node)
        return result

    def _find_all_nestings(self, tree, current_depth=0, result={}):
        for node in tree.body:
            result[node.lineno] = current_depth
            if hasattr(node, 'body'):
                self._find_all_nestings(node, current_depth + 1, result)
        return result

    @staticmethod
    def lines_count(node):
        count = 0
        for statement in node.body:
            count += 1
            if(hasattr(statement, 'body') and not
                    isinstance(statement, ast.FunctionDef)):
                count += FunctionCrawler.lines_count(statement)
        return count


def critic(code, **rules):
    if not isinstance(code, str):
        raise ValueError(
            "First argument must be a string! Yours was {}".format(type(code)))

    line_length = rules.get("line_length", 79)
    forbid_semicolons = rules.get("forbid_semicolons", True)
    forbid_trailing_whitespace = rules.get("forbid_trailing_whitespace", True)

    issues_log = defaultdict(set)
    for linenum, line in enumerate(code.splitlines()):
        if len(line) > line_length:
            issues_log[linenum + 1].add('line too long ({} > {})'.format(
                len(line), line_length))

        if forbid_semicolons and ';' in re.sub(r'([\'"]).*?\1', "''", line):
            issues_log[linenum + 1].add(
                'multiple expressions on the same line')

        if forbid_trailing_whitespace and re.search(r'\s+$', line):
            issues_log[linenum + 1].add('trailing whitespace')

    crawler = FunctionCrawler(code)
    crawler.visit(ast.parse(code))
    indentation_size = rules.get("indentation_size", 4)
    indentations = crawler.get_wrong_indentations(indentation_size)
    for linenum, message in indentations.items():
            issues_log[linenum].add(message)

    max_nesting = rules.get("max_nesting", None)
    if max_nesting is not None:
        nestings = crawler.get_nestings(max_nesting)
        for linenum, message in nestings.items():
            issues_log[linenum].add(message)

    methods_per_class = rules.get("methods_per_class", None)
    max_arity = rules.get("max_arity", None)
    max_lines_per_function = rules.get("max_lines_per_function", None)

    if methods_per_class is not None:
        for linenum, method_count in crawler.method_count.items():
            if method_count > methods_per_class:
                issues_log[linenum].add(
                    'too many methods in class({} > {})'.format(
                        method_count,
                        methods_per_class))

    if max_arity is not None:
        for linenum, arg_count in crawler.max_arity.items():
            if arg_count > max_arity:
                issues_log[linenum].add(
                    'too many arguments({} > {})'.format(arg_count,
                                                         max_arity))

    if max_lines_per_function is not None:
        for linenum, lines_count in crawler.lines_per_function.items():
            if lines_count > max_lines_per_function:
                issues_log[linenum].add(
                    'method with too many lines ({} > {})'.format(
                        lines_count,
                        max_lines_per_function))
    return issues_log