From 2ce2b7a41629842801e5ce84578769ce5ea9a371 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Wed, 7 Oct 2015 11:50:44 -0500 Subject: [PATCH] Detect duplicate globals from basic.py --- ansible_testing/modules.py | 15 ++++++++++++++- ansible_testing/utils.py | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 ansible_testing/utils.py diff --git a/ansible_testing/modules.py b/ansible_testing/modules.py index 67af30ea73..e94cf607a4 100644 --- a/ansible_testing/modules.py +++ b/ansible_testing/modules.py @@ -10,9 +10,11 @@ import sys import argparse from fnmatch import fnmatch +from utils import find_globals from ansible.executor.module_common import REPLACER_WINDOWS from ansible.utils.module_docs import get_docstring, BLACKLIST_MODULES +from ansible.module_utils import basic as module_utils_basic try: from cStringIO import StringIO @@ -22,6 +24,7 @@ except ImportError: BLACKLIST_DIRS = frozenset(('.git',)) INDENT_REGEX = re.compile(r'(^[ \t]*)') +BASIC_RESERVED = frozenset((r for r in dir(module_utils_basic) if r[0] != '_')) class Validator(object): @@ -288,6 +291,14 @@ class ModuleValidator(Validator): if not os.path.isfile(py_path): self.errors.append('Missing python documentation file') + def _find_redeclarations(self): + g = set() + find_globals(g, self.ast.body) + redeclared = BASIC_RESERVED.intersection(g) + if redeclared: + self.warnings.append('Redeclared basic.py variable or ' + 'function: %s' % ', '.join(redeclared)) + def validate(self): super(ModuleValidator, self).validate() @@ -320,7 +331,7 @@ class ModuleValidator(Validator): doc, examples, ret = get_docstring(self.path) trace = sys.stdout.getvalue() sys.stdout = sys_stdout - sys.stderr = sys.stderr + sys.stderr = sys_stderr if trace: self.traces.append(trace) if not bool(doc): @@ -337,6 +348,7 @@ class ModuleValidator(Validator): self._find_module_utils(main) self._find_has_import() self._check_for_tabs() + self._find_redeclarations() if self._powershell_module(): self._find_ps_replacers() @@ -373,6 +385,7 @@ class PythonPackageValidator(Validator): self.errors.append('Ansible module subdirectories must contain an ' '__init__.py') + def re_compile(value): """ Argparse expects things to raise TypeError, re.compile raises an re.error diff --git a/ansible_testing/utils.py b/ansible_testing/utils.py new file mode 100644 index 0000000000..dc5a84e95a --- /dev/null +++ b/ansible_testing/utils.py @@ -0,0 +1,24 @@ +import ast + + +def find_globals(g, tree): + """Uses AST to find globals in an ast tree""" + for child in tree: + if hasattr(child, 'body') and isinstance(child.body, list): + find_globals(g, child.body) + elif isinstance(child, (ast.FunctionDef, ast.ClassDef)): + g.add(child.name) + continue + elif isinstance(child, ast.Assign): + try: + g.add(child.targets[0].id) + except (IndexError, AttributeError): + pass + elif isinstance(child, ast.Import): + g.add(child.names[0].name) + elif isinstance(child, ast.ImportFrom): + for name in child.names: + g_name = name.asname or name.name + if g_name == '*': + continue + g.add(g_name)