Fri, 24 May 2019 15:32:10 +0300
Fix operation under Python 3.4
16 | 1 | from warnings import warn |
2 | ||
3 | def report_element(bad_object, type, error_name, args): | |
12 | 4 | return { |
16 | 5 | 'type': type, |
6 | 'object': bad_object, | |
7 | 'name': error_name, | |
8 | 'args': args, | |
13 | 9 | } |
10 | ||
17 | 11 | def warning(bad_object, error_name, **args): |
16 | 12 | return report_element(bad_object, 'warning', error_name, args) |
13 | ||
17 | 14 | def error(bad_object, error_name, **args): |
16 | 15 | return report_element(bad_object, 'error', error_name, args) |
16 | ||
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
17 | def notice(bad_object, error_name, **args): |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
18 | return report_element(bad_object, 'notice', error_name, args) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
19 | |
37
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
20 | def name_of_package(package): |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
21 | if isinstance(package, tuple): |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
22 | return package[1] |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
23 | else: |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
24 | return package.name |
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
25 | |
16 | 26 | def test_discovery(): |
27 | ''' | |
28 | Finds all test modules and yields their names. | |
29 | ''' | |
30 | from pkgutil import walk_packages | |
31 | import tests | |
32 | yield from sorted( | |
37
e46fa477007b
Fix operation under Python 3.4
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
33 | 'tests.' + name_of_package(result) |
16 | 34 | for result in walk_packages(tests.__path__) |
35 | ) | |
36 | ||
37 | def do_manifest_integrity_checks(test_suite, module): | |
38 | ''' | |
39 | Runs integrity checks on a given module's manifest. | |
40 | ''' | |
41 | def check_for_extra_keys(): | |
42 | extra_keys = module.manifest.keys() - test_suite.keys() | |
43 | if extra_keys: | |
44 | warn(str.format( | |
45 | '{}: extra keys in manifest: {}', | |
46 | module.__name__, | |
47 | ', '.join(map(str, extra_keys)) | |
48 | )) | |
49 | def check_for_manifest_duplicates(): | |
50 | for key in test_suite.keys(): | |
51 | duplicates = module.manifest[key].keys() & test_suite[key].keys() | |
52 | if duplicates: | |
53 | warn(str.format( | |
54 | '{}: redefined {} in manifests: {}', | |
55 | module.__name__, | |
56 | key, | |
57 | duplicates, | |
58 | )) | |
59 | check_for_extra_keys() | |
60 | check_for_manifest_duplicates() | |
61 | ||
62 | def load_tests(): | |
63 | ''' | |
64 | Imports test modules and combines their manifests into a test suite. | |
65 | ''' | |
66 | test_suite = {'tests': {}, 'messages': {}} | |
67 | for module_name in test_discovery(): | |
68 | from importlib import import_module | |
69 | module = import_module(module_name) | |
70 | if hasattr(module, 'manifest'): | |
71 | do_manifest_integrity_checks(test_suite, module) | |
72 | # Merge the data from the manifest | |
73 | for key in module.manifest.keys() & test_suite.keys(): | |
74 | test_suite[key].update(module.manifest[key]) | |
75 | else: | |
76 | warn(str.format('Module {} does not have a manifest', module_name)) | |
77 | return test_suite | |
78 | ||
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
79 | def problem_key(problem): |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
80 | problem_hierarchy = ['error', 'warning', 'notice'] |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
81 | return (problem_hierarchy.index(problem['type']), problem['line-number']) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
82 | |
17 | 83 | def check_model(model, test_suite = None): |
84 | if not test_suite: | |
85 | 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
|
86 | problems = [] |
17 | 87 | line_numbers = { |
88 | element: (i, i + 1 + model.body_offset) | |
89 | for i, element in enumerate(model.body) | |
90 | } | |
91 | for test_name, test_function in test_suite['tests'].items(): | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
92 | for problem in test_function(model): |
17 | 93 | problem['body-index'], problem['line-number'] \ |
94 | = line_numbers[problem['object']] | |
95 | del problem['object'] | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
96 | problems.append(problem) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
97 | return { |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
98 | 'passed': not any( |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
99 | problem['type'] == 'error' |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
100 | 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
|
101 | ), |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
102 | '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
|
103 | } |
17 | 104 | |
29 | 105 | def problem_text(problem, test_suite): |
106 | message = test_suite['messages'][problem['name']] | |
107 | if callable(message): | |
108 | message = message(**problem['args']) | |
109 | return message | |
110 | ||
111 | def format_report_html(report, model, test_suite): | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
112 | messages = [] |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
113 | for problem in report['problems']: |
29 | 114 | ldraw_code = model.body[problem['body-index']].textual_representation() |
115 | message = str.format( | |
116 | '<li class="{problem_type}">{model_name}:{line_number}:' | |
117 | '{problem_type}: {message}<br />{ldraw_code}</li>', | |
118 | model_name = model.name, | |
119 | line_number = problem['line-number'], | |
120 | problem_type = problem['type'], | |
121 | message = problem_text(problem, test_suite), | |
122 | ldraw_code = ldraw_code, | |
123 | ) | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
124 | messages.append(message) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
125 | return '\n'.join(messages) |
29 | 126 | |
17 | 127 | def format_report(report, model, test_suite): |
18 | 128 | import colorama |
129 | colorama.init() | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
130 | messages = [] |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
131 | for problem in report['problems']: |
18 | 132 | if problem['type'] == 'error': |
133 | text_colour = colorama.Fore.LIGHTRED_EX | |
134 | elif problem['type'] == 'warning': | |
135 | text_colour = colorama.Fore.LIGHTYELLOW_EX | |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
136 | elif problem['type'] == 'notice': |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
137 | text_colour = colorama.Fore.LIGHTBLUE_EX |
18 | 138 | else: |
139 | text_colour = '' | |
19 | 140 | ldraw_code = model.body[problem['body-index']].textual_representation() |
17 | 141 | message = str.format( |
18 | 142 | '{text_colour}{model_name}:{line_number}: {problem_type}: {message}' |
19 | 143 | '{colour_reset}\n\t{ldraw_code}', |
18 | 144 | text_colour = text_colour, |
145 | model_name = model.name, | |
146 | line_number = problem['line-number'], | |
147 | problem_type = problem['type'], | |
29 | 148 | message = problem_text(problem, test_suite), |
18 | 149 | colour_reset = colorama.Fore.RESET, |
19 | 150 | ldraw_code = ldraw_code, |
17 | 151 | ) |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
152 | messages.append(message) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
29
diff
changeset
|
153 | return '\n'.join(messages) |
17 | 154 | |
16 | 155 | if __name__ == '__main__': |
156 | from pprint import pprint | |
157 | pprint(load_tests()) |