diff options
author | cpopa <devnull@localhost> | 2014-05-02 23:38:49 +0300 |
---|---|---|
committer | cpopa <devnull@localhost> | 2014-05-02 23:38:49 +0300 |
commit | e65c187c17adb9d4dfcd214d483a78c491390f8d (patch) | |
tree | adf6aa92d411ae826535f686982a3ac8c041986f /checkers/variables.py | |
parent | f44c9a1cdcf3c9983a712672e0342cb8dd489f7a (diff) | |
download | pylint-e65c187c17adb9d4dfcd214d483a78c491390f8d.tar.gz |
Emit 'undefined-variable' for undefined names used as metaclasses with Python 3 `metaclass=` syntax.
Diffstat (limited to 'checkers/variables.py')
-rw-r--r-- | checkers/variables.py | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/checkers/variables.py b/checkers/variables.py index dc8d111..75c01cd 100644 --- a/checkers/variables.py +++ b/checkers/variables.py @@ -716,20 +716,54 @@ class VariablesChecker3k(VariablesChecker): # do not check for not used locals here self._to_consume.pop() + @check_messages('undefined-variable') def leave_module(self, node): """ Update consumption analysis variable for metaclasses. """ + module_locals = self._to_consume[0][0] + module_imports = self._to_consume[0][1] + consumed = {} + for klass in node.nodes_of_class(astroid.Class): - if klass._metaclass: - metaclass = klass.metaclass() - module_locals = self._to_consume[0][0] - - if isinstance(klass._metaclass, astroid.Name): - module_locals.pop(klass._metaclass.name, None) - if metaclass: - # if it uses a `metaclass=module.Class` - module_locals.pop(metaclass.root().name, None) + found = metaclass = name = None + metaclass = klass.metaclass() + + # Look the name in the already found locals. + # If it's not found there, look in the module locals + # and in the imported modules. + if isinstance(klass._metaclass, astroid.Name): + name = klass._metaclass.name + elif metaclass: + # if it uses a `metaclass=module.Class` + name = metaclass.root().name + + if name: + found = consumed.setdefault(name, + module_locals.get(name, module_imports.get(name)) + ) + + if found is None: + name = None + if metaclass: + name = metaclass.name + elif isinstance(klass._metaclass, astroid.Name): + name = klass._metaclass.name + elif isinstance(klass._metaclass, astroid.Getattr): + name = klass._metaclass.as_string() + + if name is not None: + if not (name in astroid.Module.scope_attrs or + is_builtin(name) or + name in self.config.additional_builtins or + name in node.locals): + self.add_message('undefined-variable', + node=klass, + args=(name, )) + # Pop the consumed items, in order to + # avoid having unused-import false positives + for name in consumed: + module_locals.pop(name, None) super(VariablesChecker3k, self).leave_module(node) if sys.version_info >= (3, 0): |