Fix the variables check to not emit false positives for E0602 on {list,generator} comprehension loop variables inside decorators.

Closes #77982

authorTorsten Marek <tmarek@google.com>
changeset51fb69c78868
branchdefault
phasepublic
hiddenno
parent revision#b0f72604a2d7 don't emit E0202 (attribute hiding a method) on @property methods. Closes #89092
child revision#78fbb02cbd93 Add 'on_set_current_module' event trigerring and event callback for reporters.
files modified by this revision
ChangeLog
checkers/utils.py
test/input/func_undefined_var.py
# HG changeset patch
# User Torsten Marek <tmarek@google.com>
# Date 1331815705 -3600
# Thu Mar 15 13:48:25 2012 +0100
# Node ID 51fb69c78868c58f4dce0cccaa0841cf4dda9928
# Parent b0f72604a2d7fb6b9ee2b0fad726f23c65269641
Fix the variables check to not emit false positives for E0602 on {list,generator} comprehension loop variables inside decorators.
Closes #77982

diff --git a/ChangeLog b/ChangeLog
@@ -1,10 +1,13 @@
1  ChangeLog for PyLint
2  ====================
3 
4  	--
5 
6 +    * #77982 Do not emit E0602 for loop variables of comprehensions
7 +      used as argument values inside a decorator (patch by tmarek@google.com)
8 +
9      * #87192 fix crash when decorators are accessed through more than one dot
10        (for instance @a.b is fine, @a.b.c crash)
11      * #89092: don't emit E0202 (attribute hiding a method) on @property methods
12      * fix potential crashes with utils.safe_infer raising InferenceError
13 
diff --git a/checkers/utils.py b/checkers/utils.py
@@ -18,10 +18,11 @@
14  """some functions that may be useful for various checkers
15  """
16 
17  import string
18  from logilab import astng
19 +from logilab.astng import scoped_nodes
20  from logilab.common.compat import builtins
21  BUILTINS_NAME = builtins.__name__
22 
23  COMP_NODE_TYPES = astng.ListComp, astng.SetComp, astng.DictComp, astng.GenExpr
24 
@@ -167,11 +168,14 @@
25      """return true if the name is used in function decorator"""
26      parent = node.parent
27      while parent is not None:
28          if isinstance(parent, astng.Decorators):
29              return True
30 -        if parent.is_statement or isinstance(parent, astng.Lambda):
31 +        if (parent.is_statement or
32 +            isinstance(parent, astng.Lambda) or
33 +            isinstance(parent, (scoped_nodes.ComprehensionScope,
34 +                                scoped_nodes.ListComp))):
35              break
36          parent = parent.parent
37      return False
38 
39  def is_ancestor_name(frame, node):
diff --git a/test/input/func_undefined_var.py b/test/input/func_undefined_var.py
@@ -65,5 +65,21 @@
40          if xxx == 1:
41              pass
42      else:
43          print xxx
44          xxx = 3
45 +
46 +
47 +def decorator(arg):
48 +    """Decorator with one argument."""
49 +    return lambda: list(arg)
50 +
51 +
52 +@decorator(arg=[i * 2 for i in range(15)])
53 +def func1():
54 +    """A function with a decorator that contains a listcomp."""
55 +    pass
56 +
57 +@decorator(arg=(i * 2 for i in range(15)))
58 +def func2():
59 +    """A function with a decorator that contains a genexpr."""
60 +    pass