Add support for inference of subscript operations on dict literals. Closes #123074

actually fix Dict.getitem and enhance infer_subscript

authorTorsten Marek <tmarek@google.com>
changeset6e82e28d4a0d
branchstable
phasepublic
hiddenno
parent revision#41db38a1c28e Set literals should be treated as inference leaves. Closes #47957
child revision#5b19a3c5b985 [py3.3] don't crash on 'yield from' nodes. Closes #124360
files modified by this revision
ChangeLog
inference.py
node_classes.py
test/unittest_inference.py
# HG changeset patch
# User Torsten Marek <tmarek@google.com>
# Date 1364388224 -3600
# Wed Mar 27 13:43:44 2013 +0100
# Branch stable
# Node ID 6e82e28d4a0d00ebffa05d78f3cb2f63be91012d
# Parent 41db38a1c28ede2883202a1eb872d199753d03e9
Add support for inference of subscript operations on dict literals. Closes #123074

actually fix Dict.getitem and enhance infer_subscript

diff --git a/ChangeLog b/ChangeLog
@@ -8,10 +8,12 @@
1      * #123068: Fix inference for generator methods to correctly handle yields
2        in lambdas.
3      * #123068: Make sure .as_string() returns valid code for yields in
4        expressions.
5      * #47957: Set literals are now correctly treated as inference leaves.
6 +    * #123074: Add support for inference of subscript operations on dict 
7 +      literals.
8 
9  2013-02-27  -- 0.24.2
10      * pylint-brain: more subprocess.Popen faking (see #46273)
11      * #109562 [jython]: java modules have no __doc__, causing crash
12      * #120646 [py3]: fix for python3.3 _ast changes which may cause crash
diff --git a/inference.py b/inference.py
@@ -1,6 +1,6 @@
13 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
14 +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
15  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
16  # copyright 2003-2010 Sylvain Thenault, all rights reserved.
17  # contact mailto:thenault@gmail.com
18  #
19  # This file is part of logilab-astng.
@@ -236,19 +236,23 @@
20  nodes.Global.infer = path_wrapper(infer_global)
21 
22 
23  def infer_subscript(self, context=None):
24      """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]"""
25 -    if isinstance(self.slice, nodes.Index):
26 -        index = self.slice.value.infer(context).next()
27 -        if index is YES:
28 -            yield YES
29 -            return
30 +    value = self.value.infer(context).next()
31 +    if value is YES:
32 +        yield YES
33 +        return
34 +
35 +    index = self.slice.infer(context).next()
36 +    if index is YES:
37 +        yield YES
38 +        return
39 +
40 +    if isinstance(index, nodes.Const):
41          try:
42 -            # suppose it's a Tuple/List node (attribute error else)
43 -            # XXX infer self.value?
44 -            assigned = self.value.getitem(index.value, context)
45 +            assigned = value.getitem(index.value, context)
46          except AttributeError:
47              raise InferenceError()
48          except (IndexError, TypeError):
49              yield YES
50              return
@@ -379,5 +383,9 @@
51                  yield infered
52          except ASTNGError:
53              yield YES
54  nodes.EmptyNode.infer = path_wrapper(infer_empty_node)
55 
56 +
57 +def infer_index(self, context=None):
58 +    return self.value.infer(context)
59 +nodes.Index.infer = infer_index
diff --git a/node_classes.py b/node_classes.py
@@ -1,6 +1,6 @@
60 -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
61 +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
62  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
63  # copyright 2003-2010 Sylvain Thenault, all rights reserved.
64  # contact mailto:thenault@gmail.com
65  #
66  # This file is part of logilab-astng.
@@ -511,18 +511,20 @@
67          return None
68 
69      def itered(self):
70          return self.items[::2]
71 
72 -    def getitem(self, key, context=None):
73 -        for i in xrange(0, len(self.items), 2):
74 -            for inferedkey in self.items[i].infer(context):
75 +    def getitem(self, lookup_key, context=None):
76 +        for key, value in self.items:
77 +            for inferedkey in key.infer(context):
78                  if inferedkey is YES:
79                      continue
80 -                if isinstance(inferedkey, Const) and inferedkey.value == key:
81 -                    return self.items[i+1]
82 -        raise IndexError(key)
83 +                if isinstance(inferedkey, Const) and inferedkey.value == lookup_key:
84 +                    return value
85 +        # This should raise KeyError, but all call sites only catch
86 +        # IndexError. Let's leave it like that for now.
87 +        raise IndexError(lookup_key)
88 
89 
90  class Discard(Statement):
91      """class representing a Discard node"""
92      _astng_fields = ('value',)
diff --git a/test/unittest_inference.py b/test/unittest_inference.py
@@ -625,20 +625,25 @@
93  a = [1, 2, 3][0]
94  b = (1, 2, 3)[1]
95  c = (1, 2, 3)[-1]
96  d = a + b + c
97  print (d)
98 +e = {'key': 'value'}
99 +f = e['key']
100 +print (f)
101          '''
102          astng = builder.string_build(code, __name__, __file__)
103          self.assertEqual([i.value for i in
104                                  get_name_node(astng, 'a', -1).infer()], [1])
105          self.assertEqual([i.value for i in
106                                  get_name_node(astng, 'b', -1).infer()], [2])
107          self.assertEqual([i.value for i in
108                                  get_name_node(astng, 'c', -1).infer()], [3])
109          self.assertEqual([i.value for i in
110                                  get_name_node(astng, 'd', -1).infer()], [6])
111 +        self.assertEqual([i.value for i in
112 +                          get_name_node(astng, 'f', -1).infer()], ['value'])
113 
114      #def test_simple_tuple(self):
115          #"""test case for a simple tuple value"""
116          ## XXX tuple inference is not implemented ...
117          #code = """