timeit

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

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

Решение на Статичен анализ на python код от Николай Мантаров

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

Към профила на Николай Мантаров

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 10 успешни тест(а)
  • 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
import re
import ast
from collections import defaultdict

NODES_TO_CHECK = (ast.If, ast.While, ast.For, ast.With,
                  ast.Try, ast.ExceptHandler, ast.FunctionDef,
                  ast.ClassDef)
MAX_LINES_NODES = (ast.If, ast.While, ast.For, ast.With,
                   ast.Try, ast.ExceptHandler)


def methods_count(node, info, **rules):
    count = 0
    for nodes in node.body:
        if isinstance(nodes, ast.FunctionDef):
            count += 1
    methods = rules.get("methods_per_class", None)
    if methods is not None and count > methods:
        info[node.lineno].append(
            'too many methods in class({} > {})'.format(count, methods))


def process_module_ast(module, info, indent_info, nesting_count=0, indent=0,
                       **rules):
    max_nesting = rules.get("max_nesting", None)
    indentation_size = rules.get("indentation_size", 4)
    max_arity = rules.get("max_arity", None)
    max_lines_per_function = rules.get("max_lines_per_function", None)
    for node in module.body:
        if isinstance(node, ast.ClassDef):
            methods_count(node, info, **rules)
            process_module_ast(node, info, indent_info, nesting_count,
                               indent + 1, **rules)
        elif isinstance(node, NODES_TO_CHECK):
            process_module_ast(node, info, indent_info, nesting_count + 1,
                               indent + 1, **rules)
        if max_nesting is not None and nesting_count > max_nesting:
            info[node.lineno].append(
                'nesting too deep ({} > {})'.format(nesting_count,
                                                    max_nesting))
        if indent_info[node.lineno] == False:
            indent_info[node.lineno] = True
            if node.col_offset != (indent * indentation_size):
                info[node.lineno].append(
                    'indentation is {} instead of {}'.format(
                        node.col_offset, (indent * indentation_size)))
        if max_arity is not None and isinstance(node, ast.FunctionDef):
            args = len(node.args.args)
            if args > max_arity:
                info[node.lineno].append('too many arguments({} > {})'.format(
                    args, max_arity))
        if max_lines_per_function is not None and isinstance(node,
                                                             ast.FunctionDef):
            container = []
            max_lines(node, container)
            if max_lines_per_function < len(container):
                info[node.lineno].append(
                    'method with too many lines ({} > {})'.format(
                     len(container), max_lines_per_function))


def max_lines(function, counter):
    nodes = function.body
    counter.extend(nodes)
    for node in nodes:
        if isinstance(node, MAX_LINES_NODES):
            max_lines(node, counter)


def critic(code, **rules):
    tree = ast.parse(code)
    result = defaultdict(list)
    indent_info = defaultdict(bool)
    process_module_ast(tree, result, indent_info, **rules)
    lines = re.split('\n', code)
    whitespace = rules.get('forbid_trailing_whitespace', True)
    forbid_semicolons = rules.get("forbid_semicolons", True)
    allowed = rules.get('line_length', 79)
    at = 0
    for line in lines:
        at += 1
        if len(line) > allowed:
            actual = len(line)
            result[at].append(
                'line too long ({} > {})'.format(actual, allowed))
        if forbid_semicolons is True:
            reworked_line = re.sub(r'(".*?")|(#.*)|(\'.*?\')', "", line)
            if(re.search(r';', str(reworked_line))):
                result[at].append('multiple expressions on the same line')
        if (re.search(r'.*\s+$', line)):
            result[at].append('trailing whitespace')
    return result

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

......F....
======================================================================
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: Items in the first set but not the second:
'method with too many lines (6 > 5)'

----------------------------------------------------------------------
Ran 11 tests in 0.403s

FAILED (failures=1)

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

Николай обнови решението на 18.05.2016 03:05 (преди над 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
import re
import ast
from collections import defaultdict

NODES_TO_CHECK = (ast.If, ast.While, ast.For, ast.With,
                  ast.Try, ast.ExceptHandler, ast.FunctionDef,
                  ast.ClassDef)
MAX_LINES_NODES = (ast.If, ast.While, ast.For, ast.With,
                   ast.Try, ast.ExceptHandler)


def methods_count(node, info, **rules):
    count = 0
    for nodes in node.body:
        if isinstance(nodes, ast.FunctionDef):
            count += 1
    methods = rules.get("methods_per_class", None)
    if methods is not None and count > methods:
        info[node.lineno].append(
            'too many methods in class({} > {})'.format(count, methods))


def process_module_ast(module, info, indent_info, nesting_count=0, indent=0,
                       **rules):
    max_nesting = rules.get("max_nesting", None)
    indentation_size = rules.get("indentation_size", 4)
    max_arity = rules.get("max_arity", None)
    max_lines_per_function = rules.get("max_lines_per_function", None)
    for node in module.body:
        if isinstance(node, ast.ClassDef):
            methods_count(node, info, **rules)
            process_module_ast(node, info, indent_info, nesting_count,
                               indent + 1, **rules)
        elif isinstance(node, NODES_TO_CHECK):
            process_module_ast(node, info, indent_info, nesting_count + 1,
                               indent + 1, **rules)
        if max_nesting is not None and nesting_count > max_nesting:
            info[node.lineno].append(
                'nesting too deep ({} > {})'.format(nesting_count,
                                                    max_nesting))
        if indent_info[node.lineno] == False:
            indent_info[node.lineno] = True
            if node.col_offset != (indent * indentation_size):
                info[node.lineno].append(
                    'indentation is {} instead of {}'.format(
                        node.col_offset, (indent * indentation_size)))
        if max_arity is not None and isinstance(node, ast.FunctionDef):
            args = len(node.args.args)
            if args > max_arity:
                info[node.lineno].append('too many arguments({} > {})'.format(
                    args, max_arity))
        if max_lines_per_function is not None and isinstance(node,
                                                             ast.FunctionDef):
            container = []
            max_lines(node, container)
            if max_lines_per_function < len(container):
                info[node.lineno].append(
                    'method with too many lines ({} > {})'.format(
                     len(container), max_lines_per_function))


def max_lines(function, counter):
    nodes = function.body
    counter.extend(nodes)
    for node in nodes:
        if isinstance(node, MAX_LINES_NODES):
            max_lines(node, counter)


def critic(code, **rules):
    tree = ast.parse(code)
    result = defaultdict(list)
    indent_info = defaultdict(bool)
    process_module_ast(tree, result, indent_info, **rules)
    lines = re.split('\n', code)
    whitespace = rules.get('forbid_trailing_whitespace', True)
    forbid_semicolons = rules.get("forbid_semicolons", True)
    allowed = rules.get('line_length', 79)
    at = 0
    for line in lines:
        at += 1
        if len(line) > allowed:
            actual = len(line)
            result[at].append(
                'line too long ({} > {})'.format(actual, allowed))
        if forbid_semicolons is True:
            reworked_line = re.sub(r'(".*?")|(#.*)|(\'.*?\')', "", line)
            if(re.search(r';', str(reworked_line))):
                result[at].append('multiple expressions on the same line')
        if (re.search(r'.*\s+$', line)):
            result[at].append('trailing whitespace')
    return result