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


class SomeVisitor(ast.NodeVisitor):
    def __init__(self, detect, depth, code_lines):
        self.detect = detect
        self.statements = [ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef,
                           ast.Return, ast.Delete, ast.Assign, ast.AugAssign,
                           ast.For, ast.AsyncFor, ast.While, ast.If, ast.With,
                           ast.AsyncWith, ast.Raise, ast.Try, ast.Assert,
                           ast.Import, ast.ImportFrom, ast.Global,
                           ast.Nonlocal, ast.Expr, ast.Pass, ast.Break,
                           ast.Continue]
        self.last_line = 0
        self.depth = depth
        self.current = 0
        self.code_lines = code_lines
        self.res = {}

    def generic_visit(self, node):
        for t in self.statements:
            if isinstance(node, t):
                if node.lineno == self.last_line:
                    self.res[node.lineno] = self.res.get(node.lineno,
                                                         set()).union(
                        set(['multiple expressions on the same line']))
                self.last_line = node.lineno
                self.current += 1
                if self.depth and self.current > self.depth:
                    self.res[node.lineno] = self.res.get(
                                            node.lineno,
                                            set()).union(
                                            set(['nesting too deep (' +
                                                str(self.current) + ' > ' +
                                                str(self.depth) + ')']))
        ast.NodeVisitor.generic_visit(self, node)
        return self.res


class LinesVisitor(ast.NodeVisitor):
    def __init__(self, lines, methods_per_class):
        self.lines = lines
        self.methods = methods_per_class
        self.res = {}

    def generic_visit(self, node):
        ast.NodeVisitor.generic_visit(self, node)
        return self.res

    def visitFunctionDef(self, function):
        print("asdfasd")
        if self.lines and len(function.body) > self.lines:
            self.res[function.lineno] = self.res.get(
                                        function.lineno,
                                        set()).union(
                                        set(['method with too many lines (' +
                                             str(len(function.body)) +
                                             ' > ' + str(self.lines) + ')']))
        generic_visit(self, function)

    def visitClassDef(self, cls):
        count = 0
        print("gasdfasd")
        for statement in cls.body:
            print(statement.name)
            if type(statement) == ast.FunctionDef:
                count += 1
        if count > self. methods:
            self.res[cls.lineno] = self.res.get(
                                   cls.lineno, set()).union(
                                   set(['too many methods in class(' +
                                        str(count) + ' > ' +
                                        str(self.methods) + ')']))


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):
    res = {}
    lines = code.splitlines()
    current = 1
    trailing = re.compile('.* +$')
    for line in lines:
        if len(line) > line_length:
            res[current] = res.get(current,
                                   set()).union(set(['line too long (' +
                                                str(len(line)) + ' > ' +
                                                str(line_length) + ')']))
        result = trailing.match(line)
        if result:
            res[current] = res.get(current,
                                   set()).union(set(['trailing whitespace']))
        current += 1
    tree = ast.parse(code)
    nesting = SomeVisitor(forbid_semicolons, max_nesting, lines).visit(tree)
    for key in nesting.keys():
        res[key] = res.get(key, set()).union(nesting[key])
    tree = ast.parse(code)
    long_functions = LinesVisitor(max_lines_per_function,
                                  methods_per_class).visit(tree)
    for key in long_functions.keys():
        res[key] = res.get(key, set()).union(long_functions[key])
    return res

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

..F..FF.FF.
======================================================================
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: 11 != 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: 2 != 1

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

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

FAILED (failures=5)

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

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


class SomeVisitor(ast.NodeVisitor):
    def __init__(self, detect, depth, code_lines):
        self.detect = detect
        self.statements = [ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef,
                           ast.Return, ast.Delete, ast.Assign, ast.AugAssign,
                           ast.For, ast.AsyncFor, ast.While, ast.If, ast.With,
                           ast.AsyncWith, ast.Raise, ast.Try, ast.Assert,
                           ast.Import, ast.ImportFrom, ast.Global,
                           ast.Nonlocal, ast.Expr, ast.Pass, ast.Break,
                           ast.Continue]
        self.last_line = 0
        self.depth = depth
        self.current = 0
        self.code_lines = code_lines
        self.res = {}

    def generic_visit(self, node):
        for t in self.statements:
            if isinstance(node, t):
                if node.lineno == self.last_line:
                    self.res[node.lineno] = self.res.get(node.lineno,
                                                         set()).union(
                        set(['multiple expressions on the same line']))
                self.last_line = node.lineno
                self.current += 1
                if self.depth and self.current > self.depth:
                    self.res[node.lineno] = self.res.get(
                                            node.lineno,
                                            set()).union(
                                            set(['nesting too deep (' +
                                                str(self.current) + ' > ' +
                                                str(self.depth) + ')']))
        ast.NodeVisitor.generic_visit(self, node)
        return self.res


class LinesVisitor(ast.NodeVisitor):
    def __init__(self, lines, methods_per_class):
        self.lines = lines
        self.methods = methods_per_class
        self.res = {}

    def generic_visit(self, node):
        ast.NodeVisitor.generic_visit(self, node)
        return self.res

    def visitFunctionDef(self, function):
        print("asdfasd")
        if self.lines and len(function.body) > self.lines:
            self.res[function.lineno] = self.res.get(
                                        function.lineno,
                                        set()).union(
                                        set(['method with too many lines (' +
                                             str(len(function.body)) +
                                             ' > ' + str(self.lines) + ')']))
        generic_visit(self, function)

    def visitClassDef(self, cls):
        count = 0
        print("gasdfasd")
        for statement in cls.body:
            print(statement.name)
            if type(statement) == ast.FunctionDef:
                count += 1
        if count > self. methods:
            self.res[cls.lineno] = self.res.get(
                                   cls.lineno, set()).union(
                                   set(['too many methods in class(' +
                                        str(count) + ' > ' +
                                        str(self.methods) + ')']))


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):
    res = {}
    lines = code.splitlines()
    current = 1
    trailing = re.compile('.* +$')
    for line in lines:
        if len(line) > line_length:
            res[current] = res.get(current,
                                   set()).union(set(['line too long (' +
                                                str(len(line)) + ' > ' +
                                                str(line_length) + ')']))
        result = trailing.match(line)
        if result:
            res[current] = res.get(current,
                                   set()).union(set(['trailing whitespace']))
        current += 1
    tree = ast.parse(code)
    nesting = SomeVisitor(forbid_semicolons, max_nesting, lines).visit(tree)
    for key in nesting.keys():
        res[key] = res.get(key, set()).union(nesting[key])
    tree = ast.parse(code)
    long_functions = LinesVisitor(max_lines_per_function,
                                  methods_per_class).visit(tree)
    for key in long_functions.keys():
        res[key] = res.get(key, set()).union(long_functions[key])
    return res