Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Side by Side Diff: third_party/logilab/astroid/inference.py

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/logilab/astroid/exceptions.py ('k') | third_party/logilab/astroid/inspector.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 __doctype__ = "restructuredtext en"
22
23 from itertools import chain
24
25 from astroid import nodes
26
27 from astroid.manager import AstroidManager
28 from astroid.exceptions import (AstroidError, InferenceError, NoDefault,
29 NotFoundError, UnresolvableName)
30 from astroid.bases import (YES, Instance, InferenceContext,
31 _infer_stmts, copy_context, path_wrapper,
32 raise_if_nothing_infered)
33 from astroid.protocols import (
34 _arguments_infer_argname,
35 BIN_OP_METHOD, UNARY_OP_METHOD)
36
37 MANAGER = AstroidManager()
38
39
40 class CallContext(object):
41 """when inferring a function call, this class is used to remember values
42 given as argument
43 """
44 def __init__(self, args, starargs, dstarargs):
45 self.args = []
46 self.nargs = {}
47 for arg in args:
48 if isinstance(arg, nodes.Keyword):
49 self.nargs[arg.arg] = arg.value
50 else:
51 self.args.append(arg)
52 self.starargs = starargs
53 self.dstarargs = dstarargs
54
55 def infer_argument(self, funcnode, name, context):
56 """infer a function argument value according to the call context"""
57 # 1. search in named keywords
58 try:
59 return self.nargs[name].infer(context)
60 except KeyError:
61 # Function.args.args can be None in astroid (means that we don't hav e
62 # information on argnames)
63 argindex = funcnode.args.find_argname(name)[0]
64 if argindex is not None:
65 # 2. first argument of instance/class method
66 if argindex == 0 and funcnode.type in ('method', 'classmethod'):
67 if context.boundnode is not None:
68 boundnode = context.boundnode
69 else:
70 # XXX can do better ?
71 boundnode = funcnode.parent.frame()
72 if funcnode.type == 'method':
73 if not isinstance(boundnode, Instance):
74 boundnode = Instance(boundnode)
75 return iter((boundnode,))
76 if funcnode.type == 'classmethod':
77 return iter((boundnode,))
78 # if we have a method, extract one position
79 # from the index, so we'll take in account
80 # the extra parameter represented by `self` or `cls`
81 if funcnode.type in ('method', 'classmethod'):
82 argindex -= 1
83 # 2. search arg index
84 try:
85 return self.args[argindex].infer(context)
86 except IndexError:
87 pass
88 # 3. search in *args (.starargs)
89 if self.starargs is not None:
90 its = []
91 for infered in self.starargs.infer(context):
92 if infered is YES:
93 its.append((YES,))
94 continue
95 try:
96 its.append(infered.getitem(argindex, context).infer( context))
97 except (InferenceError, AttributeError):
98 its.append((YES,))
99 except (IndexError, TypeError):
100 continue
101 if its:
102 return chain(*its)
103 # 4. XXX search in **kwargs (.dstarargs)
104 if self.dstarargs is not None:
105 its = []
106 for infered in self.dstarargs.infer(context):
107 if infered is YES:
108 its.append((YES,))
109 continue
110 try:
111 its.append(infered.getitem(name, context).infer(context))
112 except (InferenceError, AttributeError):
113 its.append((YES,))
114 except (IndexError, TypeError):
115 continue
116 if its:
117 return chain(*its)
118 # 5. */** argument, (Tuple or Dict)
119 if name == funcnode.args.vararg:
120 return iter((nodes.const_factory(())))
121 if name == funcnode.args.kwarg:
122 return iter((nodes.const_factory({})))
123 # 6. return default value if any
124 try:
125 return funcnode.args.default_value(name).infer(context)
126 except NoDefault:
127 raise InferenceError(name)
128
129
130 # .infer method ###############################################################
131
132
133 def infer_end(self, context=None):
134 """inference's end for node such as Module, Class, Function, Const...
135 """
136 yield self
137 nodes.Module._infer = infer_end
138 nodes.Class._infer = infer_end
139 nodes.Function._infer = infer_end
140 nodes.Lambda._infer = infer_end
141 nodes.Const._infer = infer_end
142 nodes.List._infer = infer_end
143 nodes.Tuple._infer = infer_end
144 nodes.Dict._infer = infer_end
145 nodes.Set._infer = infer_end
146
147 def _higher_function_scope(node):
148 """ Search for the first function which encloses the given
149 scope. This can be used for looking up in that function's
150 scope, in case looking up in a lower scope for a particular
151 name fails.
152
153 :param node: A scope node.
154 :returns:
155 ``None``, if no parent function scope was found,
156 otherwise an instance of :class:`astroid.scoped_nodes.Function`,
157 which encloses the given node.
158 """
159 current = node
160 while current.parent and not isinstance(current.parent, nodes.Function):
161 current = current.parent
162 if current and current.parent:
163 return current.parent
164
165 def infer_name(self, context=None):
166 """infer a Name: use name lookup rules"""
167 frame, stmts = self.lookup(self.name)
168 if not stmts:
169 # Try to see if the name is enclosed in a nested function
170 # and use the higher (first function) scope for searching.
171 # TODO: should this be promoted to other nodes as well?
172 parent_function = _higher_function_scope(self.scope())
173 if parent_function:
174 _, stmts = parent_function.lookup(self.name)
175
176 if not stmts:
177 raise UnresolvableName(self.name)
178 context = context.clone()
179 context.lookupname = self.name
180 return _infer_stmts(stmts, context, frame)
181 nodes.Name._infer = path_wrapper(infer_name)
182 nodes.AssName.infer_lhs = infer_name # won't work with a path wrapper
183
184
185 def infer_callfunc(self, context=None):
186 """infer a CallFunc node by trying to guess what the function returns"""
187 callcontext = context.clone()
188 callcontext.callcontext = CallContext(self.args, self.starargs, self.kwargs)
189 callcontext.boundnode = None
190 for callee in self.func.infer(context):
191 if callee is YES:
192 yield callee
193 continue
194 try:
195 if hasattr(callee, 'infer_call_result'):
196 for infered in callee.infer_call_result(self, callcontext):
197 yield infered
198 except InferenceError:
199 ## XXX log error ?
200 continue
201 nodes.CallFunc._infer = path_wrapper(raise_if_nothing_infered(infer_callfunc))
202
203
204 def infer_import(self, context=None, asname=True):
205 """infer an Import node: return the imported module/object"""
206 name = context.lookupname
207 if name is None:
208 raise InferenceError()
209 if asname:
210 yield self.do_import_module(self.real_name(name))
211 else:
212 yield self.do_import_module(name)
213 nodes.Import._infer = path_wrapper(infer_import)
214
215 def infer_name_module(self, name):
216 context = InferenceContext()
217 context.lookupname = name
218 return self.infer(context, asname=False)
219 nodes.Import.infer_name_module = infer_name_module
220
221
222 def infer_from(self, context=None, asname=True):
223 """infer a From nodes: return the imported module/object"""
224 name = context.lookupname
225 if name is None:
226 raise InferenceError()
227 if asname:
228 name = self.real_name(name)
229 module = self.do_import_module()
230 try:
231 context = copy_context(context)
232 context.lookupname = name
233 return _infer_stmts(module.getattr(name, ignore_locals=module is self.ro ot()), context)
234 except NotFoundError:
235 raise InferenceError(name)
236 nodes.From._infer = path_wrapper(infer_from)
237
238
239 def infer_getattr(self, context=None):
240 """infer a Getattr node by using getattr on the associated object"""
241 #context = context.clone()
242 for owner in self.expr.infer(context):
243 if owner is YES:
244 yield owner
245 continue
246 try:
247 context.boundnode = owner
248 for obj in owner.igetattr(self.attrname, context):
249 yield obj
250 context.boundnode = None
251 except (NotFoundError, InferenceError):
252 context.boundnode = None
253 except AttributeError:
254 # XXX method / function
255 context.boundnode = None
256 nodes.Getattr._infer = path_wrapper(raise_if_nothing_infered(infer_getattr))
257 nodes.AssAttr.infer_lhs = raise_if_nothing_infered(infer_getattr) # # won't work with a path wrapper
258
259
260 def infer_global(self, context=None):
261 if context.lookupname is None:
262 raise InferenceError()
263 try:
264 return _infer_stmts(self.root().getattr(context.lookupname), context)
265 except NotFoundError:
266 raise InferenceError()
267 nodes.Global._infer = path_wrapper(infer_global)
268
269
270 def infer_subscript(self, context=None):
271 """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]"""
272 value = self.value.infer(context).next()
273 if value is YES:
274 yield YES
275 return
276
277 index = self.slice.infer(context).next()
278 if index is YES:
279 yield YES
280 return
281
282 if isinstance(index, nodes.Const):
283 try:
284 assigned = value.getitem(index.value, context)
285 except AttributeError:
286 raise InferenceError()
287 except (IndexError, TypeError):
288 yield YES
289 return
290 for infered in assigned.infer(context):
291 yield infered
292 else:
293 raise InferenceError()
294 nodes.Subscript._infer = path_wrapper(infer_subscript)
295 nodes.Subscript.infer_lhs = raise_if_nothing_infered(infer_subscript)
296
297 def infer_unaryop(self, context=None):
298 for operand in self.operand.infer(context):
299 try:
300 yield operand.infer_unary_op(self.op)
301 except TypeError:
302 continue
303 except AttributeError:
304 meth = UNARY_OP_METHOD[self.op]
305 if meth is None:
306 yield YES
307 else:
308 try:
309 # XXX just suppose if the type implement meth, returned type
310 # will be the same
311 operand.getattr(meth)
312 yield operand
313 except GeneratorExit:
314 raise
315 except:
316 yield YES
317 nodes.UnaryOp._infer = path_wrapper(infer_unaryop)
318
319 def _infer_binop(operator, operand1, operand2, context, failures=None):
320 if operand1 is YES:
321 yield operand1
322 return
323 try:
324 for valnode in operand1.infer_binary_op(operator, operand2, context):
325 yield valnode
326 except AttributeError:
327 try:
328 # XXX just suppose if the type implement meth, returned type
329 # will be the same
330 operand1.getattr(BIN_OP_METHOD[operator])
331 yield operand1
332 except:
333 if failures is None:
334 yield YES
335 else:
336 failures.append(operand1)
337
338 def infer_binop(self, context=None):
339 failures = []
340 for lhs in self.left.infer(context):
341 for val in _infer_binop(self.op, lhs, self.right, context, failures):
342 yield val
343 for lhs in failures:
344 for rhs in self.right.infer(context):
345 for val in _infer_binop(self.op, rhs, lhs, context):
346 yield val
347 nodes.BinOp._infer = path_wrapper(infer_binop)
348
349
350 def infer_arguments(self, context=None):
351 name = context.lookupname
352 if name is None:
353 raise InferenceError()
354 return _arguments_infer_argname(self, name, context)
355 nodes.Arguments._infer = infer_arguments
356
357
358 def infer_ass(self, context=None):
359 """infer a AssName/AssAttr: need to inspect the RHS part of the
360 assign node
361 """
362 stmt = self.statement()
363 if isinstance(stmt, nodes.AugAssign):
364 return stmt.infer(context)
365 stmts = list(self.assigned_stmts(context=context))
366 return _infer_stmts(stmts, context)
367 nodes.AssName._infer = path_wrapper(infer_ass)
368 nodes.AssAttr._infer = path_wrapper(infer_ass)
369
370 def infer_augassign(self, context=None):
371 failures = []
372 for lhs in self.target.infer_lhs(context):
373 for val in _infer_binop(self.op, lhs, self.value, context, failures):
374 yield val
375 for lhs in failures:
376 for rhs in self.value.infer(context):
377 for val in _infer_binop(self.op, rhs, lhs, context):
378 yield val
379 nodes.AugAssign._infer = path_wrapper(infer_augassign)
380
381
382 # no infer method on DelName and DelAttr (expected InferenceError)
383
384
385 def infer_empty_node(self, context=None):
386 if not self.has_underlying_object():
387 yield YES
388 else:
389 try:
390 for infered in MANAGER.infer_ast_from_something(self.object,
391 context=context):
392 yield infered
393 except AstroidError:
394 yield YES
395 nodes.EmptyNode._infer = path_wrapper(infer_empty_node)
396
397
398 def infer_index(self, context=None):
399 return self.value.infer(context)
400 nodes.Index._infer = infer_index
OLDNEW
« no previous file with comments | « third_party/logilab/astroid/exceptions.py ('k') | third_party/logilab/astroid/inspector.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698