From ddf0474a76a97111bae4efe4d31fd78d18b57862 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Sat, 20 Feb 2016 10:30:13 -0600 Subject: [PATCH] Manipulate YAMLError for docs. Fixes #14 * reference the section the error came from * offset the line number to reference the actual line in the file --- ansible_testing/modules.py | 125 ++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 43 deletions(-) diff --git a/ansible_testing/modules.py b/ansible_testing/modules.py index 18bd281d075..6a7928bf778 100644 --- a/ansible_testing/modules.py +++ b/ansible_testing/modules.py @@ -73,6 +73,7 @@ class Validator(object): ret = [] for trace in self.traces: + print('TRACE:') print(trace) for error in self.errors: print('ERROR: %s' % error) @@ -307,20 +308,94 @@ class ModuleValidator(Validator): self.errors.append('Missing python documentation file') def _get_docs(self): - docs = None - examples = None - ret = None + docs = { + 'DOCUMENTATION': { + 'value': None, + 'lineno': 0 + }, + 'EXAMPLES': { + 'value': None, + 'lineno': 0 + }, + 'RETURN': { + 'value': None, + 'lineno': 0 + } + } for child in self.ast.body: if isinstance(child, ast.Assign): for grandchild in child.targets: if grandchild.id == 'DOCUMENTATION': - docs = child.value.s + docs['DOCUMENTATION']['value'] = child.value.s + docs['DOCUMENTATION']['lineno'] = child.lineno elif grandchild.id == 'EXAMPLES': + docs['EXAMPLES']['value'] = child.value.s[1:] + docs['EXAMPLES']['lineno'] = child.lineno examples = child.value.s[1:] elif grandchild.id == 'RETURN': - ret = child.value.s + docs['RETURN']['value'] = child.value.s + docs['RETURN']['lineno'] = child.lineno - return docs, examples, ret + return docs + + def _validate_docs(self): + sys_stdout = sys.stdout + sys_stderr = sys.stderr + sys.stdout = sys.stderr = buf = StringIO() + # instead of adding noqa to the above, do something with buf + assert buf + setattr(sys.stdout, 'encoding', sys_stdout.encoding) + setattr(sys.stderr, 'encoding', sys_stderr.encoding) + doc_info = self._get_docs() + try: + doc, examples, ret = get_docstring(self.path, verbose=True) + trace = None + except yaml.YAMLError as e: + doc = None + examples = doc_info['EXAMPLES']['value'] + ret = doc_info['RETURN']['value'] + trace = e + finally: + sys.stdout = sys_stdout + sys.stderr = sys_stderr + if trace: + # This offsets the error line number to where the + # DOCUMENTATION starts so we can just go to that line in the + # module + trace.problem_mark.line += ( + doc_info['DOCUMENTATION']['lineno'] - 1 + ) + trace.problem_mark.name = '%s.DOCUMENTATION' % self.name + self.traces.append(trace) + self.errors.append('DOCUMENTATION is not valid YAML. Line %d ' + 'column %d' % + (trace.problem_mark.line + 1, + trace.problem_mark.column + 1)) + if not bool(doc): + self.errors.append('No DOCUMENTATION provided') + else: + self._check_version_added(doc) + self._check_for_new_args(doc) + if not bool(examples): + self.errors.append('No EXAMPLES provided') + if not bool(ret): + if self._is_new_module(): + self.errors.append('No RETURN documentation provided') + else: + self.warnings.append('No RETURN provided') + else: + try: + yaml.safe_load(ret) + except yaml.YAMLError as e: + e.problem_mark.line += ( + doc_info['RETURN']['lineno'] - 1 + ) + e.problem_mark.name = '%s.RETURN' % self.name + self.errors.append('RETURN is not valid YAML. Line %d ' + 'column %d' % + (e.problem_mark.line + 1, + e.problem_mark.column + 1)) + self.traces.append(e) def _find_redeclarations(self): g = set() @@ -411,43 +486,7 @@ class ModuleValidator(Validator): return if self._python_module(): - sys_stdout = sys.stdout - sys_stderr = sys.stderr - sys.stdout = sys.stderr = buf = StringIO() - # instead of adding noqa to the above, do something with buf - assert buf - setattr(sys.stdout, 'encoding', sys_stdout.encoding) - setattr(sys.stderr, 'encoding', sys_stderr.encoding) - try: - doc, examples, ret = get_docstring(self.path, verbose=True) - trace = None - except: - doc = None - _, examples, ret = self._get_docs() - trace = traceback.format_exc() - finally: - sys.stdout = sys_stdout - sys.stderr = sys_stderr - if trace: - self.traces.append(trace) - if not bool(doc): - self.errors.append('Invalid or no DOCUMENTATION provided') - else: - self._check_version_added(doc) - self._check_for_new_args(doc) - if not bool(examples): - self.errors.append('No EXAMPLES provided') - if not bool(ret): - if self._is_new_module(): - self.errors.append('No RETURN documentation provided') - else: - self.warnings.append('No RETURN provided') - else: - try: - yaml.safe_load(ret) - except: - self.errors.append('RETURN is not valid YAML') - self.traces.append(traceback.format_exc()) + self._validate_docs() if self._python_module() and not self._just_docs(): self._check_for_sys_exit()