Do not issue warnings when using 2.6's property.setter/deleter functionality. Closes #50461, #52020 and #51222.

authorSylvain Th?nault <sylvain.thenault@logilab.fr>
changeset869685f9a22d
branchdefault
phasepublic
hiddenno
parent revision#a99af6247286 This patch is an attempt to completely remove the need for all Google-internal patches
child revision#f079c6bb5923 add note about soon useless stream.seek()
files modified by this revision
ChangeLog
checkers/base.py
checkers/typecheck.py
test/input/func_newstyle_property.py
# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1319613834 -7200
# Wed Oct 26 09:23:54 2011 +0200
# Node ID 869685f9a22d1178902aebbbcc1719beb287ce11
# Parent a99af624728686e4eb1b65835b671b486f60fe82
Do not issue warnings when using 2.6's property.setter/deleter functionality. Closes #50461, #52020 and #51222.

diff --git a/ChangeLog b/ChangeLog
@@ -6,10 +6,13 @@
1        existing names (patch by tmarek@google.com)
2 
3      * #81113: Fix W0702 messages appearing with the wrong line number.
4        (patch by tmarek@google.com)
5 
6 +    * #50461, #52020, #51222: Do not issue warnings when using 2.6's
7 +      property.setter/deleter functionality (patch by dneil@google.com)
8 +
9 
10 
11  2011-10-07  --  0.25.0
12      * #74742: make allowed name for first argument of class method configurable
13        (patch by Google)
diff --git a/checkers/base.py b/checkers/base.py
@@ -99,10 +99,26 @@
14          lines += (node_type, str(new), str(old), diff_str,
15                    nice_stats[node_type].get('percent_documented', '0'),
16                    nice_stats[node_type].get('percent_badname', '0'))
17      sect.append(Table(children=lines, cols=6, rheaders=1))
18 
19 +def redefined_by_decorator(node):
20 +    """return True if the object is a method redefined via decorator.
21 +
22 +    For example:
23 +        @property
24 +        def x(self): return self._x
25 +        @x.setter
26 +        def x(self, value): self._x = value
27 +    """
28 +    if node.decorators:
29 +        for decorator in node.decorators.nodes:
30 +            if (isinstance(decorator, astng.Getattr) and
31 +                decorator.expr.name == node.name):
32 +                return True
33 +    return False
34 +
35  class _BasicChecker(BaseChecker):
36      __implements__ = IASTNGChecker
37      name = 'basic'
38 
39  class BasicErrorChecker(_BasicChecker):
@@ -140,11 +156,12 @@
40      def visit_class(self, node):
41          self._check_redefinition('class', node)
42 
43      @check_messages('E0100', 'E0101', 'E0102', 'E0106')
44      def visit_function(self, node):
45 -        self._check_redefinition(node.is_method() and 'method' or 'function', node)
46 +        if not redefined_by_decorator(node):
47 +            self._check_redefinition(node.is_method() and 'method' or 'function', node)
48          # checks for max returns, branch, return in __init__
49          returns = node.nodes_of_class(astng.Return,
50                                        skip_klass=(astng.Function, astng.Class))
51          if node.is_method() and node.name == '__init__':
52              if node.is_generator():
diff --git a/checkers/typecheck.py b/checkers/typecheck.py
@@ -168,10 +168,12 @@
53                      continue
54              except AttributeError:
55                  # XXX method / function
56                  continue
57              except NotFoundError:
58 +                if isinstance(owner, astng.Function) and owner.decorators:
59 +                   continue
60                  if isinstance(owner, Instance) and owner.has_dynamic_getattr():
61                      continue
62                  # explicit skipping of optparse'Values class
63                  if owner.name == 'Values' and owner.root().name == 'optparse':
64                      continue
diff --git a/test/input/func_newstyle_property.py b/test/input/func_newstyle_property.py
@@ -1,7 +1,7 @@
65  # pylint: disable=R0903
66 -"""test property on old style class"""
67 +"""test property on old style class and property.setter/deleter usage"""
68 
69  __revision__ = 1
70 
71  def getter(self):
72      """interesting"""
@@ -15,5 +15,26 @@
73      """bad usage"""
74      method = property(getter, doc='hop')
75 
76      def __init__(self):
77          pass
78 +
79 +class SomeClass(object):
80 +    """another docstring"""
81 +
82 +    def __init__(self):
83 +        self._prop = None
84 +
85 +    @property
86 +    def prop(self):
87 +        """I'm the 'prop' property."""
88 +        return self._prop
89 +
90 +    @prop.setter
91 +    def prop(self, value):
92 +        """I'm the 'prop' property."""
93 +        self._prop = value
94 +
95 +    @prop.deleter
96 +    def prop(self):
97 +        """I'm the 'prop' property."""
98 +        del self._prop