Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / astroid / inference.py @ 745

History | View | Annotate | Download (11.8 KB)

1
# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
#
4
# This file is part of astroid.
5
#
6
# astroid is free software: you can redistribute it and/or modify it
7
# under the terms of the GNU Lesser General Public License as published by the
8
# Free Software Foundation, either version 2.1 of the License, or (at your
9
# option) any later version.
10
#
11
# astroid is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14
# for more details.
15
#
16
# You should have received a copy of the GNU Lesser General Public License along
17
# with astroid. If not, see <http://www.gnu.org/licenses/>.
18
"""this module contains a set of functions to handle inference on astroid trees
19
"""
20

    
21
from __future__ import print_function
22

    
23
from astroid import bases
24
from astroid import context as contextmod
25
from astroid import exceptions
26
from astroid import manager
27
from astroid import nodes
28
from astroid import protocols
29
from astroid import util
30

    
31

    
32
MANAGER = manager.AstroidManager()
33

    
34

    
35
# .infer method ###############################################################
36

    
37

    
38
def infer_end(self, context=None):
39
    """inference's end for node such as Module, ClassDef, FunctionDef,
40
    Const...
41

42
    """
43
    yield self
44
nodes.Module._infer = infer_end
45
nodes.ClassDef._infer = infer_end
46
nodes.FunctionDef._infer = infer_end
47
nodes.Lambda._infer = infer_end
48
nodes.Const._infer = infer_end
49
nodes.List._infer = infer_end
50
nodes.Tuple._infer = infer_end
51
nodes.Dict._infer = infer_end
52
nodes.Set._infer = infer_end
53

    
54
def _higher_function_scope(node):
55
    """ Search for the first function which encloses the given
56
    scope. This can be used for looking up in that function's
57
    scope, in case looking up in a lower scope for a particular
58
    name fails.
59

60
    :param node: A scope node.
61
    :returns:
62
        ``None``, if no parent function scope was found,
63
        otherwise an instance of :class:`astroid.scoped_nodes.Function`,
64
        which encloses the given node.
65
    """
66
    current = node
67
    while current.parent and not isinstance(current.parent, nodes.FunctionDef):
68
        current = current.parent
69
    if current and current.parent:
70
        return current.parent
71

    
72
def infer_name(self, context=None):
73
    """infer a Name: use name lookup rules"""
74
    frame, stmts = self.lookup(self.name)
75
    if not stmts:
76
        # Try to see if the name is enclosed in a nested function
77
        # and use the higher (first function) scope for searching.
78
        # TODO: should this be promoted to other nodes as well?
79
        parent_function = _higher_function_scope(self.scope())
80
        if parent_function:
81
            _, stmts = parent_function.lookup(self.name)
82

    
83
        if not stmts:
84
            raise exceptions.UnresolvableName(self.name)
85
    context = context.clone()
86
    context.lookupname = self.name
87
    return bases._infer_stmts(stmts, context, frame)
88
nodes.Name._infer = bases.path_wrapper(infer_name)
89
nodes.AssignName.infer_lhs = infer_name # won't work with a path wrapper
90

    
91

    
92
@bases.path_wrapper
93
@bases.raise_if_nothing_inferred
94
def infer_call(self, context=None):
95
    """infer a Call node by trying to guess what the function returns"""
96
    callcontext = context.clone()
97
    callcontext.callcontext = contextmod.CallContext(args=self.args,
98
                                                     keywords=self.keywords)
99
    callcontext.boundnode = None
100
    for callee in self.func.infer(context):
101
        if callee is util.YES:
102
            yield callee
103
            continue
104
        try:
105
            if hasattr(callee, 'infer_call_result'):
106
                for inferred in callee.infer_call_result(self, callcontext):
107
                    yield inferred
108
        except exceptions.InferenceError:
109
            ## XXX log error ?
110
            continue
111
nodes.Call._infer = infer_call
112

    
113

    
114
@bases.path_wrapper
115
def infer_import(self, context=None, asname=True):
116
    """infer an Import node: return the imported module/object"""
117
    name = context.lookupname
118
    if name is None:
119
        raise exceptions.InferenceError()
120
    if asname:
