summaryrefslogtreecommitdiff
path: root/checkers/variables.py
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2014-05-02 23:38:49 +0300
committercpopa <devnull@localhost>2014-05-02 23:38:49 +0300
commite65c187c17adb9d4dfcd214d483a78c491390f8d (patch)
treeadf6aa92d411ae826535f686982a3ac8c041986f /checkers/variables.py
parentf44c9a1cdcf3c9983a712672e0342cb8dd489f7a (diff)
downloadpylint-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.py52
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):