Sat, 08 Jun 2019 11:17:17 +0300
cleanup
65 | 1 | #!/usr/bin/env python3 |
2 | ''' | |
3 | Routines for assembling the test suite, and running it on a model. | |
4 | ''' | |
16 | 5 | from warnings import warn |
6 | ||
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
7 | class ProblemType: |
65 | 8 | ''' |
9 | Represents a type of issue in the part | |
10 | ''' | |
64
1c0884f5506e
changed severity names to be better understood
Teemu Piippo <teemu@hecknology.net>
parents:
63
diff
changeset
|
11 | severities = ['hold', 'warning'] # in descending order |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
12 | def __init__(self, name, severity, message): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
13 | if severity not in ProblemType.severities: |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
14 | raise ValueError(str.format( |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
15 | 'bad severity {severity!r}', |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
16 | severity = severity, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
17 | )) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
18 | self.name = name |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
19 | self.severity = severity |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
20 | self.message = message |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
21 | def __call__(self, bad_object, **args): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
22 | return Problem( |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
23 | problem_class = self, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
24 | bad_object = bad_object, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
25 | **args, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
26 | ) |
63
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
27 | def placeholder_message(self): |
65 | 28 | ''' |
29 | Returns the error message of this problem type, with placeholders | |
30 | filled in. | |
31 | ''' | |
63
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
32 | if callable(self.message): |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
33 | import inspect |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
34 | spec = inspect.getfullargspec(self.message) |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
35 | args = {} |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
36 | assert not spec.varargs and not spec.varkw |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
37 | for argname in spec.args + spec.kwonlyargs: |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
38 | args[argname] = '<' + argname.replace('_', ' ') + '>' |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
39 | return self.message(**args) |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
40 | else: |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
41 | return self.message |
13 | 42 | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
43 | class Problem: |
65 | 44 | ''' |
45 | Represents a single issue in the part | |
46 | ''' | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
47 | def __init__(self, problem_class, bad_object, **args): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
48 | self.problem_class = problem_class |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
49 | self.severity = problem_class.severity |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
50 | self.object = bad_object |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
51 | self.args = args |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
52 | def __str__(self): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
53 | if callable(self.problem_class.message): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
54 | return self.problem_class.message(**self.args) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
55 | else: |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
56 | return self.problem_class.message |
16 | 57 | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
58 | def problem_type(problem_name, **args): |
65 | 59 | ''' |
60 | A decorator that creates a new ProblemType and attaches it to the | |
61 | decoratable function. | |
62 | ''' | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
63 | def wrapper(function): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
64 | if not hasattr(function, 'ldcheck_problem_types'): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
65 | function.ldcheck_problem_types = {} |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
66 | new_type = ProblemType(name = problem_name, **args) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
67 | function.ldcheck_problem_types[problem_name] = new_type |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
68 | return function |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
69 | return wrapper |
16 | 70 | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
71 | def report_problem(problem_name, *, bad_object, **args): |
65 | 72 | ''' |
73 | Called from test functions to report issues. This gets later mapped | |
74 | into Problem objects. | |
75 | ''' | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
76 | return {'type': problem_name, 'bad-object': bad_object, 'args': args} |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
77 | |
37
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
78 | def name_of_package(package): |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
79 | if isinstance(package, tuple): |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
80 | return package[1] |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
81 | else: |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
82 | return package.name |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
83 | |
16 | 84 | def test_discovery(): |
85 | ''' | |
86 | Finds all test modules and yields their names. | |
87 | ''' | |
88 | from pkgutil import walk_packages | |
89 | import tests | |
90 | yield from sorted( | |
37
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
91 | 'tests.' + name_of_package(result) |
16 | 92 | for result in walk_packages(tests.__path__) |
93 | ) | |
94 | ||
95 | def load_tests(): | |
96 | ''' | |
97 | Imports test modules and combines their manifests into a test suite. | |
98 | ''' | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
99 | test_suite = {'tests': []} |
16 | 100 | for module_name in test_discovery(): |
101 | from importlib import import_module | |
102 | module = import_module(module_name) | |
103 | if hasattr(module, 'manifest'): | |
104 | # Merge the data from the manifest | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
105 | test_suite['tests'] += module.manifest['tests'] |
16 | 106 | else: |
107 | warn(str.format('Module {} does not have a manifest', module_name)) | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
108 | test_suite['tests'].sort(key = lambda f: f.__name__) |
16 | 109 | return test_suite |
110 | ||
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
111 | def problem_key(problem): |
65 | 112 | ''' |
113 | Sorts problems by rank and line number. | |
114 | ''' | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
115 | rank = ProblemType.severities.index(problem.severity) # sort by severity |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
116 | return (rank, problem.line_number) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
117 | |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
118 | def build_problem(test_function, problem_params): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
119 | problem_name = problem_params['type'] |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
120 | problem_type = test_function.ldcheck_problem_types[problem_name] |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
121 | problem_object = problem_type( |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
122 | bad_object = problem_params['bad-object'], |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
123 | **problem_params['args'], |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
124 | ) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
125 | return problem_object |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
126 | |
17 | 127 | def check_model(model, test_suite = None): |
65 | 128 | ''' |
129 | Runs the test suite on the model and prepares a report. | |
130 | ''' | |
17 | 131 | if not test_suite: |
132 | test_suite = load_tests() | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
133 | problems = [] |
17 | 134 | line_numbers = { |
47
4da025d0b283
added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
37
diff
changeset
|
135 | element: (i, i + 1) |
17 | 136 | for i, element in enumerate(model.body) |
137 | } | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
138 | for test_function in test_suite['tests']: |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
139 | for problem_params in test_function(model): |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
140 | problem = build_problem(test_function, problem_params) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
141 | # add line numbers to the problem |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
142 | problem.body_index, problem.line_number \ |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
143 | = line_numbers[problem.object] |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
144 | problem.object = None |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
145 | problems.append(problem) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
146 | return { |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
147 | 'passed': not any( |
64
1c0884f5506e
changed severity names to be better understood
Teemu Piippo <teemu@hecknology.net>
parents:
63
diff
changeset
|
148 | problem.severity == 'hold' |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
149 | for problem in problems |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
150 | ), |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
151 | 'problems': sorted(problems, key = problem_key), |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
152 | } |
17 | 153 | |
63
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
154 | def iterate_problems(test_suite): |
65 | 155 | ''' |
156 | Yields all problem types. | |
157 | ''' | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
158 | for test_function in test_suite['tests']: |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
47
diff
changeset
|
159 | yield from test_function.ldcheck_problem_types.values() |
63
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
160 | |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
161 | def all_problem_types(test_suite): |
65 | 162 | ''' |
163 | Returns a sorted list of problem types. | |
164 | ''' | |
63
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
165 | return sorted( |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
166 | iterate_problems(test_suite), |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
167 | key = lambda problem_type: problem_type.name |
8949af6a4279
added the list of issues onto the web frontend
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
168 | ) |