summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Thénault <sylvain.thenault@logilab.fr>2013-06-18 17:24:28 +0200
committerSylvain Thénault <sylvain.thenault@logilab.fr>2013-06-18 17:24:28 +0200
commitfc02b9e6bc453e0413e324c7a458b5871277744c (patch)
tree5447adcc4b02bff14a98817b4e2d4f98cb1b1443
parent2682f50ee379e7e6d7a0c5891ba7211fc8829ab3 (diff)
downloadastroid-git-fc02b9e6bc453e0413e324c7a458b5871277744c.tar.gz
[inference] introduce (but not use it yet) explicit inference for some node instances
-rw-r--r--bases.py23
-rw-r--r--exceptions.py5
-rw-r--r--inference.py48
3 files changed, 49 insertions, 27 deletions
diff --git a/bases.py b/bases.py
index c76e9bc3..65f056ab 100644
--- a/bases.py
+++ b/bases.py
@@ -24,8 +24,8 @@ __docformat__ = "restructuredtext en"
import sys
from contextlib import contextmanager
-from astroid.exceptions import (InferenceError, AstroidError,
- NotFoundError, UnresolvableName)
+from astroid.exceptions import (InferenceError, AstroidError, NotFoundError,
+ UnresolvableName, UseInferenceDefault)
if sys.version_info >= (3, 0):
@@ -355,6 +355,23 @@ class NodeNG(object):
parent = None
# attributes containing child node(s) redefined in most concrete classes:
_astroid_fields = ()
+ # instance specific inference function infer(node, context)
+ _explicit_inference = None
+
+ def infer(self, context=None):
+ """main interface to the interface system, return a generator on infered
+ values.
+
+ If the instance has some explicit inference function set, it will be
+ called instead of the default interface.
+ """
+ if self._explicit_inference is not None:
+ # explicit_inference is not bound, give it self explicitly
+ try:
+ return self._explicit_inference(self, context)
+ except UseInferenceDefault:
+ pass
+ return self._infer(context)
def _repr_name(self):
"""return self.name or self.attrname or '' for nice representation"""
@@ -543,7 +560,7 @@ class NodeNG(object):
# overridden for From, Import, Global, TryExcept and Arguments
return None
- def infer(self, context=None):
+ def _infer(self, context=None):
"""we don't know how to resolve a statement by default"""
# this method is overridden by most concrete classes
raise InferenceError(self.__class__.__name__)
diff --git a/exceptions.py b/exceptions.py
index 07fb945e..3889e2e7 100644
--- a/exceptions.py
+++ b/exceptions.py
@@ -36,6 +36,11 @@ class NotFoundError(ResolveError):
class InferenceError(ResolveError):
"""raised when we are unable to infer a node"""
+class UseInferenceDefault(Exception):
+ """exception to be raised in custom inference function to indicate that it
+ should go back to the default behaviour
+ """
+
class UnresolvableName(InferenceError):
"""raised when we are unable to resolve a name"""
diff --git a/inference.py b/inference.py
index 055b98d3..ce6dd6c7 100644
--- a/inference.py
+++ b/inference.py
@@ -126,15 +126,15 @@ 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
+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 infer_name(self, context=None):
"""infer a Name: use name lookup rules"""
@@ -144,7 +144,7 @@ def infer_name(self, context=None):
context = context.clone()
context.lookupname = self.name
return _infer_stmts(stmts, context, frame)
-nodes.Name.infer = path_wrapper(infer_name)
+nodes.Name._infer = path_wrapper(infer_name)
nodes.AssName.infer_lhs = infer_name # won't work with a path wrapper
@@ -164,7 +164,7 @@ def infer_callfunc(self, context=None):
except InferenceError:
## XXX log error ?
continue
-nodes.CallFunc.infer = path_wrapper(raise_if_nothing_infered(infer_callfunc))
+nodes.CallFunc._infer = path_wrapper(raise_if_nothing_infered(infer_callfunc))
def infer_import(self, context=None, asname=True):
@@ -176,7 +176,7 @@ def infer_import(self, context=None, asname=True):
yield self.do_import_module(self.real_name(name))
else:
yield self.do_import_module(name)
-nodes.Import.infer = path_wrapper(infer_import)
+nodes.Import._infer = path_wrapper(infer_import)
def infer_name_module(self, name):
context = InferenceContext()
@@ -199,7 +199,7 @@ def infer_from(self, context=None, asname=True):
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)
+nodes.From._infer = path_wrapper(infer_from)
def infer_getattr(self, context=None):
@@ -219,7 +219,7 @@ def infer_getattr(self, context=None):
except AttributeError:
# XXX method / function
context.boundnode = None
-nodes.Getattr.infer = path_wrapper(raise_if_nothing_infered(infer_getattr))
+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
@@ -230,7 +230,7 @@ def infer_global(self, context=None):
return _infer_stmts(self.root().getattr(context.lookupname), context)
except NotFoundError:
raise InferenceError()
-nodes.Global.infer = path_wrapper(infer_global)
+nodes.Global._infer = path_wrapper(infer_global)
def infer_subscript(self, context=None):
@@ -257,7 +257,7 @@ def infer_subscript(self, context=None):
yield infered
else:
raise InferenceError()
-nodes.Subscript.infer = path_wrapper(infer_subscript)
+nodes.Subscript._infer = path_wrapper(infer_subscript)
nodes.Subscript.infer_lhs = raise_if_nothing_infered(infer_subscript)
@@ -287,7 +287,7 @@ def infer_unaryop(self, context=None):
raise
except:
yield YES
-nodes.UnaryOp.infer = path_wrapper(infer_unaryop)
+nodes.UnaryOp._infer = path_wrapper(infer_unaryop)
BIN_OP_METHOD = {'+': '__add__',
@@ -332,7 +332,7 @@ def infer_binop(self, context=None):
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)
+nodes.BinOp._infer = path_wrapper(infer_binop)
def infer_arguments(self, context=None):
@@ -340,7 +340,7 @@ def infer_arguments(self, context=None):
if name is None:
raise InferenceError()
return _arguments_infer_argname(self, name, context)
-nodes.Arguments.infer = infer_arguments
+nodes.Arguments._infer = infer_arguments
def infer_ass(self, context=None):
@@ -352,8 +352,8 @@ def infer_ass(self, context=None):
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)
+nodes.AssName._infer = path_wrapper(infer_ass)
+nodes.AssAttr._infer = path_wrapper(infer_ass)
def infer_augassign(self, context=None):
failures = []
@@ -364,7 +364,7 @@ def infer_augassign(self, context=None):
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)
+nodes.AugAssign._infer = path_wrapper(infer_augassign)
# no infer method on DelName and DelAttr (expected InferenceError)
@@ -380,9 +380,9 @@ def infer_empty_node(self, context=None):
yield infered
except AstroidError:
yield YES
-nodes.EmptyNode.infer = path_wrapper(infer_empty_node)
+nodes.EmptyNode._infer = path_wrapper(infer_empty_node)
def infer_index(self, context=None):
return self.value.infer(context)
-nodes.Index.infer = infer_index
+nodes.Index._infer = infer_index