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


class Problem:
    def __init__(self, row, msg):
        self.row = row
        self.msg = msg
    def __repr__(self):
        return str(self.row) + "  " + self.msg


def critic(code, **rules):
    result = defaultdict(list)
    functions = [line_length, forbid_semicolons, max_arity,
                methods_per_class, forbid_trailing_whitespace, max_lines_per_function, max_nesting]
    
    for f in functions:
        problems = f(code, rules[f.__name__])
        for p in problems:
            result[p.row].append(p.msg)
            
    return result


def line_length(code, allowed_length):
    lines = code.splitlines()
    problems = []
    for row, line in enumerate(lines):
        actual_length=len(line)
        if actual_length > allowed_length:
            msg = "line too long ({0} > {1})".format(actual_length, allowed_length)
            problems.append(Problem(row+1, msg));
    return problems
    
    
def forbid_semicolons(code, forbid):
    problems = []
    if forbid:
        lines = code.splitlines()
        for row, line in enumerate(lines):
            if line.find(';') != -1: # todo: if ; is not in a string!! (" alba; blala" is not a problem)
                msg = "multiple expressions on the same line"
                problems.append(Problem(row+1, msg));
    return problems
        
        
def max_arity(code, max_args):
    problems = []
    if (max_args != None):
        tree = ast.parse(code)
        for node in ast.walk(tree):
            if isinstance(node, ast.FunctionDef):
                arity = len(node.args.args)
                if (arity > max_args):
                    msg = 'too many arguments({0} > {1})'.format(arity, max_args)
                    problems.append(Problem(node.lineno, msg));
    return problems
        
        
def methods_per_class(code, max_methods):
    problems = []
    if max_methods != None:
        tree = ast.parse(code)
        classes = [node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
        for c in classes:
            methods = len([node for node in ast.walk(c) if isinstance(node, ast.FunctionDef)])
            if (methods > max_methods):
                msg = 'too many methods in class({0} > {1})'.format(methods, max_methods)
                problems.append(Problem(c.lineno, msg))
    return problems


def forbid_trailing_whitespace(code, forbid):
    problems = []
    if forbid:
        new_line_indexes = [i for i, letter in enumerate(code) if letter == "\n"]
        for row, i in enumerate(new_line_indexes):
            if code[i-1] == ' ':
                msg = 'trailing whitespace'
                problems.append(Problem(row+1, msg));
    return problems
    
 
def find_last_deepest(node):
    try:
        child = node.body[-1]
        return find_last_deepest(child)
    except AttributeError:
        return node

 
def max_lines_per_function(code, max_lines):
    problems = []
    tree = ast.parse(code)
    functions = [node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef)]
    for f in functions:
        last = find_last_deepest(f.body[-1])
        f_lines = last.lineno - f.lineno
        if f_lines > max_lines:
            msg = 'method with too many lines ({0} > {1})'.format(f_lines, max_lines)
            problems.append(Problem(f.lineno, msg))
    return problems
    
    
def find_nesting(node, deep, crnt_max, row):
    try:
        for child in node.body:
            d, r = find_nesting(child, deep+1, crnt_max, row)
            if (d > crnt_max):
                crnt_max = d
                row = r
        return (crnt_max, row)
    except AttributeError:
        return deep, node.lineno


def max_nesting(code, allowed_nesting):
    problems = []
    root = ast.parse(code)
    max_nesting, row = find_nesting(root, 0, 0, 0)
    print(max_nesting, row)
    if (max_nesting > allowed_nesting):
         msg = "nesting too deep ({0} > {1})".format(max_nesting, allowed_nesting)
         problems.append(Problem(row, msg))
    return problems

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

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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

======================================================================
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
KeyError: 'line_length'

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

FAILED (errors=11)

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

