timeit

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

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

Решение на Статичен анализ на python код от Яница Велевска

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

Към профила на Яница Велевска

Резултати

  • 7 точки от тестове
  • 0 бонус точки
  • 7 точки общо
  • 8 успешни тест(а)
  • 3 неуспешни тест(а)

Код

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
import ast
from collections import defaultdict


def remove_coments(code):
    new = []
    for line in code:
        if '#' in line:
            line = line.partition('#')[0]
            if not len(line) == 0:
                new.append(line)
        else:
            new.append(line)
    return new


def line_length(code, n):
    l = code.splitlines()
    l = remove_coments(l)
    err = {}
    for a in l:
        if len(a) > n:
            err[l.index(a) + 1] = len(a)
    return err


def forbid_semicolons(code):
    l = code.splitlines()
    l = remove_coments(l)
    err = []
    for a in l:
        if ';' in a:
            err.append(l.index(a) + 1)
    return err


def forbid_trailing_whitespace(code):
    l = code.splitlines()
    l = remove_coments(l)
    err = []
    for a in l:
        if a[len(a)-1].isspace():
            err.append(l.index(a) + 1)
    return err


def max_nesting(code, n, ind):
    l = code.splitlines()
    l = remove_coments(l)
    err = {}
    for a in l:
        count = 0
        for b in a:
            if b.isspace():
                count = count + 1
            else:
                break
        if count / ind > n:
            err[l.index(a) + 1] = int(count / ind)
    return err


def indentation_size(code, n):
    l = code.splitlines()
    l = remove_coments(l)
    err = {}
    for a in l:
        count = 0
        for b in a:
            if b.isspace():
                count = count + 1
            else:
                break
        if count % n != 0:
            err[l.index(a) + 1] = n + count % n
    return err


def max_arity(code, n):
    tree = ast.parse(code)
    err = {}
    for node in ast.walk(tree):
        if node.__class__ is ast.FunctionDef:
            if len(node.args.args) > n:
                err[node.lineno] = len(node.args.args)
    return err


def f(tree, c):
    if not 'body' in tree.__dict__:
        return c
    else:
        for node in tree.body:
            c = f(node, c + 1)
    return c


def max_lines_per_function(code, n):
    tree = ast.parse(code)
    err = {}
    for node in ast.walk(tree):
        if node.__class__ is ast.FunctionDef:
            counter = f(node, 0)
            if counter > n:
                err[node.lineno] = counter
    return err


def methods_per_class(code, n):
    tree = ast.parse(code)
    err = []
    for node in ast.walk(tree):
        if node.__class__ is ast.ClassDef:
            if len(node.body) > n:
                err[node.lineno] = len(node.body)
    return err


def critic(code, **rules):
    res = defaultdict(list)
    if 'line_length' in rules:
        allowed = rules['line_length']
    else:
        allowed = 79
    err = line_length(code, allowed)
    for line, actual in err.items():
        res[line].append('line too long ({} > {})'.format(actual, allowed))
    err = []
    if 'forbid_semicolons' in rules and rules['forbid_semicolons'] is False:
        pass
    else:
        err = forbid_semicolons(code)
    for line in err:
        res[line].append('multiple expressions on the same line')
    err = {}
    ind = 4
    if 'indentation_size' in rules:
        ind = rules['indentation_size']
    if 'max_nesting' in rules and not rules['max_nesting'] is None:
        err = max_nesting(code, rules['max_nesting'], ind)
    for line, actual in err.items():
        s = 'nesting too deep ({} > {})'.format(actual, rules['max_nesting'])
        res[line].append(s)
    err = {}
    err = indentation_size(code, ind)
    for line, actual in err.items():
        res[line].append('indentation is {} instead of {}'.format(actual, ind))
    err = {}
    if 'methods_per_class' in rules and not rules['methods_per_class'] is None:
        meth = rules['methods_per_class']
        err = methods_per_class(code, meth)
    for line, actual in err.items():
        s = 'too many methods in class({} > {})'.format(actual, meth)
        res[line].append(s)
    err = {}
    if 'max_arity' in rules and not rules['max_arity'] is None:
        err = max_arity(code, rules['max_arity'])
    for line, actual in err.items():
        s = 'too many arguments({} > {})'.format(actual, rules['max_arity'])
        res[line].append(s)
    err = []
    s = 'forbid_trailing_whitespace'
    if s in rules and rules[s] is False:
        pass
    else:
        err = forbid_trailing_whitespace(code)
    for line in err:
        res[line].append('trailing whitespace')
    err = {}
    s = 'max_lines_per_function'
    if s in rules and not rules[s] is None:
        err = max_lines_per_function(code, rules['max_lines_per_function'])
    for line, actual in err.items():
        max_l = rules['max_lines_per_function']
        s = 'method with too many lines ({} > {})'.format(actual, max_l)
        res[line].append(s)
    return dict(res)

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

F.....EE...
======================================================================
ERROR: 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
IndexError: string index out of range

