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

Side by Side Diff: third_party/logilab/astng/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 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/astng/exceptions.py ('k') | third_party/logilab/astng/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-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # copyright 2003-2010 Sylvain Thenault, all rights reserved.
4 # contact mailto:thenault@gmail.com
5 #
6 # This file is part of logilab-astng.
7 #
8 # logilab-astng is free software: you can redistribute it and/or modify it
9 # under the terms of the GNU Lesser General Public License as published by the
10 # Free Software Foundation, either version 2.1 of the License, or (at your
11 # option) any later version.
12 #
13 # logilab-astng is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 # for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public License along
19 # with logilab-astng. If not, see <http://www.gnu.org/licenses/>.
20 """this module contains a set of functions to handle inference on astng trees
21 """
22
23 __doctype__ = "restructuredtext en"
24
25 from itertools import chain
26 import sys
27
28 from logilab.astng import nodes
29
30 from logilab.astng.manager import ASTNGManager
31 from logilab.astng.exceptions import (ASTNGBuildingException, ASTNGError,
32 InferenceError, NoDefault, NotFoundError, UnresolvableName)
33 from logilab.astng.bases import YES, Instance, InferenceContext, Generator, \
34 _infer_stmts, copy_context, path_wrapper, raise_if_nothing_infered
35 from logilab.astng.protocols import _arguments_infer_argname
36
37 MANAGER = ASTNGManager()
38
39
40 class CallContext:
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 astng (means that we don't have
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 # 2. search arg index
79 try:
80 return self.args[argindex].infer(context)
81 except IndexError:
82 pass
83 # 3. search in *args (.starargs)
84 if self.starargs is not None:
85 its = []
86 for infered in self.starargs.infer(context):
87 if infered is YES:
88 its.append((YES,))
89 continue
90 try:
91 its.append(infered.getitem(argindex, context).infer( context))
92 except (InferenceError, AttributeError):
93 its.append((YES,))
94 except (IndexError, TypeError):
95 continue
96 if its:
97 return chain(*its)
98 # 4. XXX search in **kwargs (.dstarargs)
99 if self.dstarargs is not None:
100 its = []
101 for infered in self.dstarargs.infer(context):
102 if infered is YES:
103 its.append((YES,))
104 continue
105 try:
106 its.append(infered.getitem(name, context).infer(context))
107 except (InferenceError, AttributeError):
108 its.append((YES,))
109 except (IndexError, TypeError):
110 continue
111 if its:
112 return chain(*its)
113 # 5. */** argument, (Tuple or Dict)
114 if name == funcnode.args.vararg:
115 return iter((nodes.const_factory(())))
116 if name == funcnode.args.kwarg:
117 return iter((nodes.const_factory({})))
118 # 6. return default value if any
119 try:
120 return funcnode.args.default_value(name).infer(context)
121 except NoDefault:
122 raise InferenceError(name)
123
124
125 # .infer method ###############################################################
126
127
128 def infer_end(self, context=None):
129 """inference's end for node such as Module, Class, Function, Const...
130 """
131 yield self
132 nodes.Module.infer = infer_end
133 nodes.Class.infer = infer_end
134 nodes.Function.infer = infer_end
135 nodes.Lambda.infer = infer_end
136 nodes.Const.infer = infer_end
137 nodes.List.infer = infer_end
138 nodes.Tuple.infer = infer_end
139 nodes.Dict.infer = infer_end
140
141
142 def infer_name(self, context=None):
143 """infer a Name: use name lookup rules"""
144 frame, stmts = self.lookup(self.name)
145 if not stmts:
146 raise UnresolvableName(self.name)
147 context = context.clone()
148 context.lookupname = self.name
149 return _infer_stmts(stmts, context, frame)
150 nodes.Name.infer = path_wrapper(infer_name)
151 nodes.AssName.infer_lhs = infer_name # won't work with a path wrapper
152
153
154 def infer_callfunc(self, context=None):
155 """infer a CallFunc node by trying to guess what the function returns"""
156 callcontext = context.clone()
157 callcontext.callcontext = CallContext(self.args, self.starargs, self.kwargs)
158 callcontext.boundnode = None
159 for callee in self.func.infer(context):
160 if callee is YES:
161 yield callee
162 continue
163 try:
164 if hasattr(callee, 'infer_call_result'):
165 for infered in callee.infer_call_result(self, callcontext):
166 yield infered
167 except InferenceError:
168 ## XXX log error ?
169 continue
170 nodes.CallFunc.infer = path_wrapper(raise_if_nothing_infered(infer_callfunc))
171
172
173 def infer_import(self, context=None, asname=True):
174 """infer an Import node: return the imported module/object"""
175 name = context.lookupname
176 if name is None:
177 raise InferenceError()
178 if asname:
179 yield self.do_import_module(self.real_name(name))
180 else:
181 yield self.do_import_module(name)
182 nodes.Import.infer = path_wrapper(infer_import)
183
184 def infer_name_module(self, name):
185 context = InferenceContext()
186 context.lookupname = name
187 return self.infer(context, asname=False)
188 nodes.Import.infer_name_module = infer_name_module
189
190
191 def infer_from(self, context=None, asname=True):
192 """infer a From nodes: return the imported module/object"""
193 name = context.lookupname
194 if name is None:
195 raise InferenceError()
196 if asname:
197 name = self.real_name(name)
198 module = self.do_import_module(self.modname)
199 try:
200 context = copy_context(context)
201 context.lookupname = name
202 return _infer_stmts(module.getattr(name, ignore_locals=module is self.ro ot()), context)
203 except NotFoundError:
204 raise InferenceError(name)
205 nodes.From.infer = path_wrapper(infer_from)
206
207
208 def infer_getattr(self, context=None):
209 """infer a Getattr node by using getattr on the associated object"""
210 #context = context.clone()
211 for owner in self.expr.infer(context):
212 if owner is YES:
213 yield owner
214 continue
215 try:
216 context.boundnode = owner
217 for obj in owner.igetattr(self.attrname, context):
218 yield obj
219 context.boundnode = None
220 except (NotFoundError, InferenceError):
221 context.boundnode = None
222 except AttributeError:
223 # XXX method / function
224 context.boundnode = None
225 nodes.Getattr.infer = path_wrapper(raise_if_nothing_infered(infer_getattr))
226 nodes.AssAttr.infer_lhs = raise_if_nothing_infered(infer_getattr) # # won't work with a path wrapper
227
228
229 def infer_global(self, context=None):
230 if context.lookupname is None:
231 raise InferenceError()
232 try:
233 return _infer_stmts(self.root().getattr(context.lookupname), context)
234 except NotFoundError:
235 raise InferenceError()
236 nodes.Global.infer = path_wrapper(infer_global)
237
238
239 def infer_subscript(self, context=None):
240 """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]"""
241 if isinstance(self.slice, nodes.Index):
242 index = self.slice.value.infer(context).next()
243 if index is YES:
244 yield YES
245 return
246 try:
247 # suppose it's a Tuple/List node (attribute error else)
248 assigned = self.value.getitem(index.value, context)
249 except AttributeError:
250 raise InferenceError()
251 except (IndexError, TypeError):
252 yield YES
253 return
254 for infered in assigned.infer(context):
255 yield infered
256 else:
257 raise InferenceError()
258 nodes.Subscript.infer = path_wrapper(infer_subscript)
259 nodes.Subscript.infer_lhs = raise_if_nothing_infered(infer_subscript)
260
261
262 UNARY_OP_METHOD = {'+': '__pos__',
263 '-': '__neg__',
264 '~': '__invert__',
265 'not': None, # XXX not '__nonzero__'
266 }
267
268 def infer_unaryop(self, context=None):
269 for operand in self.operand.infer(context):
270 try:
271 yield operand.infer_unary_op(self.op)
272 except TypeError:
273 continue
274 except AttributeError:
275 meth = UNARY_OP_METHOD[self.op]
276 if meth is None:
277 yield YES
278 else:
279 try:
280 # XXX just suppose if the type implement meth, returned type
281 # will be the same
282 operand.getattr(meth)
283 yield operand
284 except GeneratorExit:
285 raise
286 except:
287 yield YES
288 nodes.UnaryOp.infer = path_wrapper(infer_unaryop)
289
290
291 BIN_OP_METHOD = {'+': '__add__',
292 '-': '__sub__',
293 '/': '__div__',
294 '//': '__floordiv__',
295 '*': '__mul__',
296 '**': '__power__',
297 '%': '__mod__',
298 '&': '__and__',
299 '|': '__or__',
300 '^': '__xor__',
301 '<<': '__lshift__',
302 '>>': '__rshift__',
303 }
304
305 def _infer_binop(operator, operand1, operand2, context, failures=None):
306 if operand1 is YES:
307 yield operand1
308 return
309 try:
310 for valnode in operand1.infer_binary_op(operator, operand2, context):
311 yield valnode
312 except AttributeError:
313 try:
314 # XXX just suppose if the type implement meth, returned type
315 # will be the same
316 operand1.getattr(BIN_OP_METHOD[operator])
317 yield operand1
318 except:
319 if failures is None:
320 yield YES
321 else:
322 failures.append(operand1)
323
324 def infer_binop(self, context=None):
325 failures = []
326 for lhs in self.left.infer(context):
327 for val in _infer_binop(self.op, lhs, self.right, context, failures):
328 yield val
329 for lhs in failures:
330 for rhs in self.right.infer(context):
331 for val in _infer_binop(self.op, rhs, lhs, context):
332 yield val
333 nodes.BinOp.infer = path_wrapper(infer_binop)
334
335
336 def infer_arguments(self, context=None):
337 name = context.lookupname
338 if name is None:
339 raise InferenceError()
340 return _arguments_infer_argname(self, name, context)
341 nodes.Arguments.infer = infer_arguments
342
343
344 def infer_ass(self, context=None):
345 """infer a AssName/AssAttr: need to inspect the RHS part of the
346 assign node
347 """
348 stmt = self.statement()
349 if isinstance(stmt, nodes.AugAssign):
350 return stmt.infer(context)
351 stmts = list(self.assigned_stmts(context=context))
352 return _infer_stmts(stmts, context)
353 nodes.AssName.infer = path_wrapper(infer_ass)
354 nodes.AssAttr.infer = path_wrapper(infer_ass)
355
356 def infer_augassign(self, context=None):
357 failures = []
358 for lhs in self.target.infer_lhs(context):
359 for val in _infer_binop(self.op, lhs, self.value, context, failures):
360 yield val
361 for lhs in failures:
362 for rhs in self.value.infer(context):
363 for val in _infer_binop(self.op, rhs, lhs, context):
364 yield val
365 nodes.AugAssign.infer = path_wrapper(infer_augassign)
366
367
368 # no infer method on DelName and DelAttr (expected InferenceError)
369
370
371 def infer_empty_node(self, context=None):
372 if not self.has_underlying_object():
373 yield YES
374 else:
375 try:
376 for infered in MANAGER.infer_astng_from_something(self.object,
377 context=context):
378 yield infered
379 except ASTNGError:
380 yield YES
381 nodes.EmptyNode.infer = path_wrapper(infer_empty_node)
382
OLDNEW
« no previous file with comments | « third_party/logilab/astng/exceptions.py ('k') | third_party/logilab/astng/inspector.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698