OLD | NEW |
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 Loading... |
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)) |
OLD | NEW |