closes #77188: support lgc.decorators.classproperty

authorSylvain Thénault <sylvain.thenault@logilab.fr>
changeset579e68649037
branchdefault
phasepublic
hiddenno
parent revision#8354d4e2f92a fix some copyrights
child revision#ae207dfe2aa0 copy context path when cloning inference context, else we may skip undesired inference branches. closes #77187
files modified by this revision
ChangeLog
rebuilder.py
test/unittest_builder.py
# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1317141683 -7200
# Tue Sep 27 18:41:23 2011 +0200
# Node ID 579e686490372724c2c34be27db2014b577ab3c8
# Parent 8354d4e2f92a52c82268c5ff90594da85728cc74
closes #77188: support lgc.decorators.classproperty

diff --git a/ChangeLog b/ChangeLog
@@ -9,10 +9,12 @@
1        google)
2 
3      * #74748: getitem protocal return constant value instead of a Const node
4        (patch by google)
5 
6 +    * #77188: support lgc.decorators.classproperty
7 +
8 
9  2011-07-18  --  0.22.0
10      * added column offset information on nodes (patch by fawce)
11 
12      * #70497: Crash on AttributeError: 'NoneType' object has no attribute '_infer_name'
diff --git a/rebuilder.py b/rebuilder.py
@@ -209,10 +209,12 @@
13                  try:
14                      meth = klass[ass_node.name]
15                      if isinstance(meth, new.Function):
16                          if func_name in ('classmethod', 'staticmethod'):
17                              meth.type = func_name
18 +                        elif func_name == 'classproperty': # see lgc.decorators
19 +                            meth.type = 'classmethod'
20                          meth.extra_decorators.append(newnode.value)
21                  except (AttributeError, KeyError):
22                      continue
23          elif getattr(newnode.targets[0], 'name', None) == '__metaclass__':
24              # XXX check more...
@@ -484,13 +486,15 @@
25                  newnode.type = 'classmethod'
26              else:
27                  newnode.type = 'method'
28          if newnode.decorators is not None:
29              for decorator_expr in newnode.decorators.nodes:
30 -                if isinstance(decorator_expr, new.Name) and \
31 -                       decorator_expr.name in ('classmethod', 'staticmethod'):
32 -                    newnode.type = decorator_expr.name
33 +                if isinstance(decorator_expr, new.Name):
34 +                    if decorator_expr.name in ('classmethod', 'staticmethod'):
35 +                        newnode.type = decorator_expr.name
36 +                    elif decorator_expr.name == 'classproperty':
37 +                        newnode.type = 'classmethod'
38          frame.set_local(newnode.name, newnode)
39          return newnode
40 
41      def visit_genexpr(self, node, parent):
42          """visit a GenExpr node by returning a fresh instance of it"""
diff --git a/test/unittest_builder.py b/test/unittest_builder.py
@@ -578,10 +578,11 @@
43              self.assertEqual(keys, ['a', 'autre', 'b', 'local', 'self'])
44          else:# ListComp variables are no more accessible outside
45              self.assertEqual(len(_locals), 3)
46              self.assertEqual(keys, ['autre', 'local', 'self'])
47 
48 +
49  class ModuleBuildTC(FileBuildTC):
50 
51      def setUp(self):
52          abuilder = builder.ASTNGBuilder()
53          self.module = abuilder.module_build(test_module)
@@ -660,10 +661,24 @@
54          self.assertEqual(nothing, None)
55          self.assertIsInstance(chain, nodes.Const)
56          self.assertEqual(chain.value, 'None')
57 
58 
59 +    def test_lgc_classproperty(self):
60 +        '''test expected values of constants after rebuilding'''
61 +        code = '''
62 +from logilab.common.decorators import classproperty
63 +
64 +class A(object):
65 +    @classproperty
66 +    def hop(cls):
67 +        return None
68 +'''
69 +        astng = self.builder.string_build(code)
70 +        self.assertEqual(astng['A']['hop'].type, 'classmethod')
71 +
72 +
73  if sys.version_info < (3, 0):
74      guess_encoding = builder._guess_encoding
75 
76      class TestGuessEncoding(TestCase):
77