| 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 |