timeit

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

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

Решение на Статичен анализ на python код от Даниел Шушков

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

Към профила на Даниел Шушков

Резултати

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

Код

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
import ast
import string
import collections
import re


class DepthCounter(ast.NodeVisitor):

    def __init__(self, max_dep, diction, depth=0):
        self.depth = depth
        self.max_depth = max_dep
        self.dictionary = diction

    def _count_depth(self, node):
        child_depth = self.depth + 1
        for child in ast.iter_child_nodes(node):
            depth_counter = DepthCounter(
                self.max_depth, self.dictionary, child_depth)
            depth_counter.visit(child)
            self.depth = max(self.depth, depth_counter.depth)
            if self.depth > self.max_depth:
                msg = 'nesting too deep (' + str(self.depth) + \
                    " > " + str(self.max_depth) + ')'
                self.dictionary[node.lineno].add(msg)

    visit_For = _count_depth
    visit_While = _count_depth
    visit_With = _count_depth
    visit_Try = _count_depth
    visit_If = _count_depth
    visit_FunctionDef = _count_depth


def check_line_lenght(code, line_lenght, dictionary):
    lines = code.splitlines(True)
    for line in lines:
        if len(line) > line_lenght:
            msg = "line too long (" + str(len(line)) + \
                " > " + str(line_lenght) + ')'
            dictionary[lines.index(line) + 1].add(msg)


def check_line_whitespace(code, dictionary):
    lines = code.splitlines(True)
    for line in lines:
        if line[len(line) - 2] == ' ':
            msg = 'trailing whitespace'
            dictionary[lines.index(line) + 1].add(msg)


def check_mult_expr(code, dictionary):
    lines = code.splitlines(True)
    for line in lines:
        if re.search(r';', line):
            msg = "multiple expressions on the same line"
            dictionary[lines.index(line) + 1].add(msg)


def check_lines_per_func(tree, dictionary):
    pass


def check_max_arity(tree, dictionary, max_arity):
    for node in ast.walk(tree):
        if isinstance(node, ast.FunctionDef):
            if(max_arity < len(node.args.args)):
                msg = "too many arguments(" + str(len(node.args.args)
                                                  ) + ' > ' + str(max_arity
                                                                  ) + ')'
                dictionary[node.lineno].add(msg)


def check_max_nesting(tree, dictionary, max_nesting):
    depth_counter = DepthCounter(max_nesting, dictionary, -1)
    depth_counter.visit(tree)


def check_number_of_methods(tree, dictionary, max_count):
    for node in ast.walk(tree):
        if isinstance(node, ast.ClassDef):
            count_func = 0
            for body_item in node.body:
                if isinstance(body_item, ast.FunctionDef):
                    count_func = count_func + 1
            if count_func > max_count:
                msg = 'too many methods in class(' + str(
                    count_func) + ' > ' + str(max_count) + ')'
                dictionary[node.lineno].add(msg)


def critic(code, line_lenght=79, forbid_semicolons=True,
           max_nesting=None, indentation_size=4, max_arity=None,
           methods_per_class=None, forbid_trailing_whitespace=True,
           max_lines_per_function=None):
    dictionary = collections.defaultdict(set)
    tree = ast.parse(code)
    check_line_lenght(code, line_lenght, dictionary)

    if forbid_trailing_whitespace:
        check_line_whitespace(code, dictionary)

    if forbid_semicolons:
        check_mult_expr(code, dictionary)

    if max_nesting:
        check_max_nesting(tree, dictionary, max_nesting)

    if max_lines_per_function:
        check_lines_per_func(tree, dictionary)

    if methods_per_class:
        check_number_of_methods(tree, dictionary, methods_per_class)

    if max_arity:
        check_max_arity(tree, dictionary, max_arity)
    return dictionary

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

..F..FF.F.F
======================================================================
FAIL: 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
AssertionError: 0 != 1

======================================================================
FAIL: 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
AssertionError: 0 != 1

======================================================================
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: 3 != 5