121
        yield self.do_import_module(self.real_name(name))
122
    else:
123
        yield self.do_import_module(name)
124
nodes.Import._infer = infer_import
125

    
126

    
127
def infer_name_module(self, name):
128
    context = contextmod.InferenceContext()
129
    context.lookupname = name
130
    return self.infer(context, asname=False)
131
nodes.Import.infer_name_module = infer_name_module
132

    
133

    
134
@bases.path_wrapper
135
def infer_import_from(self, context=None, asname=True):
136
    """infer a ImportFrom node: return the imported module/object"""
137
    name = context.lookupname
138
    if name is None:
139
        raise exceptions.InferenceError()
140
    if asname:
141
        name = self.real_name(name)
142
    module = self.do_import_module()
143
    try:
144
        context = contextmod.copy_context(context)
145
        context.lookupname = name
146
        stmts = module.getattr(name, ignore_locals=module is self.root())
147
        return bases._infer_stmts(stmts, context)
148
    except exceptions.NotFoundError:
149
        raise exceptions.InferenceError(name)
150
nodes.ImportFrom._infer = infer_import_from
151

    
152

    
153
@bases.raise_if_nothing_inferred
154
def infer_attribute(self, context=None):
155
    """infer an Attribute node by using getattr on the associated object"""
156
    for owner in self.expr.infer(context):
157
        if owner is util.YES:
158
            yield owner
159
            continue
160
        try:
161
            context.boundnode = owner
162
            for obj in owner.igetattr(self.attrname, context):
163
                yield obj
164
            context.boundnode = None
165
        except (exceptions.NotFoundError, exceptions.InferenceError):
166
            context.boundnode = None
167
        except AttributeError:
168
            # XXX method / function
169
            context.boundnode = None
170
nodes.Attribute._infer = bases.path_wrapper(infer_attribute)
171
nodes.AssignAttr.infer_lhs = infer_attribute # # won't work with a path wrapper
172

    
173

    
174
@bases.path_wrapper
175
def infer_global(self, context=None):
176
    if context.lookupname is None:
177
        raise exceptions.InferenceError()
178
    try:
179
        return bases._infer_stmts(self.root().getattr(context.lookupname),
180
                                  context)
181
    except exceptions.NotFoundError:
182
        raise exceptions.InferenceError()
183
nodes.Global._infer = infer_global
184

    
185

    
186
@bases.raise_if_nothing_inferred
187
def infer_subscript(self, context=None):
188
    """Inference for subscripts
189

190
    We're understanding if the index is a Const
191
    or a slice, passing the result of inference
192
    to the value's `getitem` method, which should
193
    handle each supported index type accordingly.
194
    """
195

    
196
    value = next(self.value.infer(context))
197
    if value is util.YES:
198
        yield util.YES
199
        return
200

    
201
    index = next(self.slice.infer(context))
202
    if index is util.YES:
203
        yield util.YES
204
        return
205

    
206
    if isinstance(index, nodes.Const):
207
        try:
208
            assigned = value.getitem(index.value, context)
209
        except AttributeError:
210
            raise exceptions.InferenceError()
211
        except (IndexError, TypeError):
212
            yield util.YES
213
            return
214

    
215
        # Prevent inferring if the infered subscript
216
        # is the same as the original subscripted object.
217
        if self is assigned or assigned is util.YES:
218
            yield util.YES
219
            return
220
        for infered in assigned.infer(context):
221
            yield infered
222
    else:
223
        raise exceptions.InferenceError()
224
nodes.Subscript._infer = bases.path_wrapper(infer_subscript)
225
nodes.Subscript.infer_lhs = infer_subscript
226

    
227
@bases.raise_if_nothing_inferred
228
def infer_unaryop(self, context=None):
229
    for operand in self.operand.infer(context):
230
        try:
231
            yield operand.infer_unary_op(self.op)
232
        except TypeError:
233
            continue
234
        except AttributeError:
235
            meth = protocols.UNARY_OP_METHOD[self.op]
236
            if meth is None:
237
                yield util.YES
238
            else:
239
                try:
240
                    # XXX just suppose if the type implement meth, returned type
241
                    # will be the same
242
                    operand.getattr(meth)
