timeit

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

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

Решение на Статичен анализ на python код от Данислав Киров

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

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

Резултати

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

Код

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


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):

    result = {}
    warnings = set()

    added = 0
    if code[-1] is not '\n':
        code = code + '\n'
        added = 1

    rows = re.findall('[\d\D]*?\n', code)
    curr_row = 1
    for row in rows:
        if ';' in row and forbid_semicolons:
            warnings.add('multiple expressions on the same line')
        if ' \n' in row and forbid_trailing_whitespace:
            warnings.add('trailing whitespace')
        if len(row) > line_length:
            warnings.add('line too long ({} > {})'.format(
                len(row) - added, line_length))
        if max_arity and 'def' in row:
            f = re.findall('def [\D\d]+?:', row)
            args = f[0].count(',') + 1
            if args > max_arity:
                warnings.add('too many arguments({} > {})'.format(
                    args, max_arity))
        if warnings:
            result[curr_row] = warnings
        curr_row += 1

    if methods_per_class or max_nesting:
        tree = ast.parse(code)
        class_definitions = [node for node in tree.body if
                             isinstance(node, ast.ClassDef)]
        functions = []
        for class_def in class_definitions:
            method_definitions = [node for node in class_def.body if
                                  isinstance(node, ast.FunctionDef)]
            functions.extend(method_definitions)
            if methods_per_class and \
                    len(method_definitions) > methods_per_class:
                code_to_class = re.findall('[\d\D]*?class {}'.format(
                    class_def.name), code)
                row = code_to_class[0].count('\n') + 1
                if row in result.keys():
                    result[row][0].add(
                        'too many methods in class({} > {})'.format(
                            len(method_definitions), methods_per_class))
                else:
                    result[row] = {'too many methods in class({} > {})'.format(
                        len(method_definitions), methods_per_class)}
        if max_nesting:
            functions.extend([node for node in tree.body
                             if isinstance(node, ast.FunctionDef)])
            for f in functions:
                nest, row = find_nesting(
                    f, f.col_offset, f.lineno, max_nesting * indentation_size)
                for c in class_definitions:
                    if f in c.body:
                        nest -= indentation_size
                nest //= indentation_size
                if nest > max_nesting:
                    if row in result.keys():
                        result[row][0].add('nesting too deep ({} > {})'.format(
                            nest, max_nesting))
                    else:
                        result[row] = {'nesting too deep ({} > {})'.format(
                            nest, max_nesting)}

    return result


def find_nesting(node, nest, row, max_nesting):
    if nest <= max_nesting:
        for no in node.body:
            if not isinstance(no, ast.FunctionDef) and hasattr(no, 'body'):
                return find_nesting(no, nest, row, max_nesting)
            if no.col_offset > nest:
                nest = no.col_offset
                row = no.lineno
    return nest, row

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

..F..FE..F.
======================================================================
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
TypeError: 'set' object does not support indexing

======================================================================
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_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: 2 != 1

----------------------------------------------------------------------
Ran 11 tests in 0.094s

FAILED (failures=3, errors=1)

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

Данислав обнови решението на 18.05.2016 16: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
import re
import ast


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):

    result = {}
    warnings = set()

    added = 0
    if code[-1] is not '\n':
        code = code + '\n'
        added = 1

    rows = re.findall('[\d\D]*?\n', code)
    curr_row = 1
    for row in rows:
        if ';' in row and forbid_semicolons:
            warnings.add('multiple expressions on the same line')
        if ' \n' in row and forbid_trailing_whitespace:
            warnings.add('trailing whitespace')
        if len(row) > line_length:
            warnings.add('line too long ({} > {})'.format(
                len(row) - added, line_length))
        if max_arity and 'def' in row:
            f = re.findall('def [\D\d]+?:', row)
            args = f[0].count(',') + 1
            if args > max_arity:
                warnings.add('too many arguments({} > {})'.format(
                    args, max_arity))
        if warnings:
            result[curr_row] = warnings
        curr_row += 1

    if methods_per_class or max_nesting:
        tree = ast.parse(code)
        class_definitions = [node for node in tree.body if
                             isinstance(node, ast.ClassDef)]
        functions = []
        for class_def in class_definitions:
            method_definitions = [node for node in class_def.body if
                                  isinstance(node, ast.FunctionDef)]
            functions.extend(method_definitions)
            if methods_per_class and \
                    len(method_definitions) > methods_per_class:
                code_to_class = re.findall('[\d\D]*?class {}'.format(
                    class_def.name), code)
                row = code_to_class[0].count('\n') + 1
                if row in result.keys():
                    result[row][0].add(
                        'too many methods in class({} > {})'.format(
                            len(method_definitions), methods_per_class))
                else:
                    result[row] = {'too many methods in class({} > {})'.format(
                        len(method_definitions), methods_per_class)}
        if max_nesting:
            functions.extend([node for node in tree.body
                             if isinstance(node, ast.FunctionDef)])
            for f in functions:
                nest, row = find_nesting(
                    f, f.col_offset, f.lineno, max_nesting * indentation_size)
                for c in class_definitions:
                    if f in c.body:
                        nest -= indentation_size
                nest //= indentation_size
                if nest > max_nesting:
                    if row in result.keys():
                        result[row][0].add('nesting too deep ({} > {})'.format(
                            nest, max_nesting))
                    else:
                        result[row] = {'nesting too deep ({} > {})'.format(
                            nest, max_nesting)}

    return result


def find_nesting(node, nest, row, max_nesting):
    if nest <= max_nesting:
        for no in node.body:
            if not isinstance(no, ast.FunctionDef) and hasattr(no, 'body'):
                return find_nesting(no, nest, row, max_nesting)
            if no.col_offset > nest:
                nest = no.col_offset
                row = no.lineno
    return nest, row