======================================================================
ERROR: test_no_issues (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
IndexError: string index out of range

======================================================================
FAIL: test_dict_nesting (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: 2 != 0

----------------------------------------------------------------------
Ran 11 tests in 0.086s

FAILED (failures=1, errors=2)

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

Яница обнови решението на 17.05.2016 21:44 (преди над 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
import ast
from collections import defaultdict


def remove_coments(code):
    new = []
    for line in code:
        if '#' in line:
            line = line.partition('#')[0]
            if not len(line) == 0:
                new.append(line)
        else:
            new.append(line)
    return new


def line_length(code, n):
    l = code.splitlines()
    l = remove_coments(l)
    err = {}
    for a in l:
        if len(a) > n:
            err[l.index(a) + 1] = len(a)
    return err


def forbid_semicolons(code):
    l = code.splitlines()
    l = remove_coments(l)
    err = []
    for a in l:
        if ';' in a:
            err.append(l.index(a) + 1)
    return err


def forbid_trailing_whitespace(code):
    l = code.splitlines()
    l = remove_coments(l)
    err = []
    for a in l:
        if a[len(a)-1].isspace():
            err.append(l.index(a) + 1)
    return err


def max_nesting(code, n, ind):
    l = code.splitlines()
    l = remove_coments(l)
    err = {}
    for a in l:
        count = 0
        for b in a:
            if b.isspace():
                count = count + 1
            else:
                break
        if count / ind > n:
            err[l.index(a) + 1] = int(count / ind)
    return err


def indentation_size(code, n):
    l = code.splitlines()
    l = remove_coments(l)
    err = {}
    for a in l:
        count = 0
        for b in a:
            if b.isspace():
                count = count + 1
            else:
                break
        if count % n != 0:
            err[l.index(a) + 1] = n + count % n
    return err


def max_arity(code, n):
    tree = ast.parse(code)
    err = {}
    for node in ast.walk(tree):
        if node.__class__ is ast.FunctionDef:
            if len(node.args.args) > n:
                err[node.lineno] = len(node.args.args)
    return err


def f(tree, c):
    if not 'body' in tree.__dict__:
        return c
    else:
        for node in tree.body:
            c = f(node, c + 1)
    return c


def max_lines_per_function(code, n):
    tree = ast.parse(code)
    err = {}
    for node in ast.walk(tree):
        if node.__class__ is ast.FunctionDef:
            counter = f(node, 0)
            if counter > n:
                err[node.lineno] = counter
    return err


def methods_per_class(code, n):
    tree = ast.parse(code)
    err = []
    for node in ast.walk(tree):
        if node.__class__ is ast.ClassDef:
            if len(node.body) > n:
                err[node.lineno] = len(node.body)
    return err


def critic(code, **rules):
    res = defaultdict(list)
    if 'line_length' in rules:
        allowed = rules['line_length']
    else:
        allowed = 79
    err = line_length(code, allowed)
    for line, actual in err.items():
        res[line].append('line too long ({} > {})'.format(actual, allowed))
    err = []
    if 'forbid_semicolons' in rules and rules['forbid_semicolons'] is False:
        pass
    else:
        err = forbid_semicolons(code)
    for line in err:
        res[line].append('multiple expressions on the same line')
    err = {}
    ind = 4
    if 'indentation_size' in rules:
        ind = rules['indentation_size']
    if 'max_nesting' in rules and not rules['max_nesting'] is None:
        err = max_nesting(code, rules['max_nesting'], ind)
    for line, actual in err.items():
        s = 'nesting too deep ({} > {})'.format(actual, rules['max_nesting'])
        res[line].append(s)
    err = {}
    err = indentation_size(code, ind)
    for line, actual in err.items():
        res[line].append('indentation is {} instead of {}'.format(actual, ind))
    err = {}
    if 'methods_per_class' in rules and not rules['methods_per_class'] is None:
        meth = rules['methods_per_class']
        err = methods_per_class(code, meth)
    for line, actual in err.items():
        s = 'too many methods in class({} > {})'.format(actual, meth)
        res[line].append(s)
    err = {}
    if 'max_arity' in rules and not rules['max_arity'] is None:
        err = max_arity(code, rules['max_arity'])
    for line, actual in err.items():
        s = 'too many arguments({} > {})'.format(actual, rules['max_arity'])
        res[line].append(s)
    err = []
    s = 'forbid_trailing_whitespace'
    if s in rules and rules[s] is False:
        pass
    else:
        err = forbid_trailing_whitespace(code)
    for line in err:
        res[line].append('trailing whitespace')
    err = {}
    s = 'max_lines_per_function'
    if s in rules and not rules[s] is None:
        err = max_lines_per_function(code, rules['max_lines_per_function'])
    for line, actual in err.items():
        max_l = rules['max_lines_per_function']
        s = 'method with too many lines ({} > {})'.format(actual, max_l)
        res[line].append(s)
    return dict(res)