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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/logilab/astroid/exceptions.py ('k') | third_party/logilab/astroid/inspector.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/logilab/astroid/inference.py
===================================================================
--- third_party/logilab/astroid/inference.py (revision 0)
+++ third_party/logilab/astroid/inference.py (working copy)
@@ -0,0 +1,400 @@
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of astroid.
+#
+# astroid is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by the
+# Free Software Foundation, either version 2.1 of the License, or (at your
+# option) any later version.
+#
+# astroid is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with astroid. If not, see <http://www.gnu.org/licenses/>.
+"""this module contains a set of functions to handle inference on astroid trees
+"""
+
+__doctype__ = "restructuredtext en"
+
+from itertools import chain
+
+from astroid import nodes
+
+from astroid.manager import AstroidManager
+from astroid.exceptions import (AstroidError, InferenceError, NoDefault,
+ NotFoundError, UnresolvableName)
+from astroid.bases import (YES, Instance, InferenceContext,
+ _infer_stmts, copy_context, path_wrapper,
+ raise_if_nothing_infered)
+from astroid.protocols import (
+ _arguments_infer_argname,
+ BIN_OP_METHOD, UNARY_OP_METHOD)
+
+MANAGER = AstroidManager()
+
+
+class CallContext(object):
+ """when inferring a function call, this class is used to remember values
+ given as argument
+ """
+ def __init__(self, args, starargs, dstarargs):
+ self.args = []
+ self.nargs = {}
+ for arg in args:
+ if isinstance(arg, nodes.Keyword):
+ self.nargs[arg.arg] = arg.value
+ else:
+ self.args.append(arg)
+ self.starargs = starargs
+ self.dstarargs = dstarargs
+
+ def infer_argument(self, funcnode, name, context):
+ """infer a function argument value according to the call context"""
+ # 1. search in named keywords
+ try:
+ return self.nargs[name].infer(context)
+ except KeyError:
+ # Function.args.args can be None in astroid (means that we don't have
+ # information on argnames)
+ argindex = funcnode.args.find_argname(name)[0]
+ if argindex is not None:
+ # 2. first argument of instance/class method
+ if argindex == 0 and funcnode.type in ('method', 'classmethod'):
+ if context.boundnode is not None:
+ boundnode = context.boundnode
+ else:
+ # XXX can do better ?
+ boundnode = funcnode.parent.frame()
+ if funcnode.type == 'method':
+ if not isinstance(boundnode, Instance):
+ boundnode = Instance(boundnode)
+ return iter((boundnode,))
+ if funcnode.type == 'classmethod':
+ return iter((boundnode,))
+ # if we have a method, extract one position
+ # from the index, so we'll take in account
+ # the extra parameter represented by `self` or `cls`
+ if funcnode.type in ('method', 'classmethod'):
+ argindex -= 1
+ # 2. search arg index
+ try:
+ return self.args[argindex].infer(context)
+ except IndexError:
+ pass
+ # 3. search in *args (.starargs)
+ if self.starargs is not None:
+ its = []
+ for infered in self.starargs.infer(context):
+ if infered is YES:
+ its.append((YES,))
+ continue
+ try:
+ its.append(infered.getitem(argindex, context).infer(context))
+ except (InferenceError, AttributeError):
+ its.append((YES,))
+ except (IndexError, TypeError):
+ continue
+ if its:
+ return chain(*its)
+ # 4. XXX search in **kwargs (.dstarargs)
+ if self.dstarargs is not None:
+ its = []
+ for infered in self.dstarargs.infer(context):
+ if infered is YES:
+ its.append((YES,))
+ continue
+ try:
+ its.append(infered.getitem(name, context).infer(context))
+ except (InferenceError, AttributeError):
+ its.append((YES,))
+ except (IndexError, TypeError):
+ continue
+ if its:
+ return chain(*its)
+ # 5. */** argument, (Tuple or Dict)
+ if name == funcnode.args.vararg:
+ return iter((nodes.const_factory(())))
+ if name == funcnode.args.kwarg:
+ return iter((nodes.const_factory({})))
+ # 6. return default value if any
+ try:
+ return funcnode.args.default_value(name).infer(context)
+ except NoDefault:
+ raise InferenceError(name)
+
+
+# .infer method ###############################################################
+
+
+def infer_end(self, context=None):
+ """inference's end for node such as Module, Class, Function, Const...
+ """
+ yield self
+nodes.Module._infer = infer_end
+nodes.Class._infer = infer_end
+nodes.Function._infer = infer_end
+nodes.Lambda._infer = infer_end
+nodes.Const._infer = infer_end
+nodes.List._infer = infer_end
+nodes.Tuple._infer = infer_end
+nodes.Dict._infer = infer_end
+nodes.Set._infer = infer_end
+
+def _higher_function_scope(node):
+ """ Search for the first function which encloses the given
+ scope. This can be used for looking up in that function's
+ scope, in case looking up in a lower scope for a particular
+ name fails.
+
+ :param node: A scope node.
+ :returns:
+ ``None``, if no parent function scope was found,
+ otherwise an instance of :class:`astroid.scoped_nodes.Function`,
+ which encloses the given node.
+ """
+ current = node
+ while current.parent and not isinstance(current.parent, nodes.Function):
+ current = current.parent
+ if current and current.parent:
+ return current.parent
+
+def infer_name(self, context=None):
+ """infer a Name: use name lookup rules"""
+ frame, stmts = self.lookup(self.name)
+ if not stmts:
+ # Try to see if the name is enclosed in a nested function
+ # and use the higher (first function) scope for searching.
+ # TODO: should this be promoted to other nodes as well?
+ parent_function = _higher_function_scope(self.scope())
+ if parent_function:
+ _, stmts = parent_function.lookup(self.name)
+
+ if not stmts:
+ raise UnresolvableName(self.name)
+ context = context.clone()
+ context.lookupname = self.name
+ return _infer_stmts(stmts, context, frame)
+nodes.Name._infer = path_wrapper(infer_name)
+nodes.AssName.infer_lhs = infer_name # won't work with a path wrapper
+
+
+def infer_callfunc(self, context=None):
+ """infer a CallFunc node by trying to guess what the function returns"""
+ callcontext = context.clone()
+ callcontext.callcontext = CallContext(self.args, self.starargs, self.kwargs)
+ callcontext.boundnode = None
+ for callee in self.func.infer(context):
+ if callee is YES:
+ yield callee
+ continue
+ try:
+ if hasattr(callee, 'infer_call_result'):
+ for infered in callee.infer_call_result(self, callcontext):
+ yield infered
+ except InferenceError:
+ ## XXX log error ?
+ continue
+nodes.CallFunc._infer = path_wrapper(raise_if_nothing_infered(infer_callfunc))
+
+
+def infer_import(self, context=None, asname=True):
+ """infer an Import node: return the imported module/object"""
+ name = context.lookupname
+ if name is None:
+ raise InferenceError()
+ if asname:
+ yield self.do_import_module(self.real_name(name))
+ else:
+ yield self.do_import_module(name)
+nodes.Import._infer = path_wrapper(infer_import)
+
+def infer_name_module(self, name):
+ context = InferenceContext()
+ context.lookupname = name
+ return self.infer(context, asname=False)
+nodes.Import.infer_name_module = infer_name_module
+
+
+def infer_from(self, context=None, asname=True):
+ """infer a From nodes: return the imported module/object"""
+ name = context.lookupname
+ if name is None:
+ raise InferenceError()
+ if asname:
+ name = self.real_name(name)
+ module = self.do_import_module()
+ try:
+ context = copy_context(context)
+ context.lookupname = name
+ return _infer_stmts(module.getattr(name, ignore_locals=module is self.root()), context)
+ except NotFoundError:
+ raise InferenceError(name)
+nodes.From._infer = path_wrapper(infer_from)
+
+
+def infer_getattr(self, context=None):
+ """infer a Getattr node by using getattr on the associated object"""
+ #context = context.clone()
+ for owner in self.expr.infer(context):
+ if owner is YES:
+ yield owner
+ continue
+ try:
+ context.boundnode = owner
+ for obj in owner.igetattr(self.attrname, context):
+ yield obj
+ context.boundnode = None
+ except (NotFoundError, InferenceError):
+ context.boundnode = None
+ except AttributeError:
+ # XXX method / function
+ context.boundnode = None
+nodes.Getattr._infer = path_wrapper(raise_if_nothing_infered(infer_getattr))
+nodes.AssAttr.infer_lhs = raise_if_nothing_infered(infer_getattr) # # won't work with a path wrapper
+
+
+def infer_global(self, context=None):
+ if context.lookupname is None:
+ raise InferenceError()
+ try:
+ return _infer_stmts(self.root().getattr(context.lookupname), context)
+ except NotFoundError:
+ raise InferenceError()
+nodes.Global._infer = path_wrapper(infer_global)
+
+
+def infer_subscript(self, context=None):
+ """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]"""
+ value = self.value.infer(context).next()
+ if value is YES:
+ yield YES
+ return
+
+ index = self.slice.infer(context).next()
+ if index is YES:
+ yield YES
+ return
+
+ if isinstance(index, nodes.Const):
+ try:
+ assigned = value.getitem(index.value, context)
+ except AttributeError:
+ raise InferenceError()
+ except (IndexError, TypeError):
+ yield YES
+ return
+ for infered in assigned.infer(context):
+ yield infered
+ else:
+ raise InferenceError()
+nodes.Subscript._infer = path_wrapper(infer_subscript)
+nodes.Subscript.infer_lhs = raise_if_nothing_infered(infer_subscript)
+
+def infer_unaryop(self, context=None):
+ for operand in self.operand.infer(context):
+ try:
+ yield operand.infer_unary_op(self.op)
+ except TypeError:
+ continue
+ except AttributeError:
+ meth = UNARY_OP_METHOD[self.op]
+ if meth is None:
+ yield YES
+ else:
+ try:
+ # XXX just suppose if the type implement meth, returned type
+ # will be the same
+ operand.getattr(meth)
+ yield operand
+ except GeneratorExit:
+ raise
+ except:
+ yield YES
+nodes.UnaryOp._infer = path_wrapper(infer_unaryop)
+
+def _infer_binop(operator, operand1, operand2, context, failures=None):
+ if operand1 is YES:
+ yield operand1
+ return
+ try:
+ for valnode in operand1.infer_binary_op(operator, operand2, context):
+ yield valnode
+ except AttributeError:
+ try:
+ # XXX just suppose if the type implement meth, returned type
+ # will be the same
+ operand1.getattr(BIN_OP_METHOD[operator])
+ yield operand1
+ except:
+ if failures is None:
+ yield YES
+ else:
+ failures.append(operand1)
+
+def infer_binop(self, context=None):
+ failures = []
+ for lhs in self.left.infer(context):
+ for val in _infer_binop(self.op, lhs, self.right, context, failures):
+ yield val
+ for lhs in failures:
+ for rhs in self.right.infer(context):
+ for val in _infer_binop(self.op, rhs, lhs, context):
+ yield val
+nodes.BinOp._infer = path_wrapper(infer_binop)
+
+
+def infer_arguments(self, context=None):
+ name = context.lookupname
+ if name is None:
+ raise InferenceError()
+ return _arguments_infer_argname(self, name, context)
+nodes.Arguments._infer = infer_arguments
+
+
+def infer_ass(self, context=None):
+ """infer a AssName/AssAttr: need to inspect the RHS part of the
+ assign node
+ """
+ stmt = self.statement()
+ if isinstance(stmt, nodes.AugAssign):
+ return stmt.infer(context)
+ stmts = list(self.assigned_stmts(context=context))
+ return _infer_stmts(stmts, context)
+nodes.AssName._infer = path_wrapper(infer_ass)
+nodes.AssAttr._infer = path_wrapper(infer_ass)
+
+def infer_augassign(self, context=None):
+ failures = []
+ for lhs in self.target.infer_lhs(context):
+ for val in _infer_binop(self.op, lhs, self.value, context, failures):
+ yield val
+ for lhs in failures:
+ for rhs in self.value.infer(context):
+ for val in _infer_binop(self.op, rhs, lhs, context):
+ yield val
+nodes.AugAssign._infer = path_wrapper(infer_augassign)
+
+
+# no infer method on DelName and DelAttr (expected InferenceError)
+
+
+def infer_empty_node(self, context=None):
+ if not self.has_underlying_object():
+ yield YES
+ else:
+ try:
+ for infered in MANAGER.infer_ast_from_something(self.object,
+ context=context):
+ yield infered
+ except AstroidError:
+ yield YES
+nodes.EmptyNode._infer = path_wrapper(infer_empty_node)
+
+
+def infer_index(self, context=None):
+ return self.value.infer(context)
+nodes.Index._infer = infer_index
« 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