timeit

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

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

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

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

Към профила на Теодор Тошков

Резултати

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

Код

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


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):
    nodes = ast.parse(code)
    lines = code.splitlines()
    result = defaultdict(list)
    for num, line in enumerate(lines):
        if len(line) > line_length:
            result[num+1].append('line too long ({} > {})'.format(len(line),
                                                                  line_length))
        if forbid_trailing_whitespace is True \
           and len(line) > 0 \
           and line[-1] in {' ', '\s', '\t'}:
            result[num+1].append('trailing whitespace')
        if max_nesting is not None and space(line) % indentation_size == 0 \
           and space(line) > max_nesting * indentation_size:
            result[num+1].append('nesting too deep ({} > {})'.format(
                space(line) // indentation_size, max_nesting))
    for node in ast.walk(nodes):
        if isinstance(node, ast.FunctionDef) \
           and max_arity is not None:
            total_args = len(node.args.args) + len(node.args.kwonlyargs)
            if node.args.vararg is not None:
                total_args += 1
            if node.args.kwarg is not None:
                total_args += 1
            if total_args > max_arity:
                result[node.lineno].append(
                    'too many arguments({} > {})'.format(total_args, max_arity)
                    )
        if isinstance(node, ast.ClassDef) \
           and methods_per_class is not None:
            total_methods = 0
            for subnode in node.body:
                if isinstance(subnode, ast.FunctionDef):
                    total_methods += 1
            if total_methods > methods_per_class:
                result[node.lineno].append(
                    'too many methods in class({} > {})'.format(
                        total_methods, methods_per_class))
    ignore = None
    bracket = None
    brackets = {'(', '{', '['}
    ignore_set = {'\"', '\'', '#'}
    for num, line in enumerate(lines):
        if bracket is None and space(line) % indentation_size != 0:
            result[num+1].append(
                'indentation is {} instead of {}'.format(
                    space(line), space(line) // 4 * 4))
        gd_line = rm_space(line)
        for n, char in enumerate(gd_line):
            if char in {'\'', '\"'} and ignore is None:
                ignore = char
            elif char in {'\'', '\"'} and ignore == char:
                ignore = None
            elif char == '#' and ignore is None:
                continue
            elif (char == ";" and ignore is None and
                  n+1 != len(gd_line) and gd_line[n+1] not in ignore_set):
                result[num+1].append('multiple expressions on the same line')
                if ignore is None and char in brackets and brackets is None:
                    bracket = char
                elif ignore is None and char in brackets and brackers == char:
                    bracket = None
    return result


def rm_space(string):
    return "".join([c for c in string if c != " "])


def space(string):
    return len(string) - len(string.lstrip(" "))

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

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

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

----------------------------------------------------------------------
Ran 11 tests in 0.097s

FAILED (failures=3)

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

Теодор обнови решението на 17.05.2016 16:48 (преди над 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
import ast
from collections import defaultdict


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):
    nodes = ast.parse(code)
    lines = code.splitlines()
    result = defaultdict(list)
    for num, line in enumerate(lines):
        if len(line) > line_length:
            result[num+1].append('line too long ({} > {})'.format(len(line),
                                                                  line_length))
        if forbid_trailing_whitespace is True \
           and len(line) > 0 \
           and line[-1] in {' ', '\s', '\t'}:
            result[num+1].append('trailing whitespace')
        if max_nesting is not None and space(line) % indentation_size == 0 \
           and space(line) > max_nesting * indentation_size:
            result[num+1].append('nesting too deep ({} > {})'.format(
                space(line) // indentation_size, max_nesting))
    for node in ast.walk(nodes):
        if isinstance(node, ast.FunctionDef) \
           and max_arity is not None:
            total_args = len(node.args.args) + len(node.args.kwonlyargs)
            if node.args.vararg is not None:
                total_args += 1
            if node.args.kwarg is not None:
                total_args += 1
            if total_args > max_arity:
                result[node.lineno].append(
                    'too many arguments({} > {})'.format(total_args, max_arity)
                    )
        if isinstance(node, ast.ClassDef) \
           and methods_per_class is not None:
            total_methods = 0
            for subnode in node.body:
                if isinstance(subnode, ast.FunctionDef):
                    total_methods += 1
            if total_methods > methods_per_class:
                result[node.lineno].append(
                    'too many methods in class({} > {})'.format(
                        total_methods, methods_per_class))
    ignore1 = False
    ignore2 = False
    ignore_set = {'\"', '\'', '#'}
    for num, line in enumerate(lines):
        gd_line = rm_space(line)
        for n, char in enumerate(gd_line):
            if char == '\'' and not ignore2:
                ignore1 = not ignore1
            elif char == '\"' and not ignore1:
                ignore2 = not ignore2
            elif char == '#' and not (ignore1 or ignore2):
                continue
            elif (char == ";" and not (ignore1 or ignore2) and
                  n+1 != len(gd_line) and gd_line[n+1] not in ignore_set):
                result[num+1].append('multiple expressions on the same line')
    return result


def rm_space(string):
    return "".join([c for c in string if c != " "])


def space(string):
    return len(string) - len(string.lstrip(" "))

Теодор обнови решението на 18.05.2016 13:26 (преди над 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
import ast
from collections import defaultdict


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):
    nodes = ast.parse(code)
    lines = code.splitlines()
    result = defaultdict(list)
    for num, line in enumerate(lines):
        if len(line) > line_length:
            result[num+1].append('line too long ({} > {})'.format(len(line),
                                                                  line_length))
        if forbid_trailing_whitespace is True \
           and len(line) > 0 \
           and line[-1] in {' ', '\s', '\t'}:
            result[num+1].append('trailing whitespace')
        if max_nesting is not None and space(line) % indentation_size == 0 \
           and space(line) > max_nesting * indentation_size:
            result[num+1].append('nesting too deep ({} > {})'.format(
                space(line) // indentation_size, max_nesting))
    for node in ast.walk(nodes):
        if isinstance(node, ast.FunctionDef) \
           and max_arity is not None:
            total_args = len(node.args.args) + len(node.args.kwonlyargs)
            if node.args.vararg is not None:
                total_args += 1
            if node.args.kwarg is not None:
                total_args += 1
            if total_args > max_arity:
                result[node.lineno].append(
                    'too many arguments({} > {})'.format(total_args, max_arity)
                    )
        if isinstance(node, ast.ClassDef) \
           and methods_per_class is not None:
            total_methods = 0
            for subnode in node.body:
                if isinstance(subnode, ast.FunctionDef):
                    total_methods += 1
            if total_methods > methods_per_class:
                result[node.lineno].append(
                    'too many methods in class({} > {})'.format(
                        total_methods, methods_per_class))
    ignore = None
    bracket = None
    brackets = {'(', '{', '['}
    ignore_set = {'\"', '\'', '#'}
    for num, line in enumerate(lines):
        if bracket is None and space(line) % indentation_size != 0:
            result[num+1].append(
                'indentation is {} instead of {}'.format(
                    space(line), space(line) // 4 * 4))
        gd_line = rm_space(line)
        for n, char in enumerate(gd_line):
            if char in {'\'', '\"'} and ignore is None:
                ignore = char
            elif char in {'\'', '\"'} and ignore == char:
                ignore = None
            elif char == '#' and ignore is None:
                continue
            elif (char == ";" and ignore is None and
                  n+1 != len(gd_line) and gd_line[n+1] not in ignore_set):
                result[num+1].append('multiple expressions on the same line')
                if ignore is None and char in brackets and brackets is None:
                    bracket = char
                elif ignore is None and char in brackets and brackers == char:
                    bracket = None
    return result


def rm_space(string):
    return "".join([c for c in string if c != " "])


def space(string):
    return len(string) - len(string.lstrip(" "))