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

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

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

Powered by Google App Engine
This is Rietveld 408576698