OLD | NEW |
1 # Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE). | 1 # Copyright (c) 2003-2011 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 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 15 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
16 """variables checkers for Python code | 16 """variables checkers for Python code |
17 """ | 17 """ |
18 import os | 18 |
19 import sys | 19 import sys |
20 from copy import copy | 20 from copy import copy |
21 | 21 |
22 import astroid | 22 from logilab import astng |
23 from astroid import are_exclusive, builtin_lookup, AstroidBuildingException | 23 from logilab.astng import are_exclusive, builtin_lookup, ASTNGBuildingException |
24 | 24 |
25 from logilab.common.modutils import file_from_modpath | 25 from pylint.interfaces import IASTNGChecker |
26 | |
27 from pylint.interfaces import IAstroidChecker | |
28 from pylint.utils import get_global_option | |
29 from pylint.checkers import BaseChecker | 26 from pylint.checkers import BaseChecker |
30 from pylint.checkers.utils import ( | 27 from pylint.checkers.utils import (PYMETHODS, is_ancestor_name, is_builtin, |
31 PYMETHODS, is_ancestor_name, is_builtin, | 28 is_defined_before, is_error, is_func_default, is_func_decorator, |
32 is_defined_before, is_error, is_func_default, is_func_decorator, | 29 assign_parent, check_messages, is_inside_except, clobber_in_except) |
33 assign_parent, check_messages, is_inside_except, clobber_in_except, | |
34 get_all_elements) | |
35 | 30 |
36 | 31 |
37 def in_for_else_branch(parent, stmt): | 32 def in_for_else_branch(parent, stmt): |
38 """Returns True if stmt in inside the else branch for a parent For stmt.""" | 33 """Returns True if stmt in inside the else branch for a parent For stmt.""" |
39 return (isinstance(parent, astroid.For) and | 34 return (isinstance(parent, astng.For) and |
40 any(else_stmt.parent_of(stmt) for else_stmt in parent.orelse)) | 35 any(else_stmt.parent_of(stmt) for else_stmt in parent.orelse)) |
41 | 36 |
42 def overridden_method(klass, name): | 37 def overridden_method(klass, name): |
43 """get overridden method if any""" | 38 """get overridden method if any""" |
44 try: | 39 try: |
45 parent = klass.local_attr_ancestors(name).next() | 40 parent = klass.local_attr_ancestors(name).next() |
46 except (StopIteration, KeyError): | 41 except (StopIteration, KeyError): |
47 return None | 42 return None |
48 try: | 43 try: |
49 meth_node = parent[name] | 44 meth_node = parent[name] |
50 except KeyError: | 45 except KeyError: |
51 # We have found an ancestor defining <name> but it's not in the local | 46 # We have found an ancestor defining <name> but it's not in the local |
52 # dictionary. This may happen with astroid built from living objects. | 47 # dictionary. This may happen with astng built from living objects. |
53 return None | 48 return None |
54 if isinstance(meth_node, astroid.Function): | 49 if isinstance(meth_node, astng.Function): |
55 return meth_node | 50 return meth_node |
56 return None | 51 return None |
57 | 52 |
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 | |
137 | 53 |
138 MSGS = { | 54 MSGS = { |
139 'E0601': ('Using variable %r before assignment', | 55 'E0601': ('Using variable %r before assignment', |
140 'used-before-assignment', | |
141 'Used when a local variable is accessed before it\'s \ | 56 'Used when a local variable is accessed before it\'s \ |
142 assignment.'), | 57 assignment.'), |
143 'E0602': ('Undefined variable %r', | 58 'E0602': ('Undefined variable %r', |
144 'undefined-variable', | |
145 'Used when an undefined variable is accessed.'), | 59 '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__.'), | |
152 'E0611': ('No name %r in module %r', | 60 'E0611': ('No name %r in module %r', |
153 'no-name-in-module', | |
154 'Used when a name cannot be found in a module.'), | 61 'Used when a name cannot be found in a module.'), |
155 | 62 |
156 'W0601': ('Global variable %r undefined at the module level', | 63 'W0601': ('Global variable %r undefined at the module level', |
157 'global-variable-undefined', | |
158 'Used when a variable is defined through the "global" statement \ | 64 'Used when a variable is defined through the "global" statement \ |
159 but the variable is not defined in the module scope.'), | 65 but the variable is not defined in the module scope.'), |
160 'W0602': ('Using global for %r but no assignment is done', | 66 'W0602': ('Using global for %r but no assignment is done', |
161 'global-variable-not-assigned', | |
162 'Used when a variable is defined through the "global" statement \ | 67 'Used when a variable is defined through the "global" statement \ |
163 but no assignment to this variable is done.'), | 68 but no assignment to this variable is done.'), |
164 'W0603': ('Using the global statement', # W0121 | 69 'W0603': ('Using the global statement', # W0121 |
165 'global-statement', | |
166 'Used when you use the "global" statement to update a global \ | 70 'Used when you use the "global" statement to update a global \ |
167 variable. PyLint just try to discourage this \ | 71 variable. PyLint just try to discourage this \ |
168 usage. That doesn\'t mean you can not use it !'), | 72 usage. That doesn\'t mean you can not use it !'), |
169 'W0604': ('Using the global statement at the module level', # W0103 | 73 'W0604': ('Using the global statement at the module level', # W0103 |
170 'global-at-module-level', | |
171 'Used when you use the "global" statement at the module level \ | 74 'Used when you use the "global" statement at the module level \ |
172 since it has no effect'), | 75 since it has no effect'), |
173 'W0611': ('Unused import %s', | 76 'W0611': ('Unused import %s', |
174 'unused-import', | |
175 'Used when an imported module or variable is not used.'), | 77 'Used when an imported module or variable is not used.'), |
176 'W0612': ('Unused variable %r', | 78 'W0612': ('Unused variable %r', |
177 'unused-variable', | |
178 'Used when a variable is defined but not used.'), | 79 'Used when a variable is defined but not used.'), |
179 'W0613': ('Unused argument %r', | 80 'W0613': ('Unused argument %r', |
180 'unused-argument', | |
181 'Used when a function or method argument is not used.'), | 81 'Used when a function or method argument is not used.'), |
182 'W0614': ('Unused import %s from wildcard import', | 82 'W0614': ('Unused import %s from wildcard import', |
183 'unused-wildcard-import', | |
184 'Used when an imported module or variable is not used from a \ | 83 'Used when an imported module or variable is not used from a \ |
185 \'from X import *\' style import.'), | 84 \'from X import *\' style import.'), |
186 | 85 |
187 'W0621': ('Redefining name %r from outer scope (line %s)', | 86 'W0621': ('Redefining name %r from outer scope (line %s)', |
188 'redefined-outer-name', | |
189 'Used when a variable\'s name hide a name defined in the outer \ | 87 'Used when a variable\'s name hide a name defined in the outer \ |
190 scope.'), | 88 scope.'), |
191 'W0622': ('Redefining built-in %r', | 89 'W0622': ('Redefining built-in %r', |
192 'redefined-builtin', | |
193 'Used when a variable or function override a built-in.'), | 90 'Used when a variable or function override a built-in.'), |
194 'W0623': ('Redefining name %r from %s in exception handler', | 91 'W0623': ('Redefining name %r from %s in exception handler', |
195 'redefine-in-handler', | |
196 'Used when an exception handler assigns the exception \ | 92 'Used when an exception handler assigns the exception \ |
197 to an existing name'), | 93 to an existing name'), |
198 | 94 |
199 'W0631': ('Using possibly undefined loop variable %r', | 95 'W0631': ('Using possibly undefined loop variable %r', |
200 'undefined-loop-variable', | |
201 'Used when an loop variable (i.e. defined by a for loop or \ | 96 'Used when an loop variable (i.e. defined by a for loop or \ |
202 a list comprehension or a generator expression) is used outside \ | 97 a list comprehension or a generator expression) is used outside \ |
203 the loop.'), | 98 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 | |
222 } | 99 } |
223 | 100 |
224 class VariablesChecker(BaseChecker): | 101 class VariablesChecker(BaseChecker): |
225 """checks for | 102 """checks for |
226 * unused variables / imports | 103 * unused variables / imports |
227 * undefined variables | 104 * undefined variables |
228 * redefinition of variable from builtins or from an outer scope | 105 * redefinition of variable from builtins or from an outer scope |
229 * use of variable before assignment | 106 * use of variable before assignment |
230 * __all__ consistency | |
231 """ | 107 """ |
232 | 108 |
233 __implements__ = IAstroidChecker | 109 __implements__ = IASTNGChecker |
234 | 110 |
235 name = 'variables' | 111 name = 'variables' |
236 msgs = MSGS | 112 msgs = MSGS |
237 priority = -1 | 113 priority = -1 |
238 options = (("init-import", | 114 options = ( |
| 115 ("init-import", |
239 {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>', | 116 {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>', |
240 'help' : 'Tells whether we should check for unused import in \ | 117 'help' : 'Tells whether we should check for unused import in \ |
241 __init__ files.'}), | 118 __init__ files.'}), |
242 ("dummy-variables-rgx", | 119 ("dummy-variables-rgx", |
243 {'default': ('_$|dummy'), | 120 {'default': ('_|dummy'), |
244 'type' :'regexp', 'metavar' : '<regexp>', | 121 'type' :'regexp', 'metavar' : '<regexp>', |
245 'help' : 'A regular expression matching the name of dummy \ | 122 'help' : 'A regular expression matching the beginning of \ |
246 variables (i.e. expectedly not used).'}), | 123 the name of dummy variables (i.e. not used).'}), |
247 ("additional-builtins", | 124 ("additional-builtins", |
248 {'default': (), 'type' : 'csv', | 125 {'default': (), 'type' : 'csv', |
249 'metavar' : '<comma separated list>', | 126 'metavar' : '<comma separated list>', |
250 'help' : 'List of additional names supposed to be defined in \ | 127 'help' : 'List of additional names supposed to be defined in \ |
251 builtins. Remember that you should avoid to define new builtins when possible.' | 128 builtins. Remember that you should avoid to define new builtins when possible.' |
252 }), | 129 }), |
253 ) | 130 ) |
254 def __init__(self, linter=None): | 131 def __init__(self, linter=None): |
255 BaseChecker.__init__(self, linter) | 132 BaseChecker.__init__(self, linter) |
256 self._to_consume = None | 133 self._to_consume = None |
257 self._checking_mod_attr = None | 134 self._checking_mod_attr = None |
| 135 self._vars = None |
258 | 136 |
259 def visit_module(self, node): | 137 def visit_module(self, node): |
260 """visit module : update consumption analysis variable | 138 """visit module : update consumption analysis variable |
261 checks globals doesn't overrides builtins | 139 checks globals doesn't overrides builtins |
262 """ | 140 """ |
263 self._to_consume = [(copy(node.locals), {}, 'module')] | 141 self._to_consume = [(copy(node.locals), {}, 'module')] |
264 for name, stmts in node.locals.iteritems(): | 142 self._vars = [] |
| 143 for name, stmts in node.locals.items(): |
265 if is_builtin(name) and not is_inside_except(stmts[0]): | 144 if is_builtin(name) and not is_inside_except(stmts[0]): |
266 # do not print Redefining builtin for additional builtins | 145 # do not print Redefining builtin for additional builtins |
267 self.add_message('redefined-builtin', args=name, node=stmts[0]) | 146 self.add_message('W0622', args=name, node=stmts[0]) |
268 | 147 |
269 @check_messages('unused-import', 'unused-wildcard-import', 'redefined-builti
n', 'undefined-all-variable', 'invalid-all-object') | 148 @check_messages('W0611', 'W0614') |
270 def leave_module(self, node): | 149 def leave_module(self, node): |
271 """leave module: check globals | 150 """leave module: check globals |
272 """ | 151 """ |
273 assert len(self._to_consume) == 1 | 152 assert len(self._to_consume) == 1 |
274 not_consumed = self._to_consume.pop()[0] | 153 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 | |
314 # don't check unused imports in __init__ files | 154 # don't check unused imports in __init__ files |
315 if not self.config.init_import and node.package: | 155 if not self.config.init_import and node.package: |
316 return | 156 return |
317 for name, stmts in not_consumed.iteritems(): | 157 for name, stmts in not_consumed.items(): |
318 if any(isinstance(stmt, astroid.AssName) | |
319 and isinstance(stmt.ass_type(), astroid.AugAssign) | |
320 for stmt in stmts): | |
321 continue | |
322 stmt = stmts[0] | 158 stmt = stmts[0] |
323 if isinstance(stmt, astroid.Import): | 159 if isinstance(stmt, astng.Import): |
324 self.add_message('unused-import', args=name, node=stmt) | 160 self.add_message('W0611', args=name, node=stmt) |
325 elif isinstance(stmt, astroid.From) and stmt.modname != '__future__'
: | 161 elif isinstance(stmt, astng.From) and stmt.modname != '__future__': |
326 if stmt.names[0][0] == '*': | 162 if stmt.names[0][0] == '*': |
327 self.add_message('unused-wildcard-import', args=name, node=s
tmt) | 163 self.add_message('W0614', args=name, node=stmt) |
328 else: | 164 else: |
329 self.add_message('unused-import', args=name, node=stmt) | 165 self.add_message('W0611', args=name, node=stmt) |
330 del self._to_consume | 166 del self._to_consume |
| 167 del self._vars |
331 | 168 |
332 def visit_class(self, node): | 169 def visit_class(self, node): |
333 """visit class: update consumption analysis variable | 170 """visit class: update consumption analysis variable |
334 """ | 171 """ |
335 self._to_consume.append((copy(node.locals), {}, 'class')) | 172 self._to_consume.append((copy(node.locals), {}, 'class')) |
336 | 173 |
337 def leave_class(self, _): | 174 def leave_class(self, _): |
338 """leave class: update consumption analysis variable | 175 """leave class: update consumption analysis variable |
339 """ | 176 """ |
340 # do not check for not used locals here (no sense) | 177 # do not check for not used locals here (no sense) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 def leave_setcomp(self, _): | 218 def leave_setcomp(self, _): |
382 """leave setcomp: update consumption analysis variable | 219 """leave setcomp: update consumption analysis variable |
383 """ | 220 """ |
384 # do not check for not used locals here | 221 # do not check for not used locals here |
385 self._to_consume.pop() | 222 self._to_consume.pop() |
386 | 223 |
387 def visit_function(self, node): | 224 def visit_function(self, node): |
388 """visit function: update consumption analysis variable and check locals | 225 """visit function: update consumption analysis variable and check locals |
389 """ | 226 """ |
390 self._to_consume.append((copy(node.locals), {}, 'function')) | 227 self._to_consume.append((copy(node.locals), {}, 'function')) |
391 if not (self.linter.is_message_enabled('redefined-outer-name') or | 228 self._vars.append({}) |
392 self.linter.is_message_enabled('redefined-builtin')): | 229 if not set(('W0621', 'W0622')) & self.active_msgs: |
393 return | 230 return |
394 globs = node.root().globals | 231 globs = node.root().globals |
395 for name, stmt in node.items(): | 232 for name, stmt in node.items(): |
396 if is_inside_except(stmt): | 233 if is_inside_except(stmt): |
397 continue | 234 continue |
398 if name in globs and not isinstance(stmt, astroid.Global): | 235 if name in globs and not isinstance(stmt, astng.Global): |
399 line = globs[name][0].fromlineno | 236 line = globs[name][0].lineno |
400 dummy_rgx = self.config.dummy_variables_rgx | 237 self.add_message('W0621', args=(name, line), node=stmt) |
401 if not dummy_rgx.match(name): | |
402 self.add_message('redefined-outer-name', args=(name, line),
node=stmt) | |
403 elif is_builtin(name): | 238 elif is_builtin(name): |
404 # do not print Redefining builtin for additional builtins | 239 # do not print Redefining builtin for additional builtins |
405 self.add_message('redefined-builtin', args=name, node=stmt) | 240 self.add_message('W0622', args=name, node=stmt) |
406 | 241 |
407 def leave_function(self, node): | 242 def leave_function(self, node): |
408 """leave function: check function's locals are consumed""" | 243 """leave function: check function's locals are consumed""" |
409 not_consumed = self._to_consume.pop()[0] | 244 not_consumed = self._to_consume.pop()[0] |
410 if not (self.linter.is_message_enabled('unused-variable') or | 245 self._vars.pop(0) |
411 self.linter.is_message_enabled('unused-argument')): | 246 if not set(('W0612', 'W0613')) & self.active_msgs: |
412 return | 247 return |
413 # don't check arguments of function which are only raising an exception | 248 # don't check arguments of function which are only raising an exception |
414 if is_error(node): | 249 if is_error(node): |
415 return | 250 return |
416 # don't check arguments of abstract methods or within an interface | 251 # don't check arguments of abstract methods or within an interface |
417 is_method = node.is_method() | 252 is_method = node.is_method() |
418 klass = node.parent.frame() | 253 klass = node.parent.frame() |
419 if is_method and (klass.type == 'interface' or node.is_abstract()): | 254 if is_method and (klass.type == 'interface' or node.is_abstract()): |
420 return | 255 return |
421 authorized_rgx = self.config.dummy_variables_rgx | 256 authorized_rgx = self.config.dummy_variables_rgx |
422 called_overridden = False | 257 called_overridden = False |
423 argnames = node.argnames() | 258 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 | |
431 for name, stmts in not_consumed.iteritems(): | 259 for name, stmts in not_consumed.iteritems(): |
432 # ignore some special names specified by user configuration | 260 # ignore some special names specified by user configuration |
433 if authorized_rgx.match(name): | 261 if authorized_rgx.match(name): |
434 continue | 262 continue |
435 # ignore names imported by the global statement | 263 # ignore names imported by the global statement |
436 # FIXME: should only ignore them if it's assigned latter | 264 # FIXME: should only ignore them if it's assigned latter |
437 stmt = stmts[0] | 265 stmt = stmts[0] |
438 if isinstance(stmt, astroid.Global): | 266 if isinstance(stmt, astng.Global): |
439 continue | 267 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 | |
457 # care about functions with unknown argument (builtins) | 268 # care about functions with unknown argument (builtins) |
458 if name in argnames: | 269 if name in argnames: |
459 if is_method: | 270 if is_method: |
460 # don't warn for the first argument of a (non static) method | 271 # don't warn for the first argument of a (non static) method |
461 if node.type != 'staticmethod' and name == argnames[0]: | 272 if node.type != 'staticmethod' and name == argnames[0]: |
462 continue | 273 continue |
463 # don't warn for argument of an overridden method | 274 # don't warn for argument of an overridden method |
464 if not called_overridden: | 275 if not called_overridden: |
465 overridden = overridden_method(klass, node.name) | 276 overridden = overridden_method(klass, node.name) |
466 called_overridden = True | 277 called_overridden = True |
467 if overridden is not None and name in overridden.argnames(): | 278 if overridden is not None and name in overridden.argnames(): |
468 continue | 279 continue |
469 if node.name in PYMETHODS and node.name not in ('__init__',
'__new__'): | 280 if node.name in PYMETHODS and node.name not in ('__init__',
'__new__'): |
470 continue | 281 continue |
471 # don't check callback arguments XXX should be configurable | 282 # don't check callback arguments XXX should be configurable |
472 if node.name.startswith('cb_') or node.name.endswith('_cb'): | 283 if node.name.startswith('cb_') or node.name.endswith('_cb'): |
473 continue | 284 continue |
474 self.add_message('unused-argument', args=name, node=stmt) | 285 self.add_message('W0613', args=name, node=stmt) |
475 else: | 286 else: |
476 if stmt.parent and isinstance(stmt.parent, astroid.Assign): | 287 self.add_message('W0612', args=name, node=stmt) |
477 if name in nonlocal_names: | |
478 continue | |
479 self.add_message('unused-variable', args=name, node=stmt) | |
480 | 288 |
481 @check_messages('global-variable-undefined', 'global-variable-not-assigned',
'global-statement', | 289 @check_messages('W0601', 'W0602', 'W0603', 'W0604', 'W0622') |
482 'global-at-module-level', 'redefined-builtin') | |
483 def visit_global(self, node): | 290 def visit_global(self, node): |
484 """check names imported exists in the global scope""" | 291 """check names imported exists in the global scope""" |
485 frame = node.frame() | 292 frame = node.frame() |
486 if isinstance(frame, astroid.Module): | 293 if isinstance(frame, astng.Module): |
487 self.add_message('global-at-module-level', node=node) | 294 self.add_message('W0604', node=node) |
488 return | 295 return |
489 module = frame.root() | 296 module = frame.root() |
490 default_message = True | 297 default_message = True |
491 for name in node.names: | 298 for name in node.names: |
492 try: | 299 try: |
493 assign_nodes = module.getattr(name) | 300 assign_nodes = module.getattr(name) |
494 except astroid.NotFoundError: | 301 except astng.NotFoundError: |
495 # unassigned global, skip | 302 # unassigned global, skip |
496 assign_nodes = [] | 303 assign_nodes = [] |
497 for anode in assign_nodes: | 304 for anode in assign_nodes: |
498 if anode.parent is None: | 305 if anode.parent is None: |
499 # node returned for builtin attribute such as __file__, | 306 # node returned for builtin attribute such as __file__, |
500 # __doc__, etc... | 307 # __doc__, etc... |
501 continue | 308 continue |
502 if anode.frame() is frame: | 309 if anode.frame() is frame: |
503 # same scope level assignment | 310 # same scope level assignment |
504 break | 311 break |
505 else: | 312 else: |
506 # global but no assignment | 313 # global but no assignment |
507 # Detect imports in the current frame, with the required | 314 self.add_message('W0602', args=name, node=node) |
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) | |
527 default_message = False | 315 default_message = False |
528 if not assign_nodes: | 316 if not assign_nodes: |
529 continue | 317 continue |
530 for anode in assign_nodes: | 318 for anode in assign_nodes: |
531 if anode.parent is None: | 319 if anode.parent is None: |
532 self.add_message('redefined-builtin', args=name, node=node) | 320 self.add_message('W0622', args=name, node=node) |
533 break | 321 break |
534 if anode.frame() is module: | 322 if anode.frame() is module: |
535 # module level assignment | 323 # module level assignment |
536 break | 324 break |
537 else: | 325 else: |
538 # global undefined at the module scope | 326 # global undefined at the module scope |
539 self.add_message('global-variable-undefined', args=name, node=no
de) | 327 self.add_message('W0601', args=name, node=node) |
540 default_message = False | 328 default_message = False |
541 if default_message: | 329 if default_message: |
542 self.add_message('global-statement', node=node) | 330 self.add_message('W0603', 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) | |
570 | 331 |
571 def _loopvar_name(self, node, name): | 332 def _loopvar_name(self, node, name): |
572 # filter variables according to node's scope | 333 # filter variables according to node's scope |
573 # XXX used to filter parents but don't remember why, and removing this | 334 # XXX used to filter parents but don't remember why, and removing this |
574 # fixes a W0631 false positive reported by Paul Hachmann on 2008/12 on | 335 # fixes a W0631 false positive reported by Paul Hachmann on 2008/12 on |
575 # python-projects (added to func_use_for_or_listcomp_var test) | 336 # python-projects (added to func_use_for_or_listcomp_var test) |
576 #astmts = [stmt for stmt in node.lookup(name)[1] | 337 #astmts = [stmt for stmt in node.lookup(name)[1] |
577 # if hasattr(stmt, 'ass_type')] and | 338 # if hasattr(stmt, 'ass_type')] and |
578 # not stmt.statement().parent_of(node)] | 339 # not stmt.statement().parent_of(node)] |
579 if not self.linter.is_message_enabled('undefined-loop-variable'): | 340 if 'W0631' not in self.active_msgs: |
580 return | 341 return |
581 astmts = [stmt for stmt in node.lookup(name)[1] | 342 astmts = [stmt for stmt in node.lookup(name)[1] |
582 if hasattr(stmt, 'ass_type')] | 343 if hasattr(stmt, 'ass_type')] |
583 # filter variables according their respective scope test is_statement | 344 # filter variables according their respective scope test is_statement |
584 # and parent to avoid #74747. This is not a total fix, which would | 345 # and parent to avoid #74747. This is not a total fix, which would |
585 # introduce a mechanism similar to special attribute lookup in | 346 # introduce a mechanism similar to special attribute lookup in |
586 # modules. Also, in order to get correct inference in this case, the | 347 # modules. Also, in order to get correct inference in this case, the |
587 # scope lookup rules would need to be changed to return the initial | 348 # scope lookup rules would need to be changed to return the initial |
588 # assignment (which does not exist in code per se) as well as any later | 349 # assignment (which does not exist in code per se) as well as any later |
589 # modifications. | 350 # modifications. |
590 if not astmts or (astmts[0].is_statement or astmts[0].parent) \ | 351 if not astmts or (astmts[0].is_statement or astmts[0].parent) \ |
591 and astmts[0].statement().parent_of(node): | 352 and astmts[0].statement().parent_of(node): |
592 _astmts = [] | 353 _astmts = [] |
593 else: | 354 else: |
594 _astmts = astmts[:1] | 355 _astmts = astmts[:1] |
595 for i, stmt in enumerate(astmts[1:]): | 356 for i, stmt in enumerate(astmts[1:]): |
596 if (astmts[i].statement().parent_of(stmt) | 357 if (astmts[i].statement().parent_of(stmt) |
597 and not in_for_else_branch(astmts[i].statement(), stmt)): | 358 and not in_for_else_branch(astmts[i].statement(), stmt)): |
598 continue | 359 continue |
599 _astmts.append(stmt) | 360 _astmts.append(stmt) |
600 astmts = _astmts | 361 astmts = _astmts |
601 if len(astmts) == 1: | 362 if len(astmts) == 1: |
602 ass = astmts[0].ass_type() | 363 ass = astmts[0].ass_type() |
603 if isinstance(ass, (astroid.For, astroid.Comprehension, astroid.GenE
xpr)) \ | 364 if isinstance(ass, (astng.For, astng.Comprehension, astng.GenExpr))
\ |
604 and not ass.statement() is node.statement(): | 365 and not ass.statement() is node.statement(): |
605 self.add_message('undefined-loop-variable', args=name, node=node
) | 366 self.add_message('W0631', args=name, node=node) |
606 | 367 |
607 @check_messages('redefine-in-handler') | |
608 def visit_excepthandler(self, node): | 368 def visit_excepthandler(self, node): |
609 for name in get_all_elements(node.name): | 369 clobbering, args = clobber_in_except(node.name) |
610 clobbering, args = clobber_in_except(name) | 370 if clobbering: |
611 if clobbering: | 371 self.add_message('W0623', args=args, node=node) |
612 self.add_message('redefine-in-handler', args=args, node=name) | |
613 | 372 |
614 def visit_assname(self, node): | 373 def visit_assname(self, node): |
615 if isinstance(node.ass_type(), astroid.AugAssign): | 374 if isinstance(node.ass_type(), astng.AugAssign): |
616 self.visit_name(node) | 375 self.visit_name(node) |
617 | 376 |
618 def visit_delname(self, node): | 377 def visit_delname(self, node): |
619 self.visit_name(node) | 378 self.visit_name(node) |
620 | 379 |
621 @check_messages(*(MSGS.keys())) | |
622 def visit_name(self, node): | 380 def visit_name(self, node): |
623 """check that a name is defined if the current scope and doesn't | 381 """check that a name is defined if the current scope and doesn't |
624 redefine a built-in | 382 redefine a built-in |
625 """ | 383 """ |
626 stmt = node.statement() | 384 stmt = node.statement() |
627 if stmt.fromlineno is None: | 385 if stmt.fromlineno is None: |
628 # name node from a astroid built from live code, skip | 386 # name node from a astng built from live code, skip |
629 assert not stmt.root().file.endswith('.py') | 387 assert not stmt.root().file.endswith('.py') |
630 return | 388 return |
631 name = node.name | 389 name = node.name |
632 frame = stmt.scope() | 390 frame = stmt.scope() |
633 # if the name node is used as a function default argument's value or as | 391 # if the name node is used as a function default argument's value or as |
634 # a decorator, then start from the parent frame of the function instead | 392 # a decorator, then start from the parent frame of the function instead |
635 # of the function frame - and thus open an inner class scope | 393 # of the function frame - and thus open an inner class scope |
636 if (is_func_default(node) or is_func_decorator(node) | 394 if (is_func_default(node) or is_func_decorator(node) |
637 or is_ancestor_name(frame, node)): | 395 or is_ancestor_name(frame, node)): |
638 start_index = len(self._to_consume) - 2 | 396 start_index = len(self._to_consume) - 2 |
639 else: | 397 else: |
640 start_index = len(self._to_consume) - 1 | 398 start_index = len(self._to_consume) - 1 |
641 # iterates through parent scopes, from the inner to the outer | 399 # iterates through parent scopes, from the inner to the outer |
642 base_scope_type = self._to_consume[start_index][-1] | 400 base_scope_type = self._to_consume[start_index][-1] |
643 for i in range(start_index, -1, -1): | 401 for i in range(start_index, -1, -1): |
644 to_consume, consumed, scope_type = self._to_consume[i] | 402 to_consume, consumed, scope_type = self._to_consume[i] |
645 # if the current scope is a class scope but it's not the inner | 403 # if the current scope is a class scope but it's not the inner |
646 # scope, ignore it. This prevents to access this scope instead of | 404 # scope, ignore it. This prevents to access this scope instead of |
647 # the globals one in function members when there are some common | 405 # the globals one in function members when there are some common |
648 # names. The only exception is when the starting scope is a | 406 # names. The only exception is when the starting scope is a |
649 # comprehension and its direct outer scope is a class | 407 # comprehension and its direct outer scope is a class |
650 if scope_type == 'class' and i != start_index and not ( | 408 if scope_type == 'class' and i != start_index and not ( |
651 base_scope_type == 'comprehension' and i == start_index-1): | 409 base_scope_type == 'comprehension' and i == start_index-1): |
652 # Detect if we are in a local class scope, as an assignment. | 410 # XXX find a way to handle class scope in a smoother way |
653 # For example, the following is fair game. | 411 continue |
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 | |
661 # the name has already been consumed, only check it's not a loop | 412 # the name has already been consumed, only check it's not a loop |
662 # variable used outside the loop | 413 # variable used outside the loop |
663 if name in consumed: | 414 if name in consumed: |
664 defnode = assign_parent(consumed[name][0]) | |
665 self._check_late_binding_closure(node, defnode, scope_type) | |
666 self._loopvar_name(node, name) | 415 self._loopvar_name(node, name) |
667 break | 416 break |
668 # mark the name as consumed if it's defined in this scope | 417 # mark the name as consumed if it's defined in this scope |
669 # (i.e. no KeyError is raised by "to_consume[name]") | 418 # (i.e. no KeyError is raised by "to_consume[name]") |
670 try: | 419 try: |
671 consumed[name] = to_consume[name] | 420 consumed[name] = to_consume[name] |
672 except KeyError: | 421 except KeyError: |
673 continue | 422 continue |
674 # checks for use before assignment | 423 # checks for use before assignment |
675 defnode = assign_parent(to_consume[name][0]) | 424 defnode = assign_parent(to_consume[name][0]) |
676 if defnode is not None: | 425 if defnode is not None: |
677 self._check_late_binding_closure(node, defnode, scope_type) | |
678 defstmt = defnode.statement() | 426 defstmt = defnode.statement() |
679 defframe = defstmt.frame() | 427 defframe = defstmt.frame() |
680 maybee0601 = True | 428 maybee0601 = True |
681 if not frame is defframe: | 429 if not frame is defframe: |
682 maybee0601 = _detect_global_scope(node, frame, defframe) | 430 maybee0601 = False |
683 elif defframe.parent is None: | 431 elif defframe.parent is None: |
684 # we are at the module level, check the name is not | 432 # we are at the module level, check the name is not |
685 # defined in builtins | 433 # defined in builtins |
686 if name in defframe.scope_attrs or builtin_lookup(name)[1]: | 434 if name in defframe.scope_attrs or builtin_lookup(name)[1]: |
687 maybee0601 = False | 435 maybee0601 = False |
688 else: | 436 else: |
689 # we are in a local scope, check the name is not | 437 # we are in a local scope, check the name is not |
690 # defined in global or builtin scope | 438 # defined in global or builtin scope |
691 if defframe.root().lookup(name)[1]: | 439 if defframe.root().lookup(name)[1]: |
692 maybee0601 = False | 440 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 | |
706 if (maybee0601 | 441 if (maybee0601 |
707 and not is_defined_before(node) | 442 and stmt.fromlineno <= defstmt.fromlineno |
708 and not are_exclusive(stmt, defstmt, ('NameError', | 443 and not is_defined_before(node) |
709 'Exception', | 444 and not are_exclusive(stmt, defstmt, ('NameError', 'Exceptio
n', 'BaseException'))): |
710 'BaseException')))
: | 445 if defstmt is stmt and isinstance(node, (astng.DelName, |
711 if defstmt is stmt and isinstance(node, (astroid.DelName, | 446 astng.AssName)): |
712 astroid.AssName)): | 447 self.add_message('E0602', args=name, node=node) |
713 self.add_message('undefined-variable', args=name, node=n
ode) | |
714 elif self._to_consume[-1][-1] != 'lambda': | 448 elif self._to_consume[-1][-1] != 'lambda': |
715 # E0601 may *not* occurs in lambda scope. | 449 # E0601 may *not* occurs in lambda scope |
716 self.add_message('used-before-assignment', args=name, no
de=node) | 450 self.add_message('E0601', args=name, node=node) |
717 elif self._to_consume[-1][-1] == 'lambda': | 451 if not isinstance(node, astng.AssName): # Aug AssName |
718 # E0601 can occur in class-level scope in lambdas, as in | 452 del to_consume[name] |
719 # the following example: | 453 else: |
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] | 454 del consumed[name] |
738 else: | |
739 del to_consume[name] | |
740 # check it's not a loop variable used outside the loop | 455 # check it's not a loop variable used outside the loop |
741 self._loopvar_name(node, name) | 456 self._loopvar_name(node, name) |
742 break | 457 break |
743 else: | 458 else: |
744 # we have not found the name, if it isn't a builtin, that's an | 459 # we have not found the name, if it isn't a builtin, that's an |
745 # undefined name ! | 460 # undefined name ! |
746 if not (name in astroid.Module.scope_attrs or is_builtin(name) | 461 if not (name in astng.Module.scope_attrs or is_builtin(name) |
747 or name in self.config.additional_builtins): | 462 or name in self.config.additional_builtins): |
748 self.add_message('undefined-variable', args=name, node=node) | 463 self.add_message('E0602', args=name, node=node) |
749 | 464 |
750 @check_messages('no-name-in-module') | 465 @check_messages('E0611') |
751 def visit_import(self, node): | 466 def visit_import(self, node): |
752 """check modules attribute accesses""" | 467 """check modules attribute accesses""" |
753 for name, _ in node.names: | 468 for name, _ in node.names: |
754 parts = name.split('.') | 469 parts = name.split('.') |
755 try: | 470 try: |
756 module = node.infer_name_module(parts[0]).next() | 471 module = node.infer_name_module(parts[0]).next() |
757 except astroid.ResolveError: | 472 except astng.ResolveError: |
758 continue | 473 continue |
759 self._check_module_attrs(node, module, parts[1:]) | 474 self._check_module_attrs(node, module, parts[1:]) |
760 | 475 |
761 @check_messages('no-name-in-module') | 476 @check_messages('E0611') |
762 def visit_from(self, node): | 477 def visit_from(self, node): |
763 """check modules attribute accesses""" | 478 """check modules attribute accesses""" |
764 name_parts = node.modname.split('.') | 479 name_parts = node.modname.split('.') |
765 level = getattr(node, 'level', None) | 480 level = getattr(node, 'level', None) |
766 try: | 481 try: |
767 module = node.root().import_module(name_parts[0], level=level) | 482 module = node.root().import_module(name_parts[0], level=level) |
768 except AstroidBuildingException: | 483 except ASTNGBuildingException: |
769 return | 484 return |
770 except Exception, exc: | 485 except Exception, exc: |
771 print 'Unhandled exception in VariablesChecker:', exc | 486 print 'Unhandled exception in VariablesChecker:', exc |
772 return | 487 return |
773 module = self._check_module_attrs(node, module, name_parts[1:]) | 488 module = self._check_module_attrs(node, module, name_parts[1:]) |
774 if not module: | 489 if not module: |
775 return | 490 return |
776 for name, _ in node.names: | 491 for name, _ in node.names: |
777 if name == '*': | 492 if name == '*': |
778 continue | 493 continue |
779 self._check_module_attrs(node, module, name.split('.')) | 494 self._check_module_attrs(node, module, name.split('.')) |
780 | 495 |
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 | |
830 def _check_module_attrs(self, node, module, module_names): | 496 def _check_module_attrs(self, node, module, module_names): |
831 """check that module_names (list of string) are accessible through the | 497 """check that module_names (list of string) are accessible through the |
832 given module | 498 given module |
833 if the latest access name corresponds to a module, return it | 499 if the latest access name corresponds to a module, return it |
834 """ | 500 """ |
835 assert isinstance(module, astroid.Module), module | 501 assert isinstance(module, astng.Module), module |
836 ignored_modules = get_global_option(self, 'ignored-modules', | |
837 default=[]) | |
838 while module_names: | 502 while module_names: |
839 name = module_names.pop(0) | 503 name = module_names.pop(0) |
840 if name == '__dict__': | 504 if name == '__dict__': |
841 module = None | 505 module = None |
842 break | 506 break |
843 try: | 507 try: |
844 module = module.getattr(name)[0].infer().next() | 508 module = module.getattr(name)[0].infer().next() |
845 if module is astroid.YES: | 509 if module is astng.YES: |
846 return None | 510 return None |
847 except astroid.NotFoundError: | 511 except astng.NotFoundError: |
848 if module.name in ignored_modules: | 512 self.add_message('E0611', args=(name, module.name), node=node) |
849 return None | |
850 self.add_message('no-name-in-module', | |
851 args=(name, module.name), node=node) | |
852 return None | 513 return None |
853 except astroid.InferenceError: | 514 except astng.InferenceError: |
854 return None | 515 return None |
855 if module_names: | 516 if module_names: |
856 # FIXME: other message if name is not the latest part of | 517 # FIXME: other message if name is not the latest part of |
857 # module_names ? | 518 # module_names ? |
858 modname = module and module.name or '__dict__' | 519 modname = module and module.name or '__dict__' |
859 self.add_message('no-name-in-module', node=node, | 520 self.add_message('E0611', node=node, |
860 args=('.'.join(module_names), modname)) | 521 args=('.'.join(module_names), modname)) |
861 return None | 522 return None |
862 if isinstance(module, astroid.Module): | 523 if isinstance(module, astng.Module): |
863 return module | 524 return module |
864 return None | 525 return None |
865 | 526 |
866 | 527 |
867 class VariablesChecker3k(VariablesChecker): | 528 class VariablesChecker3k(VariablesChecker): |
868 '''Modified variables checker for 3k''' | 529 '''Modified variables checker for 3k''' |
869 # listcomp have now also their scope | 530 # listcomp have now also their scope |
870 | 531 |
871 def visit_listcomp(self, node): | 532 def visit_listcomp(self, node): |
872 """visit dictcomp: update consumption analysis variable | 533 """visit dictcomp: update consumption analysis variable |
873 """ | 534 """ |
874 self._to_consume.append((copy(node.locals), {}, 'comprehension')) | 535 self._to_consume.append((copy(node.locals), {}, 'comprehension')) |
875 | 536 |
876 def leave_listcomp(self, _): | 537 def leave_listcomp(self, _): |
877 """leave dictcomp: update consumption analysis variable | 538 """leave dictcomp: update consumption analysis variable |
878 """ | 539 """ |
879 # do not check for not used locals here | 540 # do not check for not used locals here |
880 self._to_consume.pop() | 541 self._to_consume.pop() |
881 | 542 |
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 | |
933 if sys.version_info >= (3, 0): | 543 if sys.version_info >= (3, 0): |
934 VariablesChecker = VariablesChecker3k | 544 VariablesChecker = VariablesChecker3k |
935 | 545 |
936 | 546 |
937 def register(linter): | 547 def register(linter): |
938 """required method to auto register this checker""" | 548 """required method to auto register this checker""" |
939 linter.register_checker(VariablesChecker(linter)) | 549 linter.register_checker(VariablesChecker(linter)) |
OLD | NEW |