Христо обнови решението на 17.05.2016 22:25 (преди над 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
import ast;
from collections import defaultdict;


class Problem:
        def __init__(self, row, msg):
                self.row = row
                self.msg = msg
        def __repr__(self):
                return str(self.row) + "  " + self.msg


def critic(code, **rules):
        result = defaultdict(list)
        functions = [line_length, forbid_semicolons, max_arity, methods_per_class, forbid_trailing_whitespace]
        
        for f in functions:
                problems = f(code, rules[f.__name__])
                for p in problems:
                        result[p.row].append(p.msg)
                        
        return result


def line_length(code, allowed_length):
        lines = code.splitlines()
        problems = []
        for row, line in enumerate(lines):
                actual_length=len(line)
                if actual_length > allowed_length:
                        msg = "line too long ({0} > {1})".format(actual_length, allowed_length)
                        problems.append(Problem(row+1, msg));
        return problems
        
        
def forbid_semicolons(code, forbid):
        problems = []
        if forbid:
                lines = code.splitlines()
                for row, line in enumerate(lines):
                        if line.find(';') != -1: # todo: if ; is not in a string!! (" alba; blala" is not a problem)
                                msg = "multiple expressions on the same line"
                                problems.append(Problem(row+1, msg));
        return problems
                
                
def max_arity(code, max_args):
        problems = []
        if (max_args != None):
                tree = ast.parse(code)
                for node in ast.walk(tree):
                        if isinstance(node, ast.FunctionDef):
                                arity = len(node.args.args)
                                if (arity > max_args):
                                        msg = 'too many arguments({0} > {1})'.format(arity, max_args)
                                        problems.append(Problem(node.lineno, msg));
        return problems
                
                
def methods_per_class(code, max_methods):
        problems = []
        if max_methods != None:
                tree = ast.parse(code)
                classes = [node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
                for c in classes:
                        methods = len([node for node in ast.walk(c) if isinstance(node, ast.FunctionDef)])
                        if (methods > max_methods):
                                msg = 'too many methods in class({0} > {1})'.format(methods, max_methods)
                                problems.append(Problem(c.lineno, msg))
        return problems


def forbid_trailing_whitespace(code, forbid):
        problems = []
        if forbid:
                new_line_indexes = [i for i, letter in enumerate(code) if letter == "\n"]
                for row, i in enumerate(new_line_indexes):
                        if code[i-1] == ' ':
                                msg = 'trailing whitespace'
                                problems.append(Problem(row+1, msg));
        return problems

Христо обнови решението на 17.05.2016 22:28 (преди над 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
import ast;
from collections import defaultdict;


class Problem:
    def __init__(self, row, msg):
        self.row = row
        self.msg = msg
    def __repr__(self):
        return str(self.row) + "  " + self.msg


def critic(code, **rules):
    result = defaultdict(list)
    functions = [line_length, forbid_semicolons, max_arity, methods_per_class, forbid_trailing_whitespace]
    
    for f in functions:
        problems = f(code, rules[f.__name__])
        for p in problems:
            result[p.row].append(p.msg)
            
    return result


def line_length(code, allowed_length):
    lines = code.splitlines()
    problems = []
    for row, line in enumerate(lines):
        actual_length=len(line)
        if actual_length > allowed_length:
            msg = "line too long ({0} > {1})".format(actual_length, allowed_length)
            problems.append(Problem(row+1, msg));
    return problems
    
    
def forbid_semicolons(code, forbid):
    problems = []
    if forbid:
        lines = code.splitlines()
        for row, line in enumerate(lines):
            if line.find(';') != -1: # todo: if ; is not in a string!! (" alba; blala" is not a problem)
                msg = "multiple expressions on the same line"
                problems.append(Problem(row+1, msg));
    return problems
        
        
def max_arity(code, max_args):
    problems = []
    if (max_args != None):
        tree = ast.parse(code)
        for node in ast.walk(tree):
            if isinstance(node, ast.FunctionDef):
                arity = len(node.args.args)
                if (arity > max_args):
                    msg = 'too many arguments({0} > {1})'.format(arity, max_args)
                    problems.append(Problem(node.lineno, msg));
    return problems
        
        
def methods_per_class(code, max_methods):
    problems = []
    if max_methods != None:
        tree = ast.parse(code)
        classes = [node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
        for c in classes:
            methods = len([node for node in ast.walk(c) if isinstance(node, ast.FunctionDef)])
            if (methods > max_methods):
                msg = 'too many methods in class({0} > {1})'.format(methods, max_methods)
                problems.append(Problem(c.lineno, msg))
    return problems


def forbid_trailing_whitespace(code, forbid):
    problems = []
    if forbid:
        new_line_indexes = [i for i, letter in enumerate(code) if letter == "\n"]
        for row, i in enumerate(new_line_indexes):
            if code[i-1] == ' ':
                msg = 'trailing whitespace'
                problems.append(Problem(row+1, msg));
    return problems

Христо обнови решението на 18.05.2016 00:17 (преди над 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
import ast;
from collections import defaultdict;


class Problem:
    def __init__(self, row, msg):
        self.row = row
        self.msg = msg
    def __repr__(self):
        return str(self.row) + "  " + self.msg


def critic(code, **rules):
    result = defaultdict(list)
    functions = [line_length, forbid_semicolons, max_arity,
                methods_per_class, forbid_trailing_whitespace, max_lines_per_function]
    
    for f in functions:
        problems = f(code, rules[f.__name__])
        for p in problems:
            result[p.row].append(p.msg)
            
    return result


def line_length(code, allowed_length):
    lines = code.splitlines()
    problems = []
    for row, line in enumerate(lines):
        actual_length=len(line)
        if actual_length > allowed_length:
            msg = "line too long ({0} > {1})".format(actual_length, allowed_length)
            problems.append(Problem(row+1, msg));
    return problems
    
    
def forbid_semicolons(code, forbid):
    problems = []
    if forbid:
        lines = code.splitlines()
        for row, line in enumerate(lines):
            if line.find(';') != -1: # todo: if ; is not in a string!! (" alba; blala" is not a problem)
                msg = "multiple expressions on the same line"
                problems.append(Problem(row+1, msg));
    return problems
        
        
def max_arity(code, max_args):
    problems = []
    if (max_args != None):
        tree = ast.parse(code)
        for node in ast.walk(tree):
            if isinstance(node, ast.FunctionDef):
                arity = len(node.args.args)
                if (arity > max_args):
                    msg = 'too many arguments({0} > {1})'.format(arity, max_args)
                    problems.append(Problem(node.lineno, msg));
    return problems
        
        
def methods_per_class(code, max_methods):
    problems = []
    if max_methods != None:
        tree = ast.parse(code)
        classes = [node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
        for c in classes:
            methods = len([node for node in ast.walk(c) if isinstance(node, ast.FunctionDef)])
            if (methods > max_methods):
                msg = 'too many methods in class({0} > {1})'.format(methods, max_methods)
                problems.append(Problem(c.lineno, msg))
    return problems


def forbid_trailing_whitespace(code, forbid):
    problems = []
    if forbid:
        new_line_indexes = [i for i, letter in enumerate(code) if letter == "\n"]
        for row, i in enumerate(new_line_indexes):
            if code[i-1] == ' ':
                msg = 'trailing whitespace'
                problems.append(Problem(row+1, msg));
    return problems
    
 
def find_last_deepest(node):
    try:
        child = node.body[-1]
        return find_last_deepest(child)
    except AttributeError:
        return node

 
def max_lines_per_function(code, max_lines):
    problems = []
    tree = ast.parse(code)
    functions = [node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef)]
    for f in functions:
        last = find_last_deepest(f.body[-1])
        f_lines = last.lineno - f.lineno
        if f_lines > max_lines:
            msg = 'method with too many lines ({0} > {1})'.format(f_lines, max_lines)
            problems.append(Problem(f.lineno, msg))
    return problems

Христо обнови решението на 18.05.2016 14:52 (преди над 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
import ast;
from collections import defaultdict;


class Problem:
    def __init__(self, row, msg):
        self.row = row
        self.msg = msg
    def __repr__(self):
        return str(self.row) + "  " + self.msg


def critic(code, **rules):
    result = defaultdict(list)
    functions = [line_length, forbid_semicolons, max_arity,
                methods_per_class, forbid_trailing_whitespace, max_lines_per_function, max_nesting]
    
    for f in functions:
        problems = f(code, rules[f.__name__])
        for p in problems:
            result[p.row].append(p.msg)
            
    return result


def line_length(code, allowed_length):
    lines = code.splitlines()
    problems = []
    for row, line in enumerate(lines):
        actual_length=len(line)
        if actual_length > allowed_length:
            msg = "line too long ({0} > {1})".format(actual_length, allowed_length)
            problems.append(Problem(row+1, msg));
    return problems
    
    
def forbid_semicolons(code, forbid):
    problems = []
    if forbid:
        lines = code.splitlines()
        for row, line in enumerate(lines):
            if line.find(';') != -1: # todo: if ; is not in a string!! (" alba; blala" is not a problem)
                msg = "multiple expressions on the same line"
                problems.append(Problem(row+1, msg));
    return problems
        
        
def max_arity(code, max_args):
    problems = []
    if (max_args != None):
        tree = ast.parse(code)
        for node in ast.walk(tree):
            if isinstance(node, ast.FunctionDef):
                arity = len(node.args.args)
                if (arity > max_args):
                    msg = 'too many arguments({0} > {1})'.format(arity, max_args)
                    problems.append(Problem(node.lineno, msg));
    return problems
        
        
def methods_per_class(code, max_methods):
    problems = []
    if max_methods != None:
        tree = ast.parse(code)
        classes = [node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
        for c in classes:
            methods = len([node for node in ast.walk(c) if isinstance(node, ast.FunctionDef)])
            if (methods > max_methods):
                msg = 'too many methods in class({0} > {1})'.format(methods, max_methods)
                problems.append(Problem(c.lineno, msg))
    return problems


def forbid_trailing_whitespace(code, forbid):
    problems = []
    if forbid:
        new_line_indexes = [i for i, letter in enumerate(code) if letter == "\n"]
        for row, i in enumerate(new_line_indexes):
            if code[i-1] == ' ':
                msg = 'trailing whitespace'
                problems.append(Problem(row+1, msg));
    return problems
    
 
def find_last_deepest(node):
    try:
        child = node.body[-1]
        return find_last_deepest(child)
    except AttributeError:
        return node

 
def max_lines_per_function(code, max_lines):
    problems = []
    tree = ast.parse(code)
    functions = [node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef)]
    for f in functions:
        last = find_last_deepest(f.body[-1])
        f_lines = last.lineno - f.lineno
        if f_lines > max_lines:
            msg = 'method with too many lines ({0} > {1})'.format(f_lines, max_lines)
            problems.append(Problem(f.lineno, msg))
    return problems
    
    
def find_nesting(node, deep, crnt_max, row):
    try:
        for child in node.body:
            d, r = find_nesting(child, deep+1, crnt_max, row)
            if (d > crnt_max):
                crnt_max = d
                row = r
        return (crnt_max, row)
    except AttributeError:
        return deep, node.lineno


def max_nesting(code, allowed_nesting):
    problems = []
    root = ast.parse(code)
    max_nesting, row = find_nesting(root, 0, 0, 0)
    print(max_nesting, row)
    if (max_nesting > allowed_nesting):
         msg = "nesting too deep ({0} > {1})".format(max_nesting, allowed_nesting)
         problems.append(Problem(row, msg))
    return problems