timeit

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

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

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

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

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

Резултати

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

Код

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
def check_len(lines, length, d):
    for i in range(0, len(lines)):
        if len(lines[i]) > length:
            d[i+1] = d.get(i+1, [])
            s = 'line too long ({} > {})'.format(len(lines[i]), length)
            d[i+1].append(s)


def whitespaces(lines, d):
    for i in range(0, len(lines)):
        if line.endswith(' '):
            d[i+1] = d.get(i+1, [])
            d[i+1].append('trailing whitespace')


def is_line_logic(line):
    s = line.strip()
    if s == '':
        return False
    if s[0] == '#':
        return False
    return True


def line_indent(line):
    indent = 0
    for i in range(0, len(line)):
        if line[i] == ' ':
            indent += 1
        else:
            return indent


def indentation(lines, indent, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip()[-1] == ':':
            indentation = line_indent(lines[i])
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                ind = line_indent(lines[j])
                if ind <= indentation:
                    break
                diff = ind - indentation
                if diff != indent:
                    d[j+1] = d.get(j+1, [])
                    s = 'indentation is {} instead of {}'.format(diff,indent)
                    d[j+1].append(s)


def func_max_lines(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            indent = line_indent(lines[i])
            num = 0
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                ind = line_indent(lines[j])
                if ind <= indent:
                    break
                num += 1
            if num > number:
                d[i+1] = d.get(i+1, [])
                s = 'method with too many lines ({} > {})'.format(num, number)
                d[i+1].append(s)


def func_max_args(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            str = lines[i]
            j = i+1
            while ')' not in str and j < len(lines):
                str += lines[j]
                j += 1
            start = str.index('(')
            end = str.index(')')
            str = str[start:end]
            args = str.split(',')
            if len(args) > number:
                d[i+1] = d.get(i+1, [])
                s = 'too many arguments({} > {})'.format(len(args), number)
                d[i+1].append(s)
            
            
def methods_in_class(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('class '):
            indent = line_indent(lines[i])
            methods = 0
            for j in range(i+1, len(lines)):
                ind = line_indent(lines[j])
                if ind <= indent:
                    break
                if lines[j].strip().startswith('def '):
                    methods += 1
            if methods > number:
                d[i+1] = d.get(i+1, [])
                s = 'too many methods in class({} > {})'.format(methods, number)
                d[i+1].append(s)


def mult_expr(lines, d):
    for i in range(0, len(lines)):
        line = lines[i]
        spl = line.split('\'')
        for j in range(0, len(spl), 2):
            if ';' in spl[j]:
                d[i+1] = d.get(i+1, [])
                s = 'multiple expressions on the same line'
                d[i+1].append(s)
        spl = line.split('\"')
        for j in range(0, len(spl), 2):
            if ';' in spl[j]:
                d[i+1] = d.get(i+1, [])
                s = 'multiple expressions on the same line'
                d[i+1].append(s)


def nesting(lines, nesting, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            current = line_indent(lines[i])
            current_d = current
            curr = 0
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                dep = line_indent(lines[j])
                if dep <= current:
                    break
                if dep > current_d:
                    curr += 1
                    current_d = dep
                    if curr > nesting:
                        d[i+1] = d.get(i+1, [])
                        s = 'nesting too deep ({} > {})'.format(curr, nesting)
                        d[i+1].append(s)


def critic(code, line_length=79, forbid_semicolons=True, max_nesting=None,
           indentation_size=4, methods_per_class=None, max_arity=None,
           forbid_trailing_whitespace=True, max_lines_per_function=None):
    lines = code.split('\n')
    d = dict()
    if line_length:
        check_len(lines, line_length, d)
    if forbid_trailing_whitespace:
        whitespaces(lines, d)
    if indentation_size:
        indentation(line, indentation_size, d)
    if methods_per_class:
        methods_in_class(lines, methods_per_class, d)
    if max_lines_per_function:
        func_max_lines(lines, max_lines_per_function, d)
    if max_arity:
        func_max_args(lines, max_arity, d)
    if forbid_semicolons:
        mult_expr(lines, d)
    if max_nesting:
        nesting(lines, max_nesting, d)
    return d

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

EEEEEEEEEEE
======================================================================
ERROR: 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
NameError: name 'line' is not defined

======================================================================
ERROR: test_forbid_trailing_whitespace (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
NameError: name 'line' is not defined

======================================================================
ERROR: test_indentation (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
NameError: name 'line' is not defined

======================================================================
ERROR: test_line_too_long (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
NameError: name 'line' is not defined

======================================================================
ERROR: test_long_line_with_several_statements (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
NameError: name 'line' is not defined

======================================================================
ERROR: test_max_lines_per_function (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
NameError: name 'line' is not defined

======================================================================
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
NameError: name 'line' is not defined

======================================================================
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
NameError: name 'line' is not defined

======================================================================
ERROR: test_too_deep_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
NameError: name 'line' is not defined

======================================================================
ERROR: test_too_many_arguments (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
NameError: name 'line' is not defined

======================================================================
ERROR: test_two_statements_on_one_line (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
NameError: name 'line' is not defined

----------------------------------------------------------------------
Ran 11 tests in 0.083s

FAILED (errors=11)

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

Димо обнови решението на 18.05.2016 15:19 (преди над 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
def check_len(lines, length, d):
    for i in range(0, len(lines)):
        if len(lines[i]) > length:
            d[i+1] = d.get(i+1, [])
            s = 'line too long ({} > {})'.format(len(lines[i]), length)
            d[i+1].append(s)


def whitespaces(lines, d):
    for i in range(0, len(lines)):
        if line.endswith(' '):
            d[i+1] = d.get(i+1, [])
            d[i+1].append('trailing whitespace')


def is_line_logic(line):
    s = line.strip()
    if s == '':
        return False
    if s[0] == '#':
        return False
    return True


def line_indent(line):
    indent = 0
    for i in range(0, len(line)):
        if line[i] == ' ':
            indent += 1
        else:
            return indent


def indentation(lines, indent, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip()[-1] == ':':
            indentation = line_indent(lines[i])
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                ind = line_indent(lines[j])
                if ind <= indentation:
                    break
                diff = ind - indentation
                if diff != indent:
                    d[j+1] = d.get(j+1, [])
                    s = 'indentation is {} instead of {}'.format(diff,indent)
                    d[j+1].append(s)


def func_max_lines(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            indent = line_indent(lines[i])
            num = 0
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                ind = line_indent(lines[j])
                if ind <= indent:
                    break
                num += 1
            if num > number:
                d[i+1] = d.get(i+1, [])
                s = 'method with too many lines ({} > {})'.format(num, number)
                d[i+1].append(s)


def func_max_args(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            str = lines[i]
            j = i+1
            while ')' not in str and j < len(lines):
                str += lines[j]
                j += 1
            start = str.index('(')
            end = str.index(')')
            str = str[start:end]
            args = str.split(',')
            if len(args) > number:
                d[i+1] = d.get(i+1, [])
                s = 'too many arguments({} > {})'.format(len(args), number)
                d[i+1].append(s)
            
            
def methods_in_class(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('class '):
            indent = line_indent(lines[i])
            methods = 0
            for j in range(i+1, len(lines)):
                ind = line_indent(lines[j])
                if ind <= indent:
                    break
                if lines[j].strip().startswith('def '):
                    methods += 1
            if methods > number:
                d[i+1] = d.get(i+1, [])
                s = 'too many methods in class({} > {})'.format(methods, number)
                d[i+1].append(s)


def mult_expr(lines, d):
    for i in range(0, len(lines)):
        line = lines[i]
        spl = line.split('\'')
        for j in range(0, len(spl), 2):
            if ';' in spl[j]:
                d[i+1] = d.get(i+1, [])
                s = 'multiple expressions on the same line'
                d[i+1].append(s)
                return
        spl = line.split('\"')
        for j in range(0, len(spl), 2):
            if ';' in spl[j]:
                d[i+1] = d.get(i+1, [])
                s = 'multiple expressions on the same line'
                d[i+1].append(s)
                return


def critic(code, line_length=79, forbid_semicolons=True, max_nesting=None,
           indentation_size=4, methods_per_class=None, max_arity=None,
           forbid_trailing_whitespace=True, max_lines_per_function=None):
    lines = code.split('\n')
    d = dict()
    if line_length:
        check_len(lines, line_length, d)
    if forbid_trailing_whitespace:
        whitespaces(lines, d)
    if indentation_size:
        indentation(line, indentation_size, d)
    if methods_per_class:
        methods_in_class(lines, methods_per_class, d)
    if max_lines_per_function:
        func_max_lines(lines, max_lines_per_function, d)
    if max_arity:
        func_max_args(lines, max_arity, d)
    if forbid_semicolons:
        mult_expr(lines, d)
    return d

Димо обнови решението на 18.05.2016 16:33 (преди над 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
def check_len(lines, length, d):
    for i in range(0, len(lines)):
        if len(lines[i]) > length:
            d[i+1] = d.get(i+1, [])
            s = 'line too long ({} > {})'.format(len(lines[i]), length)
            d[i+1].append(s)


def whitespaces(lines, d):
    for i in range(0, len(lines)):
        if line.endswith(' '):
            d[i+1] = d.get(i+1, [])
            d[i+1].append('trailing whitespace')


def is_line_logic(line):
    s = line.strip()
    if s == '':
        return False
    if s[0] == '#':
        return False
    return True


def line_indent(line):
    indent = 0
    for i in range(0, len(line)):
        if line[i] == ' ':
            indent += 1
        else:
            return indent


def indentation(lines, indent, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip()[-1] == ':':
            indentation = line_indent(lines[i])
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                ind = line_indent(lines[j])
                if ind <= indentation:
                    break
                diff = ind - indentation
                if diff != indent:
                    d[j+1] = d.get(j+1, [])
                    s = 'indentation is {} instead of {}'.format(diff,indent)
                    d[j+1].append(s)


def func_max_lines(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            indent = line_indent(lines[i])
            num = 0
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                ind = line_indent(lines[j])
                if ind <= indent:
                    break
                num += 1
            if num > number:
                d[i+1] = d.get(i+1, [])
                s = 'method with too many lines ({} > {})'.format(num, number)
                d[i+1].append(s)


def func_max_args(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            str = lines[i]
            j = i+1
            while ')' not in str and j < len(lines):
                str += lines[j]
                j += 1
            start = str.index('(')
            end = str.index(')')
            str = str[start:end]
            args = str.split(',')
            if len(args) > number:
                d[i+1] = d.get(i+1, [])
                s = 'too many arguments({} > {})'.format(len(args), number)
                d[i+1].append(s)
            
            
def methods_in_class(lines, number, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('class '):
            indent = line_indent(lines[i])
            methods = 0
            for j in range(i+1, len(lines)):
                ind = line_indent(lines[j])
                if ind <= indent:
                    break
                if lines[j].strip().startswith('def '):
                    methods += 1
            if methods > number:
                d[i+1] = d.get(i+1, [])
                s = 'too many methods in class({} > {})'.format(methods, number)
                d[i+1].append(s)


def mult_expr(lines, d):
    for i in range(0, len(lines)):
        line = lines[i]
        spl = line.split('\'')
        for j in range(0, len(spl), 2):
            if ';' in spl[j]:
                d[i+1] = d.get(i+1, [])
                s = 'multiple expressions on the same line'
                d[i+1].append(s)
        spl = line.split('\"')
        for j in range(0, len(spl), 2):
            if ';' in spl[j]:
                d[i+1] = d.get(i+1, [])
                s = 'multiple expressions on the same line'
                d[i+1].append(s)


def nesting(lines, nesting, d):
    for i in range(0, len(lines)):
        if is_line_logic(lines[i]) and lines[i].strip().startswith('def '):
            current = line_indent(lines[i])
            current_d = current
            curr = 0
            for j in range(i+1, len(lines)):
                if not is_line_logic(lines[j]):
                    continue
                dep = line_indent(lines[j])
                if dep <= current:
                    break
                if dep > current_d:
                    curr += 1
                    current_d = dep
                    if curr > nesting:
                        d[i+1] = d.get(i+1, [])
                        s = 'nesting too deep ({} > {})'.format(curr, nesting)
                        d[i+1].append(s)


def critic(code, line_length=79, forbid_semicolons=True, max_nesting=None,
           indentation_size=4, methods_per_class=None, max_arity=None,
           forbid_trailing_whitespace=True, max_lines_per_function=None):
    lines = code.split('\n')
    d = dict()
    if line_length:
        check_len(lines, line_length, d)
    if forbid_trailing_whitespace:
        whitespaces(lines, d)
    if indentation_size:
        indentation(line, indentation_size, d)
    if methods_per_class:
        methods_in_class(lines, methods_per_class, d)
    if max_lines_per_function:
        func_max_lines(lines, max_lines_per_function, d)
    if max_arity:
        func_max_args(lines, max_arity, d)
    if forbid_semicolons:
        mult_expr(lines, d)
    if max_nesting:
        nesting(lines, max_nesting, d)
    return d