243
                    yield operand
244
                except GeneratorExit:
245
                    raise
246
                except:
247
                    yield util.YES
248
nodes.UnaryOp._infer = bases.path_wrapper(infer_unaryop)
249

    
250
def _infer_binop(operator, operand1, operand2, context, failures=None):
251
    if operand1 is util.YES:
252
        yield operand1
253
        return
254
    try:
255
        for valnode in operand1.infer_binary_op(operator, operand2, context):
256
            yield valnode
257
    except AttributeError:
258
        try:
259
            # XXX just suppose if the type implement meth, returned type
260
            # will be the same
261
            operand1.getattr(protocols.BIN_OP_METHOD[operator])
262
            yield operand1
263
        except:
264
            if failures is None:
265
                yield util.YES
266
            else:
267
                failures.append(operand1)
268

    
269
@bases.yes_if_nothing_inferred
270
def infer_binop(self, context=None):
271
    failures = []
272
    for lhs in self.left.infer(context):
273
        for val in _infer_binop(self.op, lhs, self.right, context, failures):
274
            yield val
275
    for lhs in failures:
276
        for rhs in self.right.infer(context):
277
            for val in _infer_binop(self.op, rhs, lhs, context):
278
                yield val
279
nodes.BinOp._infer = bases.path_wrapper(infer_binop)
280

    
281

    
282
def infer_arguments(self, context=None):
283
    name = context.lookupname
284
    if name is None:
285
        raise exceptions.InferenceError()
286
    return protocols._arguments_infer_argname(self, name, context)
287
nodes.Arguments._infer = infer_arguments
288

    
289

    
290
@bases.path_wrapper
291
def infer_assign(self, context=None):
292
    """infer a AssignName/AssignAttr: need to inspect the RHS part of the
293
    assign node
294
    """
295
    stmt = self.statement()
296
    if isinstance(stmt, nodes.AugAssign):
297
        return stmt.infer(context)
298

    
299
    stmts = list(self.assigned_stmts(context=context))
300
    return bases._infer_stmts(stmts, context)
301
nodes.AssignName._infer = infer_assign
302
nodes.AssignAttr._infer = infer_assign
303

    
304
def infer_augassign(self, context=None):
305
    failures = []
306
    for lhs in self.target.infer_lhs(context):
307
        for val in _infer_binop(self.op, lhs, self.value, context, failures):
308
            yield val
309
    for lhs in failures:
310
        for rhs in self.value.infer(context):
311
            for val in _infer_binop(self.op, rhs, lhs, context):
312
                yield val
313
nodes.AugAssign._infer = bases.path_wrapper(infer_augassign)
314

    
315

    
316
# no infer method on DelName and DelAttr (expected InferenceError)
317

    
318
@bases.path_wrapper
319
def infer_empty_node(self, context=None):
320
    if not self.has_underlying_object():
321
        yield util.YES
322
    else:
323
        try:
324
            for inferred in MANAGER.infer_ast_from_something(self.object,
325
                                                             context=context):
326
                yield inferred
327
        except exceptions.AstroidError:
328
            yield util.YES
329
nodes.EmptyNode._infer = infer_empty_node
330

    
331

    
332
def infer_index(self, context=None):
333
    return self.value.infer(context)
334
nodes.Index._infer = infer_index
335

    
336
# TODO: move directly into bases.Instance when the dependency hell
337
# will be solved.
338
def instance_getitem(self, index, context=None):
339
    # Rewrap index to Const for this case
340
    index = nodes.Const(index)
341
    if context:
342
        new_context = context.clone()
343
    else:
344
        context = new_context = contextmod.InferenceContext()
345

    
346
    # Create a new callcontext for providing index as an argument.
347
    new_context.callcontext = contextmod.CallContext(args=[index])
348
    new_context.boundnode = self
349

    
350
    method = next(self.igetattr('__getitem__', context=context))
351
    if not isinstance(method, bases.BoundMethod):
352
        raise exceptions.InferenceError
353

    
354
    try:
355
        return next(method.infer_call_result(self, new_context))
356
    except StopIteration:
357
        raise exceptions.InferenceError
358

    
359
bases.Instance.getitem = instance_getitem