Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: third_party/pylint/checkers/variables.py

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/pylint/checkers/utils.py ('k') | third_party/pylint/config.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # 3 #
4 # This program is free software; you can redistribute it and/or modify it under 4 # This program is free software; you can redistribute it and/or modify it under
5 # the terms of the GNU General Public License as published by the Free Software 5 # the terms of the GNU General Public License as published by the Free Software
6 # Foundation; either version 2 of the License, or (at your option) any later 6 # Foundation; either version 2 of the License, or (at your option) any later
7 # version. 7 # version.
8 # 8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT 9 # This program is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License along with 13 # You should have received a copy of the GNU General Public License along with
14 # this program; if not, write to the Free Software Foundation, Inc., 14 # this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 """variables checkers for Python code 16 """variables checkers for Python code
17 """ 17 """
18 18 import os
19 import sys 19 import sys
20 from copy import copy 20 from copy import copy
21 21
22 from logilab import astng 22 import astroid
23 from logilab.astng import are_exclusive, builtin_lookup, ASTNGBuildingException 23 from astroid import are_exclusive, builtin_lookup, AstroidBuildingException
24 24
25 from pylint.interfaces import IASTNGChecker 25 from logilab.common.modutils import file_from_modpath
26
27 from pylint.interfaces import IAstroidChecker
28 from pylint.utils import get_global_option
26 from pylint.checkers import BaseChecker 29 from pylint.checkers import BaseChecker
27 from pylint.checkers.utils import (PYMETHODS, is_ancestor_name, is_builtin, 30 from pylint.checkers.utils import (
28 is_defined_before, is_error, is_func_default, is_func_decorator, 31 PYMETHODS, is_ancestor_name, is_builtin,
29 assign_parent, check_messages, is_inside_except, clobber_in_except) 32 is_defined_before, is_error, is_func_default, is_func_decorator,
33 assign_parent, check_messages, is_inside_except, clobber_in_except,
34 get_all_elements)
30 35
31 36
32 def in_for_else_branch(parent, stmt): 37 def in_for_else_branch(parent, stmt):
33 """Returns True if stmt in inside the else branch for a parent For stmt.""" 38 """Returns True if stmt in inside the else branch for a parent For stmt."""
34 return (isinstance(parent, astng.For) and 39 return (isinstance(parent, astroid.For) and
35 any(else_stmt.parent_of(stmt) for else_stmt in parent.orelse)) 40 any(else_stmt.parent_of(stmt) for else_stmt in parent.orelse))
36 41
37 def overridden_method(klass, name): 42 def overridden_method(klass, name):
38 """get overridden method if any""" 43 """get overridden method if any"""
39 try: 44 try:
40 parent = klass.local_attr_ancestors(name).next() 45 parent = klass.local_attr_ancestors(name).next()
41 except (StopIteration, KeyError): 46 except (StopIteration, KeyError):
42 return None 47 return None
43 try: 48 try:
44 meth_node = parent[name] 49 meth_node = parent[name]
45 except KeyError: 50 except KeyError:
46 # We have found an ancestor defining <name> but it's not in the local 51 # We have found an ancestor defining <name> but it's not in the local
47 # dictionary. This may happen with astng built from living objects. 52 # dictionary. This may happen with astroid built from living objects.
48 return None 53 return None
49 if isinstance(meth_node, astng.Function): 54 if isinstance(meth_node, astroid.Function):
50 return meth_node 55 return meth_node
51 return None 56 return None
52 57
58 def _get_unpacking_extra_info(node, infered):
59 """return extra information to add to the message for unpacking-non-sequence
60 and unbalanced-tuple-unpacking errors
61 """
62 more = ''
63 infered_module = infered.root().name
64 if node.root().name == infered_module:
65 if node.lineno == infered.lineno:
66 more = ' %s' % infered.as_string()
67 elif infered.lineno:
68 more = ' defined at line %s' % infered.lineno
69 elif infered.lineno:
70 more = ' defined at line %s of %s' % (infered.lineno, infered_module)
71 return more
72
73 def _detect_global_scope(node, frame, defframe):
74 """ Detect that the given frames shares a global
75 scope.
76
77 Two frames shares a global scope when neither
78 of them are hidden under a function scope, as well
79 as any of parent scope of them, until the root scope.
80 In this case, depending from something defined later on
81 will not work, because it is still undefined.
82
83 Example:
84 class A:
85 # B has the same global scope as `C`, leading to a NameError.
86 class B(C): ...
87 class C: ...
88
89 """
90 def_scope = scope = None
91 if frame and frame.parent:
92 scope = frame.parent.scope()
93 if defframe and defframe.parent:
94 def_scope = defframe.parent.scope()
95 if isinstance(frame, astroid.Function):
96 # If the parent of the current node is a
97 # function, then it can be under its scope
98 # (defined in, which doesn't concern us) or
99 # the `->` part of annotations. The same goes
100 # for annotations of function arguments, they'll have
101 # their parent the Arguments node.
102 if not isinstance(node.parent,
103 (astroid.Function, astroid.Arguments)):
104 return False
105 elif any(not isinstance(f, (astroid.Class, astroid.Module))
106 for f in (frame, defframe)):
107 # Not interested in other frames, since they are already
108 # not in a global scope.
109 return False
110
111 break_scopes = []
112 for s in (scope, def_scope):
113 # Look for parent scopes. If there is anything different
114 # than a module or a class scope, then they frames don't
115 # share a global scope.
116 parent_scope = s
117 while parent_scope:
118 if not isinstance(parent_scope, (astroid.Class, astroid.Module)):
119 break_scopes.append(parent_scope)
120 break
121 if parent_scope.parent:
122 parent_scope = parent_scope.parent.scope()
123 else:
124 break
125 if break_scopes and len(set(break_scopes)) != 1:
126 # Store different scopes than expected.
127 # If the stored scopes are, in fact, the very same, then it means
128 # that the two frames (frame and defframe) shares the same scope,
129 # and we could apply our lineno analysis over them.
130 # For instance, this works when they are inside a function, the node
131 # that uses a definition and the definition itself.
132 return False
133 # At this point, we are certain that frame and defframe shares a scope
134 # and the definition of the first depends on the second.
135 return frame.lineno < defframe.lineno
136
53 137
54 MSGS = { 138 MSGS = {
55 'E0601': ('Using variable %r before assignment', 139 'E0601': ('Using variable %r before assignment',
140 'used-before-assignment',
56 'Used when a local variable is accessed before it\'s \ 141 'Used when a local variable is accessed before it\'s \
57 assignment.'), 142 assignment.'),
58 'E0602': ('Undefined variable %r', 143 'E0602': ('Undefined variable %r',
144 'undefined-variable',
59 'Used when an undefined variable is accessed.'), 145 'Used when an undefined variable is accessed.'),
146 'E0603': ('Undefined variable name %r in __all__',
147 'undefined-all-variable',
148 'Used when an undefined variable name is referenced in __all__.'),
149 'E0604': ('Invalid object %r in __all__, must contain only strings',
150 'invalid-all-object',
151 'Used when an invalid (non-string) object occurs in __all__.'),
60 'E0611': ('No name %r in module %r', 152 'E0611': ('No name %r in module %r',
153 'no-name-in-module',
61 'Used when a name cannot be found in a module.'), 154 'Used when a name cannot be found in a module.'),
62 155
63 'W0601': ('Global variable %r undefined at the module level', 156 'W0601': ('Global variable %r undefined at the module level',
157 'global-variable-undefined',
64 'Used when a variable is defined through the "global" statement \ 158 'Used when a variable is defined through the "global" statement \
65 but the variable is not defined in the module scope.'), 159 but the variable is not defined in the module scope.'),
66 'W0602': ('Using global for %r but no assignment is done', 160 'W0602': ('Using global for %r but no assignment is done',
161 'global-variable-not-assigned',
67 'Used when a variable is defined through the "global" statement \ 162 'Used when a variable is defined through the "global" statement \
68 but no assignment to this variable is done.'), 163 but no assignment to this variable is done.'),
69 'W0603': ('Using the global statement', # W0121 164 'W0603': ('Using the global statement', # W0121
165 'global-statement',
70 'Used when you use the "global" statement to update a global \ 166 'Used when you use the "global" statement to update a global \
71 variable. PyLint just try to discourage this \ 167 variable. PyLint just try to discourage this \
72 usage. That doesn\'t mean you can not use it !'), 168 usage. That doesn\'t mean you can not use it !'),
73 'W0604': ('Using the global statement at the module level', # W0103 169 'W0604': ('Using the global statement at the module level', # W0103
170 'global-at-module-level',
74 'Used when you use the "global" statement at the module level \ 171 'Used when you use the "global" statement at the module level \
75 since it has no effect'), 172 since it has no effect'),
76 'W0611': ('Unused import %s', 173 'W0611': ('Unused import %s',
174 'unused-import',
77 'Used when an imported module or variable is not used.'), 175 'Used when an imported module or variable is not used.'),
78 'W0612': ('Unused variable %r', 176 'W0612': ('Unused variable %r',
177 'unused-variable',
79 'Used when a variable is defined but not used.'), 178 'Used when a variable is defined but not used.'),
80 'W0613': ('Unused argument %r', 179 'W0613': ('Unused argument %r',
180 'unused-argument',
81 'Used when a function or method argument is not used.'), 181 'Used when a function or method argument is not used.'),
82 'W0614': ('Unused import %s from wildcard import', 182 'W0614': ('Unused import %s from wildcard import',
183 'unused-wildcard-import',
83 'Used when an imported module or variable is not used from a \ 184 'Used when an imported module or variable is not used from a \
84 \'from X import *\' style import.'), 185 \'from X import *\' style import.'),
85 186
86 'W0621': ('Redefining name %r from outer scope (line %s)', 187 'W0621': ('Redefining name %r from outer scope (line %s)',
188 'redefined-outer-name',
87 'Used when a variable\'s name hide a name defined in the outer \ 189 'Used when a variable\'s name hide a name defined in the outer \
88 scope.'), 190 scope.'),
89 'W0622': ('Redefining built-in %r', 191 'W0622': ('Redefining built-in %r',
192 'redefined-builtin',
90 'Used when a variable or function override a built-in.'), 193 'Used when a variable or function override a built-in.'),
91 'W0623': ('Redefining name %r from %s in exception handler', 194 'W0623': ('Redefining name %r from %s in exception handler',
195 'redefine-in-handler',
92 'Used when an exception handler assigns the exception \ 196 'Used when an exception handler assigns the exception \
93 to an existing name'), 197 to an existing name'),
94 198
95 'W0631': ('Using possibly undefined loop variable %r', 199 'W0631': ('Using possibly undefined loop variable %r',
200 'undefined-loop-variable',
96 'Used when an loop variable (i.e. defined by a for loop or \ 201 'Used when an loop variable (i.e. defined by a for loop or \
97 a list comprehension or a generator expression) is used outside \ 202 a list comprehension or a generator expression) is used outside \
98 the loop.'), 203 the loop.'),
204
205 'W0632': ('Possible unbalanced tuple unpacking with '
206 'sequence%s: '
207 'left side has %d label(s), right side has %d value(s)',
208 'unbalanced-tuple-unpacking',
209 'Used when there is an unbalanced tuple unpacking in assignment'),
210
211 'W0633': ('Attempting to unpack a non-sequence%s',
212 'unpacking-non-sequence',
213 'Used when something which is not '
214 'a sequence is used in an unpack assignment'),
215
216 'W0640': ('Cell variable %s defined in loop',
217 'cell-var-from-loop',
218 'A variable used in a closure is defined in a loop. '
219 'This will result in all closures using the same value for '
220 'the closed-over variable.'),
221
99 } 222 }
100 223
101 class VariablesChecker(BaseChecker): 224 class VariablesChecker(BaseChecker):
102 """checks for 225 """checks for
103 * unused variables / imports 226 * unused variables / imports
104 * undefined variables 227 * undefined variables
105 * redefinition of variable from builtins or from an outer scope 228 * redefinition of variable from builtins or from an outer scope
106 * use of variable before assignment 229 * use of variable before assignment
230 * __all__ consistency
107 """ 231 """
108 232
109 __implements__ = IASTNGChecker 233 __implements__ = IAstroidChecker
110 234
111 name = 'variables' 235 name = 'variables'
112 msgs = MSGS 236 msgs = MSGS
113 priority = -1 237 priority = -1
114 options = ( 238 options = (("init-import",
115 ("init-import",
116 {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>', 239 {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>',
117 'help' : 'Tells whether we should check for unused import in \ 240 'help' : 'Tells whether we should check for unused import in \
118 __init__ files.'}), 241 __init__ files.'}),
119 ("dummy-variables-rgx", 242 ("dummy-variables-rgx",
120 {'default': ('_|dummy'), 243 {'default': ('_$|dummy'),
121 'type' :'regexp', 'metavar' : '<regexp>', 244 'type' :'regexp', 'metavar' : '<regexp>',
122 'help' : 'A regular expression matching the beginning of \ 245 'help' : 'A regular expression matching the name of dummy \
123 the name of dummy variables (i.e. not used).'}), 246 variables (i.e. expectedly not used).'}),
124 ("additional-builtins", 247 ("additional-builtins",
125 {'default': (), 'type' : 'csv', 248 {'default': (), 'type' : 'csv',
126 'metavar' : '<comma separated list>', 249 'metavar' : '<comma separated list>',
127 'help' : 'List of additional names supposed to be defined in \ 250 'help' : 'List of additional names supposed to be defined in \
128 builtins. Remember that you should avoid to define new builtins when possible.' 251 builtins. Remember that you should avoid to define new builtins when possible.'
129 }), 252 }),
130 ) 253 )
131 def __init__(self, linter=None): 254 def __init__(self, linter=None):
132 BaseChecker.__init__(self, linter) 255 BaseChecker.__init__(self, linter)
133 self._to_consume = None 256 self._to_consume = None
134 self._checking_mod_attr = None 257 self._checking_mod_attr = None
135 self._vars = None
136 258
137 def visit_module(self, node): 259 def visit_module(self, node):
138 """visit module : update consumption analysis variable 260 """visit module : update consumption analysis variable
139 checks globals doesn't overrides builtins 261 checks globals doesn't overrides builtins
140 """ 262 """
141 self._to_consume = [(copy(node.locals), {}, 'module')] 263 self._to_consume = [(copy(node.locals), {}, 'module')]
142 self._vars = [] 264 for name, stmts in node.locals.iteritems():
143 for name, stmts in node.locals.items():
144 if is_builtin(name) and not is_inside_except(stmts[0]): 265 if is_builtin(name) and not is_inside_except(stmts[0]):
145 # do not print Redefining builtin for additional builtins 266 # do not print Redefining builtin for additional builtins
146 self.add_message('W0622', args=name, node=stmts[0]) 267 self.add_message('redefined-builtin', args=name, node=stmts[0])
147 268
148 @check_messages('W0611', 'W0614') 269 @check_messages('unused-import', 'unused-wildcard-import', 'redefined-builti n', 'undefined-all-variable', 'invalid-all-object')
149 def leave_module(self, node): 270 def leave_module(self, node):
150 """leave module: check globals 271 """leave module: check globals
151 """ 272 """
152 assert len(self._to_consume) == 1 273 assert len(self._to_consume) == 1
153 not_consumed = self._to_consume.pop()[0] 274 not_consumed = self._to_consume.pop()[0]
275 # attempt to check for __all__ if defined
276 if '__all__' in node.locals:
277 assigned = node.igetattr('__all__').next()
278 if assigned is not astroid.YES:
279 for elt in getattr(assigned, 'elts', ()):
280 try:
281 elt_name = elt.infer().next()
282 except astroid.InferenceError:
283 continue
284
285 if not isinstance(elt_name, astroid.Const) \
286 or not isinstance(elt_name.value, basestring):
287 self.add_message('invalid-all-object', args=elt.as_strin g(), node=elt)
288 continue
289 elt_name = elt_name.value
290 # If elt is in not_consumed, remove it from not_consumed
291 if elt_name in not_consumed:
292 del not_consumed[elt_name]
293 continue
294 if elt_name not in node.locals:
295 if not node.package:
296 self.add_message('undefined-all-variable',
297 args=elt_name,
298 node=elt)
299 else:
300 basename = os.path.splitext(node.file)[0]
301 if os.path.basename(basename) == '__init__':
302 name = node.name + "." + elt_name
303 try:
304 file_from_modpath(name.split("."))
305 except ImportError:
306 self.add_message('undefined-all-variable',
307 args=elt_name,
308 node=elt)
309 except SyntaxError:
310 # don't yield an syntax-error warning,
311 # because it will be later yielded
312 # when the file will be checked
313 pass
154 # don't check unused imports in __init__ files 314 # don't check unused imports in __init__ files
155 if not self.config.init_import and node.package: 315 if not self.config.init_import and node.package:
156 return 316 return
157 for name, stmts in not_consumed.items(): 317 for name, stmts in not_consumed.iteritems():
318 if any(isinstance(stmt, astroid.AssName)
319 and isinstance(stmt.ass_type(), astroid.AugAssign)
320 for stmt in stmts):
321 continue
158 stmt = stmts[0] 322 stmt = stmts[0]
159 if isinstance(stmt, astng.Import): 323 if isinstance(stmt, astroid.Import):
160 self.add_message('W0611', args=name, node=stmt) 324 self.add_message('unused-import', args=name, node=stmt)
161 elif isinstance(stmt, astng.From) and stmt.modname != '__future__': 325 elif isinstance(stmt, astroid.From) and stmt.modname != '__future__' :
162 if stmt.names[0][0] == '*': 326 if stmt.names[0][0] == '*':
163 self.add_message('W0614', args=name, node=stmt) 327 self.add_message('unused-wildcard-import', args=name, node=s tmt)
164 else: 328 else:
165 self.add_message('W0611', args=name, node=stmt) 329 self.add_message('unused-import', args=name, node=stmt)
166 del self._to_consume 330 del self._to_consume
167 del self._vars
168 331
169 def visit_class(self, node): 332 def visit_class(self, node):
170 """visit class: update consumption analysis variable 333 """visit class: update consumption analysis variable
171 """ 334 """
172 self._to_consume.append((copy(node.locals), {}, 'class')) 335 self._to_consume.append((copy(node.locals), {}, 'class'))
173 336
174 def leave_class(self, _): 337 def leave_class(self, _):
175 """leave class: update consumption analysis variable 338 """leave class: update consumption analysis variable
176 """ 339 """
177 # do not check for not used locals here (no sense) 340 # do not check for not used locals here (no sense)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 def leave_setcomp(self, _): 381 def leave_setcomp(self, _):
219 """leave setcomp: update consumption analysis variable 382 """leave setcomp: update consumption analysis variable
220 """ 383 """
221 # do not check for not used locals here 384 # do not check for not used locals here
222 self._to_consume.pop() 385 self._to_consume.pop()
223 386
224 def visit_function(self, node): 387 def visit_function(self, node):
225 """visit function: update consumption analysis variable and check locals 388 """visit function: update consumption analysis variable and check locals
226 """ 389 """
227 self._to_consume.append((copy(node.locals), {}, 'function')) 390 self._to_consume.append((copy(node.locals), {}, 'function'))
228 self._vars.append({}) 391 if not (self.linter.is_message_enabled('redefined-outer-name') or
229 if not set(('W0621', 'W0622')) & self.active_msgs: 392 self.linter.is_message_enabled('redefined-builtin')):
230 return 393 return
231 globs = node.root().globals 394 globs = node.root().globals
232 for name, stmt in node.items(): 395 for name, stmt in node.items():
233 if is_inside_except(stmt): 396 if is_inside_except(stmt):
234 continue 397 continue
235 if name in globs and not isinstance(stmt, astng.Global): 398 if name in globs and not isinstance(stmt, astroid.Global):
236 line = globs[name][0].lineno 399 line = globs[name][0].fromlineno
237 self.add_message('W0621', args=(name, line), node=stmt) 400 dummy_rgx = self.config.dummy_variables_rgx
401 if not dummy_rgx.match(name):
402 self.add_message('redefined-outer-name', args=(name, line), node=stmt)
238 elif is_builtin(name): 403 elif is_builtin(name):
239 # do not print Redefining builtin for additional builtins 404 # do not print Redefining builtin for additional builtins
240 self.add_message('W0622', args=name, node=stmt) 405 self.add_message('redefined-builtin', args=name, node=stmt)
241 406
242 def leave_function(self, node): 407 def leave_function(self, node):
243 """leave function: check function's locals are consumed""" 408 """leave function: check function's locals are consumed"""
244 not_consumed = self._to_consume.pop()[0] 409 not_consumed = self._to_consume.pop()[0]
245 self._vars.pop(0) 410 if not (self.linter.is_message_enabled('unused-variable') or
246 if not set(('W0612', 'W0613')) & self.active_msgs: 411 self.linter.is_message_enabled('unused-argument')):
247 return 412 return
248 # don't check arguments of function which are only raising an exception 413 # don't check arguments of function which are only raising an exception
249 if is_error(node): 414 if is_error(node):
250 return 415 return
251 # don't check arguments of abstract methods or within an interface 416 # don't check arguments of abstract methods or within an interface
252 is_method = node.is_method() 417 is_method = node.is_method()
253 klass = node.parent.frame() 418 klass = node.parent.frame()
254 if is_method and (klass.type == 'interface' or node.is_abstract()): 419 if is_method and (klass.type == 'interface' or node.is_abstract()):
255 return 420 return
256 authorized_rgx = self.config.dummy_variables_rgx 421 authorized_rgx = self.config.dummy_variables_rgx
257 called_overridden = False 422 called_overridden = False
258 argnames = node.argnames() 423 argnames = node.argnames()
424 global_names = set()
425 nonlocal_names = set()
426 for global_stmt in node.nodes_of_class(astroid.Global):
427 global_names.update(set(global_stmt.names))
428 for nonlocal_stmt in node.nodes_of_class(astroid.Nonlocal):
429 nonlocal_names.update(set(nonlocal_stmt.names))
430
259 for name, stmts in not_consumed.iteritems(): 431 for name, stmts in not_consumed.iteritems():
260 # ignore some special names specified by user configuration 432 # ignore some special names specified by user configuration
261 if authorized_rgx.match(name): 433 if authorized_rgx.match(name):
262 continue 434 continue
263 # ignore names imported by the global statement 435 # ignore names imported by the global statement
264 # FIXME: should only ignore them if it's assigned latter 436 # FIXME: should only ignore them if it's assigned latter
265 stmt = stmts[0] 437 stmt = stmts[0]
266 if isinstance(stmt, astng.Global): 438 if isinstance(stmt, astroid.Global):
267 continue 439 continue
440 if isinstance(stmt, (astroid.Import, astroid.From)):
441 # Detect imports, assigned to global statements.
442 if global_names:
443 skip = False
444 for import_name, import_alias in stmt.names:
445 # If the import uses an alias, check only that.
446 # Otherwise, check only the import name.
447 if import_alias:
448 if import_alias in global_names:
449 skip = True
450 break
451 elif import_name in global_names:
452 skip = True
453 break
454 if skip:
455 continue
456
268 # care about functions with unknown argument (builtins) 457 # care about functions with unknown argument (builtins)
269 if name in argnames: 458 if name in argnames:
270 if is_method: 459 if is_method:
271 # don't warn for the first argument of a (non static) method 460 # don't warn for the first argument of a (non static) method
272 if node.type != 'staticmethod' and name == argnames[0]: 461 if node.type != 'staticmethod' and name == argnames[0]:
273 continue 462 continue
274 # don't warn for argument of an overridden method 463 # don't warn for argument of an overridden method
275 if not called_overridden: 464 if not called_overridden:
276 overridden = overridden_method(klass, node.name) 465 overridden = overridden_method(klass, node.name)
277 called_overridden = True 466 called_overridden = True
278 if overridden is not None and name in overridden.argnames(): 467 if overridden is not None and name in overridden.argnames():
279 continue 468 continue
280 if node.name in PYMETHODS and node.name not in ('__init__', '__new__'): 469 if node.name in PYMETHODS and node.name not in ('__init__', '__new__'):
281 continue 470 continue
282 # don't check callback arguments XXX should be configurable 471 # don't check callback arguments XXX should be configurable
283 if node.name.startswith('cb_') or node.name.endswith('_cb'): 472 if node.name.startswith('cb_') or node.name.endswith('_cb'):
284 continue 473 continue
285 self.add_message('W0613', args=name, node=stmt) 474 self.add_message('unused-argument', args=name, node=stmt)
286 else: 475 else:
287 self.add_message('W0612', args=name, node=stmt) 476 if stmt.parent and isinstance(stmt.parent, astroid.Assign):
477 if name in nonlocal_names:
478 continue
479 self.add_message('unused-variable', args=name, node=stmt)
288 480
289 @check_messages('W0601', 'W0602', 'W0603', 'W0604', 'W0622') 481 @check_messages('global-variable-undefined', 'global-variable-not-assigned', 'global-statement',
482 'global-at-module-level', 'redefined-builtin')
290 def visit_global(self, node): 483 def visit_global(self, node):
291 """check names imported exists in the global scope""" 484 """check names imported exists in the global scope"""
292 frame = node.frame() 485 frame = node.frame()
293 if isinstance(frame, astng.Module): 486 if isinstance(frame, astroid.Module):
294 self.add_message('W0604', node=node) 487 self.add_message('global-at-module-level', node=node)
295 return 488 return
296 module = frame.root() 489 module = frame.root()
297 default_message = True 490 default_message = True
298 for name in node.names: 491 for name in node.names:
299 try: 492 try:
300 assign_nodes = module.getattr(name) 493 assign_nodes = module.getattr(name)
301 except astng.NotFoundError: 494 except astroid.NotFoundError:
302 # unassigned global, skip 495 # unassigned global, skip
303 assign_nodes = [] 496 assign_nodes = []
304 for anode in assign_nodes: 497 for anode in assign_nodes:
305 if anode.parent is None: 498 if anode.parent is None:
306 # node returned for builtin attribute such as __file__, 499 # node returned for builtin attribute such as __file__,
307 # __doc__, etc... 500 # __doc__, etc...
308 continue 501 continue
309 if anode.frame() is frame: 502 if anode.frame() is frame:
310 # same scope level assignment 503 # same scope level assignment
311 break 504 break
312 else: 505 else:
313 # global but no assignment 506 # global but no assignment
314 self.add_message('W0602', args=name, node=node) 507 # Detect imports in the current frame, with the required
508 # name. Such imports can be considered assignments.
509 imports = frame.nodes_of_class((astroid.Import, astroid.From))
510 for import_node in imports:
511 found = False
512 for import_name, import_alias in import_node.names:
513 # If the import uses an alias, check only that.
514 # Otherwise, check only the import name.
515 if import_alias:
516 if import_alias == name:
517 found = True
518 break
519 elif import_name and import_name == name:
520 found = True
521 break
522 if found:
523 break
524 else:
525 self.add_message('global-variable-not-assigned',
526 args=name, node=node)
315 default_message = False 527 default_message = False
316 if not assign_nodes: 528 if not assign_nodes:
317 continue 529 continue
318 for anode in assign_nodes: 530 for anode in assign_nodes:
319 if anode.parent is None: 531 if anode.parent is None:
320 self.add_message('W0622', args=name, node=node) 532 self.add_message('redefined-builtin', args=name, node=node)
321 break 533 break
322 if anode.frame() is module: 534 if anode.frame() is module:
323 # module level assignment 535 # module level assignment
324 break 536 break
325 else: 537 else:
326 # global undefined at the module scope 538 # global undefined at the module scope
327 self.add_message('W0601', args=name, node=node) 539 self.add_message('global-variable-undefined', args=name, node=no de)
328 default_message = False 540 default_message = False
329 if default_message: 541 if default_message:
330 self.add_message('W0603', node=node) 542 self.add_message('global-statement', node=node)
543
544 def _check_late_binding_closure(self, node, assignment_node, scope_type):
545 def _is_direct_lambda_call():
546 return (isinstance(node_scope.parent, astroid.CallFunc)
547 and node_scope.parent.func is node_scope)
548
549 node_scope = node.scope()
550 if not isinstance(node_scope, (astroid.Lambda, astroid.Function)):
551 return
552 if isinstance(node.parent, astroid.Arguments):
553 return
554
555 if isinstance(assignment_node, astroid.Comprehension):
556 if assignment_node.parent.parent_of(node.scope()):
557 self.add_message('cell-var-from-loop', node=node, args=node.name )
558 else:
559 assign_scope = assignment_node.scope()
560 maybe_for = assignment_node
561 while not isinstance(maybe_for, astroid.For):
562 if maybe_for is assign_scope:
563 break
564 maybe_for = maybe_for.parent
565 else:
566 if (maybe_for.parent_of(node_scope)
567 and not _is_direct_lambda_call()
568 and not isinstance(node_scope.statement(), astroid.Retur n)):
569 self.add_message('cell-var-from-loop', node=node, args=node. name)
331 570
332 def _loopvar_name(self, node, name): 571 def _loopvar_name(self, node, name):
333 # filter variables according to node's scope 572 # filter variables according to node's scope
334 # XXX used to filter parents but don't remember why, and removing this 573 # XXX used to filter parents but don't remember why, and removing this
335 # fixes a W0631 false positive reported by Paul Hachmann on 2008/12 on 574 # fixes a W0631 false positive reported by Paul Hachmann on 2008/12 on
336 # python-projects (added to func_use_for_or_listcomp_var test) 575 # python-projects (added to func_use_for_or_listcomp_var test)
337 #astmts = [stmt for stmt in node.lookup(name)[1] 576 #astmts = [stmt for stmt in node.lookup(name)[1]
338 # if hasattr(stmt, 'ass_type')] and 577 # if hasattr(stmt, 'ass_type')] and
339 # not stmt.statement().parent_of(node)] 578 # not stmt.statement().parent_of(node)]
340 if 'W0631' not in self.active_msgs: 579 if not self.linter.is_message_enabled('undefined-loop-variable'):
341 return 580 return
342 astmts = [stmt for stmt in node.lookup(name)[1] 581 astmts = [stmt for stmt in node.lookup(name)[1]
343 if hasattr(stmt, 'ass_type')] 582 if hasattr(stmt, 'ass_type')]
344 # filter variables according their respective scope test is_statement 583 # filter variables according their respective scope test is_statement
345 # and parent to avoid #74747. This is not a total fix, which would 584 # and parent to avoid #74747. This is not a total fix, which would
346 # introduce a mechanism similar to special attribute lookup in 585 # introduce a mechanism similar to special attribute lookup in
347 # modules. Also, in order to get correct inference in this case, the 586 # modules. Also, in order to get correct inference in this case, the
348 # scope lookup rules would need to be changed to return the initial 587 # scope lookup rules would need to be changed to return the initial
349 # assignment (which does not exist in code per se) as well as any later 588 # assignment (which does not exist in code per se) as well as any later
350 # modifications. 589 # modifications.
351 if not astmts or (astmts[0].is_statement or astmts[0].parent) \ 590 if not astmts or (astmts[0].is_statement or astmts[0].parent) \
352 and astmts[0].statement().parent_of(node): 591 and astmts[0].statement().parent_of(node):
353 _astmts = [] 592 _astmts = []
354 else: 593 else:
355 _astmts = astmts[:1] 594 _astmts = astmts[:1]
356 for i, stmt in enumerate(astmts[1:]): 595 for i, stmt in enumerate(astmts[1:]):
357 if (astmts[i].statement().parent_of(stmt) 596 if (astmts[i].statement().parent_of(stmt)
358 and not in_for_else_branch(astmts[i].statement(), stmt)): 597 and not in_for_else_branch(astmts[i].statement(), stmt)):
359 continue 598 continue
360 _astmts.append(stmt) 599 _astmts.append(stmt)
361 astmts = _astmts 600 astmts = _astmts
362 if len(astmts) == 1: 601 if len(astmts) == 1:
363 ass = astmts[0].ass_type() 602 ass = astmts[0].ass_type()
364 if isinstance(ass, (astng.For, astng.Comprehension, astng.GenExpr)) \ 603 if isinstance(ass, (astroid.For, astroid.Comprehension, astroid.GenE xpr)) \
365 and not ass.statement() is node.statement(): 604 and not ass.statement() is node.statement():
366 self.add_message('W0631', args=name, node=node) 605 self.add_message('undefined-loop-variable', args=name, node=node )
367 606
607 @check_messages('redefine-in-handler')
368 def visit_excepthandler(self, node): 608 def visit_excepthandler(self, node):
369 clobbering, args = clobber_in_except(node.name) 609 for name in get_all_elements(node.name):
370 if clobbering: 610 clobbering, args = clobber_in_except(name)
371 self.add_message('W0623', args=args, node=node) 611 if clobbering:
612 self.add_message('redefine-in-handler', args=args, node=name)
372 613
373 def visit_assname(self, node): 614 def visit_assname(self, node):
374 if isinstance(node.ass_type(), astng.AugAssign): 615 if isinstance(node.ass_type(), astroid.AugAssign):
375 self.visit_name(node) 616 self.visit_name(node)
376 617
377 def visit_delname(self, node): 618 def visit_delname(self, node):
378 self.visit_name(node) 619 self.visit_name(node)
379 620
621 @check_messages(*(MSGS.keys()))
380 def visit_name(self, node): 622 def visit_name(self, node):
381 """check that a name is defined if the current scope and doesn't 623 """check that a name is defined if the current scope and doesn't
382 redefine a built-in 624 redefine a built-in
383 """ 625 """
384 stmt = node.statement() 626 stmt = node.statement()
385 if stmt.fromlineno is None: 627 if stmt.fromlineno is None:
386 # name node from a astng built from live code, skip 628 # name node from a astroid built from live code, skip
387 assert not stmt.root().file.endswith('.py') 629 assert not stmt.root().file.endswith('.py')
388 return 630 return
389 name = node.name 631 name = node.name
390 frame = stmt.scope() 632 frame = stmt.scope()
391 # if the name node is used as a function default argument's value or as 633 # if the name node is used as a function default argument's value or as
392 # a decorator, then start from the parent frame of the function instead 634 # a decorator, then start from the parent frame of the function instead
393 # of the function frame - and thus open an inner class scope 635 # of the function frame - and thus open an inner class scope
394 if (is_func_default(node) or is_func_decorator(node) 636 if (is_func_default(node) or is_func_decorator(node)
395 or is_ancestor_name(frame, node)): 637 or is_ancestor_name(frame, node)):
396 start_index = len(self._to_consume) - 2 638 start_index = len(self._to_consume) - 2
397 else: 639 else:
398 start_index = len(self._to_consume) - 1 640 start_index = len(self._to_consume) - 1
399 # iterates through parent scopes, from the inner to the outer 641 # iterates through parent scopes, from the inner to the outer
400 base_scope_type = self._to_consume[start_index][-1] 642 base_scope_type = self._to_consume[start_index][-1]
401 for i in range(start_index, -1, -1): 643 for i in range(start_index, -1, -1):
402 to_consume, consumed, scope_type = self._to_consume[i] 644 to_consume, consumed, scope_type = self._to_consume[i]
403 # if the current scope is a class scope but it's not the inner 645 # if the current scope is a class scope but it's not the inner
404 # scope, ignore it. This prevents to access this scope instead of 646 # scope, ignore it. This prevents to access this scope instead of
405 # the globals one in function members when there are some common 647 # the globals one in function members when there are some common
406 # names. The only exception is when the starting scope is a 648 # names. The only exception is when the starting scope is a
407 # comprehension and its direct outer scope is a class 649 # comprehension and its direct outer scope is a class
408 if scope_type == 'class' and i != start_index and not ( 650 if scope_type == 'class' and i != start_index and not (
409 base_scope_type == 'comprehension' and i == start_index-1): 651 base_scope_type == 'comprehension' and i == start_index-1):
410 # XXX find a way to handle class scope in a smoother way 652 # Detect if we are in a local class scope, as an assignment.
411 continue 653 # For example, the following is fair game.
654 # class A:
655 # b = 1
656 # c = lambda b=b: b * b
657 class_assignment = (isinstance(frame, astroid.Class) and
658 name in frame.locals)
659 if not class_assignment:
660 continue
412 # the name has already been consumed, only check it's not a loop 661 # the name has already been consumed, only check it's not a loop
413 # variable used outside the loop 662 # variable used outside the loop
414 if name in consumed: 663 if name in consumed:
664 defnode = assign_parent(consumed[name][0])
665 self._check_late_binding_closure(node, defnode, scope_type)
415 self._loopvar_name(node, name) 666 self._loopvar_name(node, name)
416 break 667 break
417 # mark the name as consumed if it's defined in this scope 668 # mark the name as consumed if it's defined in this scope
418 # (i.e. no KeyError is raised by "to_consume[name]") 669 # (i.e. no KeyError is raised by "to_consume[name]")
419 try: 670 try:
420 consumed[name] = to_consume[name] 671 consumed[name] = to_consume[name]
421 except KeyError: 672 except KeyError:
422 continue 673 continue
423 # checks for use before assignment 674 # checks for use before assignment
424 defnode = assign_parent(to_consume[name][0]) 675 defnode = assign_parent(to_consume[name][0])
425 if defnode is not None: 676 if defnode is not None:
677 self._check_late_binding_closure(node, defnode, scope_type)
426 defstmt = defnode.statement() 678 defstmt = defnode.statement()
427 defframe = defstmt.frame() 679 defframe = defstmt.frame()
428 maybee0601 = True 680 maybee0601 = True
429 if not frame is defframe: 681 if not frame is defframe:
430 maybee0601 = False 682 maybee0601 = _detect_global_scope(node, frame, defframe)
431 elif defframe.parent is None: 683 elif defframe.parent is None:
432 # we are at the module level, check the name is not 684 # we are at the module level, check the name is not
433 # defined in builtins 685 # defined in builtins
434 if name in defframe.scope_attrs or builtin_lookup(name)[1]: 686 if name in defframe.scope_attrs or builtin_lookup(name)[1]:
435 maybee0601 = False 687 maybee0601 = False
436 else: 688 else:
437 # we are in a local scope, check the name is not 689 # we are in a local scope, check the name is not
438 # defined in global or builtin scope 690 # defined in global or builtin scope
439 if defframe.root().lookup(name)[1]: 691 if defframe.root().lookup(name)[1]:
440 maybee0601 = False 692 maybee0601 = False
693 else:
694 # check if we have a nonlocal
695 if name in defframe.locals:
696 maybee0601 = not any(isinstance(child, astroid.Nonlo cal)
697 and name in child.names
698 for child in defframe.get_child ren())
699 if (self._to_consume[-1][-1] == 'lambda' and
700 isinstance(frame, astroid.Class)
701 and name in frame.locals):
702 maybee0601 = True
703 else:
704 maybee0601 = maybee0601 and stmt.fromlineno <= defstmt.froml ineno
705
441 if (maybee0601 706 if (maybee0601
442 and stmt.fromlineno <= defstmt.fromlineno 707 and not is_defined_before(node)
443 and not is_defined_before(node) 708 and not are_exclusive(stmt, defstmt, ('NameError',
444 and not are_exclusive(stmt, defstmt, ('NameError', 'Exceptio n', 'BaseException'))): 709 'Exception',
445 if defstmt is stmt and isinstance(node, (astng.DelName, 710 'BaseException'))) :
446 astng.AssName)): 711 if defstmt is stmt and isinstance(node, (astroid.DelName,
447 self.add_message('E0602', args=name, node=node) 712 astroid.AssName)):
713 self.add_message('undefined-variable', args=name, node=n ode)
448 elif self._to_consume[-1][-1] != 'lambda': 714 elif self._to_consume[-1][-1] != 'lambda':
449 # E0601 may *not* occurs in lambda scope 715 # E0601 may *not* occurs in lambda scope.
450 self.add_message('E0601', args=name, node=node) 716 self.add_message('used-before-assignment', args=name, no de=node)
451 if not isinstance(node, astng.AssName): # Aug AssName 717 elif self._to_consume[-1][-1] == 'lambda':
718 # E0601 can occur in class-level scope in lambdas, as in
719 # the following example:
720 # class A:
721 # x = lambda attr: f + attr
722 # f = 42
723 if isinstance(frame, astroid.Class) and name in frame.lo cals:
724 if isinstance(node.parent, astroid.Arguments):
725 # Doing the following is fine:
726 # class A:
727 # x = 42
728 # y = lambda attr=x: attr
729 if stmt.fromlineno <= defstmt.fromlineno:
730 self.add_message('used-before-assignment',
731 args=name, node=node)
732 else:
733 self.add_message('undefined-variable',
734 args=name, node=node)
735
736 if isinstance(node, astroid.AssName): # Aug AssName
737 del consumed[name]
738 else:
452 del to_consume[name] 739 del to_consume[name]
453 else:
454 del consumed[name]
455 # check it's not a loop variable used outside the loop 740 # check it's not a loop variable used outside the loop
456 self._loopvar_name(node, name) 741 self._loopvar_name(node, name)
457 break 742 break
458 else: 743 else:
459 # we have not found the name, if it isn't a builtin, that's an 744 # we have not found the name, if it isn't a builtin, that's an
460 # undefined name ! 745 # undefined name !
461 if not (name in astng.Module.scope_attrs or is_builtin(name) 746 if not (name in astroid.Module.scope_attrs or is_builtin(name)
462 or name in self.config.additional_builtins): 747 or name in self.config.additional_builtins):
463 self.add_message('E0602', args=name, node=node) 748 self.add_message('undefined-variable', args=name, node=node)
464 749
465 @check_messages('E0611') 750 @check_messages('no-name-in-module')
466 def visit_import(self, node): 751 def visit_import(self, node):
467 """check modules attribute accesses""" 752 """check modules attribute accesses"""
468 for name, _ in node.names: 753 for name, _ in node.names:
469 parts = name.split('.') 754 parts = name.split('.')
470 try: 755 try:
471 module = node.infer_name_module(parts[0]).next() 756 module = node.infer_name_module(parts[0]).next()
472 except astng.ResolveError: 757 except astroid.ResolveError:
473 continue 758 continue
474 self._check_module_attrs(node, module, parts[1:]) 759 self._check_module_attrs(node, module, parts[1:])
475 760
476 @check_messages('E0611') 761 @check_messages('no-name-in-module')
477 def visit_from(self, node): 762 def visit_from(self, node):
478 """check modules attribute accesses""" 763 """check modules attribute accesses"""
479 name_parts = node.modname.split('.') 764 name_parts = node.modname.split('.')
480 level = getattr(node, 'level', None) 765 level = getattr(node, 'level', None)
481 try: 766 try:
482 module = node.root().import_module(name_parts[0], level=level) 767 module = node.root().import_module(name_parts[0], level=level)
483 except ASTNGBuildingException: 768 except AstroidBuildingException:
484 return 769 return
485 except Exception, exc: 770 except Exception, exc:
486 print 'Unhandled exception in VariablesChecker:', exc 771 print 'Unhandled exception in VariablesChecker:', exc
487 return 772 return
488 module = self._check_module_attrs(node, module, name_parts[1:]) 773 module = self._check_module_attrs(node, module, name_parts[1:])
489 if not module: 774 if not module:
490 return 775 return
491 for name, _ in node.names: 776 for name, _ in node.names:
492 if name == '*': 777 if name == '*':
493 continue 778 continue
494 self._check_module_attrs(node, module, name.split('.')) 779 self._check_module_attrs(node, module, name.split('.'))
495 780
781 @check_messages('unbalanced-tuple-unpacking', 'unpacking-non-sequence')
782 def visit_assign(self, node):
783 """Check unbalanced tuple unpacking for assignments
784 and unpacking non-sequences.
785 """
786 if not isinstance(node.targets[0], (astroid.Tuple, astroid.List)):
787 return
788
789 targets = node.targets[0].itered()
790 try:
791 for infered in node.value.infer():
792 self._check_unpacking(infered, node, targets)
793 except astroid.InferenceError:
794 return
795
796 def _check_unpacking(self, infered, node, targets):
797 """ Check for unbalanced tuple unpacking
798 and unpacking non sequences.
799 """
800 if infered is astroid.YES:
801 return
802 if isinstance(infered, (astroid.Tuple, astroid.List)):
803 # attempt to check unpacking is properly balanced
804 values = infered.itered()
805 if len(targets) != len(values):
806 # Check if we have starred nodes.
807 if any(isinstance(target, astroid.Starred)
808 for target in targets):
809 return
810 self.add_message('unbalanced-tuple-unpacking', node=node,
811 args=(_get_unpacking_extra_info(node, infered),
812 len(targets),
813 len(values)))
814 # attempt to check unpacking may be possible (ie RHS is iterable)
815 elif isinstance(infered, astroid.Instance):
816 for meth in ('__iter__', '__getitem__'):
817 try:
818 infered.getattr(meth)
819 break
820 except astroid.NotFoundError:
821 continue
822 else:
823 self.add_message('unpacking-non-sequence', node=node,
824 args=(_get_unpacking_extra_info(node, infered), ))
825 else:
826 self.add_message('unpacking-non-sequence', node=node,
827 args=(_get_unpacking_extra_info(node, infered),))
828
829
496 def _check_module_attrs(self, node, module, module_names): 830 def _check_module_attrs(self, node, module, module_names):
497 """check that module_names (list of string) are accessible through the 831 """check that module_names (list of string) are accessible through the
498 given module 832 given module
499 if the latest access name corresponds to a module, return it 833 if the latest access name corresponds to a module, return it
500 """ 834 """
501 assert isinstance(module, astng.Module), module 835 assert isinstance(module, astroid.Module), module
836 ignored_modules = get_global_option(self, 'ignored-modules',
837 default=[])
502 while module_names: 838 while module_names:
503 name = module_names.pop(0) 839 name = module_names.pop(0)
504 if name == '__dict__': 840 if name == '__dict__':
505 module = None 841 module = None
506 break 842 break
507 try: 843 try:
508 module = module.getattr(name)[0].infer().next() 844 module = module.getattr(name)[0].infer().next()
509 if module is astng.YES: 845 if module is astroid.YES:
510 return None 846 return None
511 except astng.NotFoundError: 847 except astroid.NotFoundError:
512 self.add_message('E0611', args=(name, module.name), node=node) 848 if module.name in ignored_modules:
849 return None
850 self.add_message('no-name-in-module',
851 args=(name, module.name), node=node)
513 return None 852 return None
514 except astng.InferenceError: 853 except astroid.InferenceError:
515 return None 854 return None
516 if module_names: 855 if module_names:
517 # FIXME: other message if name is not the latest part of 856 # FIXME: other message if name is not the latest part of
518 # module_names ? 857 # module_names ?
519 modname = module and module.name or '__dict__' 858 modname = module and module.name or '__dict__'
520 self.add_message('E0611', node=node, 859 self.add_message('no-name-in-module', node=node,
521 args=('.'.join(module_names), modname)) 860 args=('.'.join(module_names), modname))
522 return None 861 return None
523 if isinstance(module, astng.Module): 862 if isinstance(module, astroid.Module):
524 return module 863 return module
525 return None 864 return None
526 865
527 866
528 class VariablesChecker3k(VariablesChecker): 867 class VariablesChecker3k(VariablesChecker):
529 '''Modified variables checker for 3k''' 868 '''Modified variables checker for 3k'''
530 # listcomp have now also their scope 869 # listcomp have now also their scope
531 870
532 def visit_listcomp(self, node): 871 def visit_listcomp(self, node):
533 """visit dictcomp: update consumption analysis variable 872 """visit dictcomp: update consumption analysis variable
534 """ 873 """
535 self._to_consume.append((copy(node.locals), {}, 'comprehension')) 874 self._to_consume.append((copy(node.locals), {}, 'comprehension'))
536 875
537 def leave_listcomp(self, _): 876 def leave_listcomp(self, _):
538 """leave dictcomp: update consumption analysis variable 877 """leave dictcomp: update consumption analysis variable
539 """ 878 """
540 # do not check for not used locals here 879 # do not check for not used locals here
541 self._to_consume.pop() 880 self._to_consume.pop()
542 881
882 def leave_module(self, node):
883 """ Update consumption analysis variable
884 for metaclasses.
885 """
886 module_locals = self._to_consume[0][0]
887 module_imports = self._to_consume[0][1]
888 consumed = {}
889
890 for klass in node.nodes_of_class(astroid.Class):
891 found = metaclass = name = None
892 if not klass._metaclass:
893 # Skip if this class doesn't use
894 # explictly a metaclass, but inherits it from ancestors
895 continue
896
897 metaclass = klass.metaclass()
898
899 # Look the name in the already found locals.
900 # If it's not found there, look in the module locals
901 # and in the imported modules.
902 if isinstance(klass._metaclass, astroid.Name):
903 name = klass._metaclass.name
904 elif metaclass:
905 # if it uses a `metaclass=module.Class`
906 name = metaclass.root().name
907
908 if name:
909 found = consumed.setdefault(
910 name, module_locals.get(name, module_imports.get(name)))
911
912 if found is None and not metaclass:
913 name = None
914 if isinstance(klass._metaclass, astroid.Name):
915 name = klass._metaclass.name
916 elif isinstance(klass._metaclass, astroid.Getattr):
917 name = klass._metaclass.as_string()
918
919 if name is not None:
920 if not (name in astroid.Module.scope_attrs or
921 is_builtin(name) or
922 name in self.config.additional_builtins or
923 name in node.locals):
924 self.add_message('undefined-variable',
925 node=klass,
926 args=(name, ))
927 # Pop the consumed items, in order to
928 # avoid having unused-import false positives
929 for name in consumed:
930 module_locals.pop(name, None)
931 super(VariablesChecker3k, self).leave_module(node)
932
543 if sys.version_info >= (3, 0): 933 if sys.version_info >= (3, 0):
544 VariablesChecker = VariablesChecker3k 934 VariablesChecker = VariablesChecker3k
545 935
546 936
547 def register(linter): 937 def register(linter):
548 """required method to auto register this checker""" 938 """required method to auto register this checker"""
549 linter.register_checker(VariablesChecker(linter)) 939 linter.register_checker(VariablesChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/checkers/utils.py ('k') | third_party/pylint/config.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698