======================================================================
FAIL: 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
AssertionError: 0 != 1

======================================================================
FAIL: 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
AssertionError: Items in the first set but not the second:
'trailing whitespace'

----------------------------------------------------------------------
Ran 11 tests in 0.104s

FAILED (failures=5)

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

Даниел обнови решението на 18.05.2016 16:27 (преди над 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
import ast
import string
import collections
import re


class DepthCounter(ast.NodeVisitor):

    def __init__(self, max_dep, diction, depth=0):
        self.depth = depth
        self.max_depth = max_dep
        self.dictionary = diction

    def _count_depth(self, node):
        child_depth = self.depth + 1
        for child in ast.iter_child_nodes(node):
            depth_counter = DepthCounter(
                self.max_depth, self.dictionary, child_depth)
            depth_counter.visit(child)
            self.depth = max(self.depth, depth_counter.depth)
            if self.depth > self.max_depth:
                msg = 'nesting too deep (' + str(self.depth) + \
                    " > " + str(self.max_depth) + ')'
                self.dictionary[node.lineno].add(msg)

    visit_For = _count_depth
    visit_While = _count_depth
    visit_With = _count_depth
    visit_Try = _count_depth
    visit_If = _count_depth
    visit_FunctionDef = _count_depth


def check_line_lenght(code, line_lenght, dictionary):
    lines = code.splitlines(True)
    for line in lines:
        if len(line) > line_lenght:
            msg = "line too long (" + str(len(line)) + \
                " > " + str(line_lenght) + ')'
            dictionary[lines.index(line) + 1].add(msg)


def check_line_whitespace(code, dictionary):
    lines = code.splitlines(True)
    for line in lines:
        if line[len(line) - 2] == ' ':
            msg = 'trailing whitespace'
            dictionary[lines.index(line) + 1].add(msg)


def check_mult_expr(code, dictionary):
    lines = code.splitlines(True)
    for line in lines:
        if re.search(r';', line):
            msg = "multiple expressions on the same line"
            dictionary[lines.index(line) + 1].add(msg)


def check_lines_per_func(tree, dictionary):
    pass


def check_max_arity(tree, dictionary, max_arity):
    for node in ast.walk(tree):
        if isinstance(node, ast.FunctionDef):
            if(max_arity < len(node.args.args)):
                msg = "too many arguments(" + str(len(node.args.args)
                                                  ) + ' > ' + str(max_arity
                                                                  ) + ')'
                dictionary[node.lineno].add(msg)


def check_max_nesting(tree, dictionary, max_nesting):
    depth_counter = DepthCounter(max_nesting, dictionary, -1)
    depth_counter.visit(tree)


def check_number_of_methods(tree, dictionary, max_count):
    for node in ast.walk(tree):
        if isinstance(node, ast.ClassDef):
            count_func = 0
            for body_item in node.body:
                if isinstance(body_item, ast.FunctionDef):
                    count_func = count_func + 1
            if count_func > max_count:
                msg = 'too many methods in class(' + str(
                    count_func) + ' > ' + str(max_count) + ')'
                dictionary[node.lineno].add(msg)


def critic(code, line_lenght=79, forbid_semicolons=True,
           max_nesting=None, indentation_size=4, max_arity=None,
           methods_per_class=None, forbid_trailing_whitespace=True,
           max_lines_per_function=None):
    dictionary = collections.defaultdict(set)
    tree = ast.parse(code)
    check_line_lenght(code, line_lenght, dictionary)

    if forbid_trailing_whitespace:
        check_line_whitespace(code, dictionary)

    if forbid_semicolons:
        check_mult_expr(code, dictionary)

    if max_nesting:
        check_max_nesting(tree, dictionary, max_nesting)

    if max_lines_per_function:
        check_lines_per_func(tree, dictionary)

    if methods_per_class:
        check_number_of_methods(tree, dictionary, methods_per_class)

    if max_arity:
        check_max_arity(tree, dictionary, max_arity)
    return dictionary