Mon, 22 Jan 2018 17:05:10 +0200
Added code to run the test suite.
from warnings import warn def report_element(bad_object, type, error_name, args): return { 'type': type, 'object': bad_object, 'name': error_name, 'args': args, } def warning(bad_object, error_name, **args): return report_element(bad_object, 'warning', error_name, args) def error(bad_object, error_name, **args): return report_element(bad_object, 'error', error_name, args) def test_discovery(): ''' Finds all test modules and yields their names. ''' from pkgutil import walk_packages import tests yield from sorted( 'tests.' + result.name for result in walk_packages(tests.__path__) ) def do_manifest_integrity_checks(test_suite, module): ''' Runs integrity checks on a given module's manifest. ''' def check_for_extra_keys(): extra_keys = module.manifest.keys() - test_suite.keys() if extra_keys: warn(str.format( '{}: extra keys in manifest: {}', module.__name__, ', '.join(map(str, extra_keys)) )) def check_for_manifest_duplicates(): for key in test_suite.keys(): duplicates = module.manifest[key].keys() & test_suite[key].keys() if duplicates: warn(str.format( '{}: redefined {} in manifests: {}', module.__name__, key, duplicates, )) check_for_extra_keys() check_for_manifest_duplicates() def load_tests(): ''' Imports test modules and combines their manifests into a test suite. ''' test_suite = {'tests': {}, 'messages': {}} for module_name in test_discovery(): from importlib import import_module module = import_module(module_name) if hasattr(module, 'manifest'): do_manifest_integrity_checks(test_suite, module) # Merge the data from the manifest for key in module.manifest.keys() & test_suite.keys(): test_suite[key].update(module.manifest[key]) else: warn(str.format('Module {} does not have a manifest', module_name)) return test_suite def check_model(model, test_suite = None): if not test_suite: test_suite = load_tests() report = [] line_numbers = { element: (i, i + 1 + model.body_offset) for i, element in enumerate(model.body) } for test_name, test_function in test_suite['tests'].items(): problems = test_function(model) for problem in problems: problem['body-index'], problem['line-number'] \ = line_numbers[problem['object']] del problem['object'] report.append(problem) return report def format_report(report, model, test_suite): result = [] for problem in report: problem_text = test_suite['messages'][problem['name']] if callable(problem_text): problem_text = problem_text(**problem['args']) message = str.format( 'Line {}: {}\n\t{}', problem['line-number'], problem_text, model.body[problem['body-index']].original_code ) result.append((problem['line-number'], message)) return '\n'.join( problem[1] for problem in sorted(result) ) if __name__ == '__main__': from pprint import pprint pprint(load_tests())