summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-11-05 15:44:59 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2015-11-05 15:44:59 +0200
commitef2e48a4842c0d30a3d8379c0570731aab8243ef (patch)
tree33dfead9c99912efa6970be0632c5157151e96ec
parent282ee076e73e0683752cafeba9c64156074b5e88 (diff)
downloadastroid-git-ef2e48a4842c0d30a3d8379c0570731aab8243ef.tar.gz
The inference functions are implemented as dispatch-functions on virtual base classes, instead of monkey-patching nodes
This has the nice side effect that circular the dependency between inference.py and node_classes is finally removed.
-rw-r--r--astroid/helpers.py3
-rw-r--r--astroid/inference.py188
-rw-r--r--astroid/interpreter/objects.py8
-rw-r--r--astroid/interpreter/runtimeabc.py8
-rw-r--r--astroid/protocols.py5
-rw-r--r--astroid/tree/base.py5
-rw-r--r--astroid/tree/node_classes.py50
7 files changed, 147 insertions, 120 deletions
diff --git a/astroid/helpers.py b/astroid/helpers.py
index 437b39de..a0ba6c18 100644
--- a/astroid/helpers.py
+++ b/astroid/helpers.py
@@ -26,7 +26,6 @@ from astroid import context as contextmod
from astroid import exceptions
from astroid.interpreter import runtimeabc
from astroid import manager
-from astroid import raw_building
from astroid.tree import treeabc
from astroid import util
@@ -35,6 +34,8 @@ BUILTINS = six.moves.builtins.__name__
def _build_proxy_class(cls_name, builtins):
+ # TODO(cpopa): remove this when merging with modular-locals.
+ from astroid import raw_building
proxy = raw_building.build_class(cls_name)
proxy.parent = builtins
return proxy
diff --git a/astroid/inference.py b/astroid/inference.py
index 871af194..20efeae7 100644
--- a/astroid/inference.py
+++ b/astroid/inference.py
@@ -25,39 +25,39 @@ import itertools
import operator
from astroid import context as contextmod
-from astroid import exceptions
from astroid import decorators
+from astroid import exceptions
from astroid import helpers
+from astroid.interpreter import runtimeabc
+from astroid.interpreter import util as inferenceutil
from astroid import manager
-from astroid import nodes
from astroid import protocols
-from astroid.interpreter import util as inferenceutil
-from astroid.interpreter import objects
+from astroid.tree import treeabc
from astroid import util
MANAGER = manager.AstroidManager()
-# .infer method ###############################################################
+@util.singledispatch
+def infer(self, context=None):
+ raise exceptions.InferenceError
+@infer.register(treeabc.Module)
+@infer.register(treeabc.ClassDef)
+@infer.register(treeabc.FunctionDef)
+@infer.register(treeabc.Lambda)
+@infer.register(treeabc.Const)
+@infer.register(treeabc.List)
+@infer.register(treeabc.Tuple)
+@infer.register(treeabc.Dict)
+@infer.register(treeabc.Set)
+@infer.register(treeabc.Slice)
+@infer.register(runtimeabc.Super)
+@infer.register(runtimeabc.FrozenSet)
def infer_end(self, context=None):
- """inference's end for node such as Module, ClassDef, FunctionDef,
- Const...
-
- """
yield self
-nodes.Module._infer = infer_end
-nodes.ClassDef._infer = infer_end
-nodes.FunctionDef._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.Slice._infer = infer_end
def _higher_function_scope(node):
@@ -73,11 +73,12 @@ def _higher_function_scope(node):
which encloses the given node.
"""
current = node
- while current.parent and not isinstance(current.parent, nodes.FunctionDef):
+ while current.parent and not isinstance(current.parent, treeabc.FunctionDef):
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)
@@ -94,10 +95,11 @@ def infer_name(self, context=None):
context = context.clone()
context.lookupname = self.name
return inferenceutil.infer_stmts(stmts, context, frame)
-nodes.Name._infer = decorators.path_wrapper(infer_name)
-nodes.AssignName.infer_lhs = infer_name # won't work with a path wrapper
+
+infer.register(treeabc.Name, decorators.path_wrapper(infer_name))
+@infer.register(treeabc.Call)
@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
def infer_call(self, context=None):
@@ -117,9 +119,9 @@ def infer_call(self, context=None):
except exceptions.InferenceError:
## XXX log error ?
continue
-nodes.Call._infer = infer_call
+@infer.register(treeabc.Import)
@decorators.path_wrapper
def infer_import(self, context=None, asname=True):
"""infer an Import node: return the imported module/object"""
@@ -130,16 +132,9 @@ 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 = infer_import
-
-
-def infer_name_module(self, name):
- context = contextmod.InferenceContext()
- context.lookupname = name
- return self.infer(context, asname=False)
-nodes.Import.infer_name_module = infer_name_module
+@infer.register(treeabc.ImportFrom)
@decorators.path_wrapper
def infer_import_from(self, context=None, asname=True):
"""infer a ImportFrom node: return the imported module/object"""
@@ -156,7 +151,6 @@ def infer_import_from(self, context=None, asname=True):
return inferenceutil.infer_stmts(stmts, context)
except exceptions.NotFoundError:
util.reraise(exceptions.InferenceError(name))
-nodes.ImportFrom._infer = infer_import_from
@decorators.raise_if_nothing_inferred
@@ -176,10 +170,11 @@ def infer_attribute(self, context=None):
except AttributeError:
# XXX method / function
context.boundnode = None
-nodes.Attribute._infer = decorators.path_wrapper(infer_attribute)
-nodes.AssignAttr.infer_lhs = infer_attribute # # won't work with a path wrapper
+infer.register(treeabc.Attribute, decorators.path_wrapper(infer_attribute))
+
+@infer.register(treeabc.Global)
@decorators.path_wrapper
def infer_global(self, context=None):
if context.lookupname is None:
@@ -189,14 +184,13 @@ def infer_global(self, context=None):
context)
except exceptions.NotFoundError:
util.reraise(exceptions.InferenceError())
-nodes.Global._infer = infer_global
_SLICE_SENTINEL = object()
def _slice_value(index, context=None):
"""Get the value of the given slice index."""
- if isinstance(index, nodes.Const):
+ if isinstance(index, treeabc.Const):
if isinstance(index.value, (int, type(None))):
return index.value
elif index is None:
@@ -210,7 +204,7 @@ def _slice_value(index, context=None):
except exceptions.InferenceError:
pass
else:
- if isinstance(inferred, nodes.Const):
+ if isinstance(inferred, treeabc.Const):
if isinstance(inferred.value, (int, type(None))):
return inferred.value
@@ -240,20 +234,20 @@ def infer_subscript(self, context=None):
yield util.YES
return
- if value.__class__ == objects.Instance:
+ if value.__class__.__name__ == 'Instance':
index_value = index
else:
index_value = _SLICE_SENTINEL
- if isinstance(index, nodes.Const):
+ if isinstance(index, treeabc.Const):
index_value = index.value
- elif isinstance(index, nodes.Slice):
+ elif isinstance(index, treeabc.Slice):
# Infer slices from the original object.
lower = _slice_value(index.lower, context)
upper = _slice_value(index.upper, context)
step = _slice_value(index.step, context)
if all(elem is not _SLICE_SENTINEL for elem in (lower, upper, step)):
index_value = slice(lower, upper, step)
- elif isinstance(index, objects.Instance):
+ elif isinstance(index, runtimeabc.Instance):
index = inferenceutil.class_instance_as_index(index)
if index:
index_value = index.value
@@ -276,10 +270,10 @@ def infer_subscript(self, context=None):
for inferred in assigned.infer(context):
yield inferred
-nodes.Subscript._infer = decorators.path_wrapper(infer_subscript)
-nodes.Subscript.infer_lhs = infer_subscript
+infer.register(treeabc.Subscript, decorators.path_wrapper(infer_subscript))
+@infer.register(treeabc.BoolOp)
@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
def _infer_boolop(self, context=None):
@@ -330,8 +324,6 @@ def _infer_boolop(self, context=None):
else:
yield value
-nodes.BoolOp._infer = _infer_boolop
-
# UnaryOp, BinOp and AugAssign inferences
@@ -346,7 +338,7 @@ def _filter_operation_errors(self, infer_callable, context, error):
yield result
-def _infer_unaryop(self, context=None):
+def infer_unaryop(self, context=None, nodes=None):
"""Infer what an UnaryOp should return when evaluated."""
for operand in self.operand.infer(context):
try:
@@ -366,7 +358,7 @@ def _infer_unaryop(self, context=None):
else:
yield util.YES
else:
- if not isinstance(operand, objects.Instance):
+ if not isinstance(operand, runtimeabc.Instance):
# The operation was used on something which
# doesn't support it.
yield exceptions.UnaryOperationError(operand, self.op, exc)
@@ -396,38 +388,37 @@ def _infer_unaryop(self, context=None):
@decorators.raise_if_nothing_inferred
@decorators.path_wrapper
-def infer_unaryop(self, context=None):
+def filtered_infer_unaryop(self, context=None, nodes=None):
"""Infer what an UnaryOp should return when evaluated."""
- return _filter_operation_errors(self, _infer_unaryop, context,
+ with_nodes_func = functools.partial(infer_unaryop, nodes=nodes)
+ return _filter_operation_errors(self, with_nodes_func, context,
exceptions.UnaryOperationError)
-nodes.UnaryOp._infer_unaryop = _infer_unaryop
-nodes.UnaryOp._infer = infer_unaryop
-
def _is_not_implemented(const):
"""Check if the given const node is NotImplemented."""
- return isinstance(const, nodes.Const) and const.value is NotImplemented
+ return isinstance(const, treeabc.Const) and const.value is NotImplemented
-def _invoke_binop_inference(instance, op, other, context, method_name):
+def _invoke_binop_inference(instance, op, other, context, method_name, nodes):
"""Invoke binary operation inference on the given instance."""
method = instance.getattr(method_name)[0]
inferred = next(method.infer(context=context))
return protocols.infer_binary_op(instance, op, other, context, inferred, nodes)
-def _aug_op(instance, op, other, context, reverse=False):
+def _aug_op(instance, op, other, context, nodes, reverse=False):
"""Get an inference callable for an augmented binary operation."""
method_name = protocols.AUGMENTED_OP_METHOD[op]
return functools.partial(_invoke_binop_inference,
instance=instance,
op=op, other=other,
context=context,
- method_name=method_name)
+ method_name=method_name,
+ nodes=nodes)
-def _bin_op(instance, op, other, context, reverse=False):
+def _bin_op(instance, op, other, context, nodes, reverse=False):
"""Get an inference callable for a normal binary operation.
If *reverse* is True, then the reflected method will be used instead.
@@ -440,7 +431,8 @@ def _bin_op(instance, op, other, context, reverse=False):
instance=instance,
op=op, other=other,
context=context,
- method_name=method_name)
+ method_name=method_name,
+ nodes=nodes)
def _get_binop_contexts(context, left, right):
@@ -465,7 +457,7 @@ def _same_type(type1, type2):
def _get_binop_flow(left, left_type, op, right, right_type,
- context, reverse_context):
+ context, reverse_context, nodes):
"""Get the flow for binary operations.
The rules are a bit messy:
@@ -481,20 +473,20 @@ def _get_binop_flow(left, left_type, op, right, right_type,
is first tried and then left.__op__(right)
"""
if _same_type(left_type, right_type):
- methods = [_bin_op(left, op, right, context)]
+ methods = [_bin_op(left, op, right, context, nodes)]
elif inferenceutil.is_subtype(left_type, right_type):
- methods = [_bin_op(left, op, right, context)]
+ methods = [_bin_op(left, op, right, context, nodes)]
elif inferenceutil.is_supertype(left_type, right_type):
- methods = [_bin_op(right, op, left, reverse_context, reverse=True),
- _bin_op(left, op, right, context)]
+ methods = [_bin_op(right, op, left, reverse_context, nodes, reverse=True),
+ _bin_op(left, op, right, context, nodes)]
else:
- methods = [_bin_op(left, op, right, context),
- _bin_op(right, op, left, reverse_context, reverse=True)]
+ methods = [_bin_op(left, op, right, context, nodes),
+ _bin_op(right, op, left, reverse_context, nodes, reverse=True)]
return methods
def _get_aug_flow(left, left_type, aug_op, right, right_type,
- context, reverse_context):
+ context, reverse_context, nodes):
"""Get the flow for augmented binary operations.
The rules are a bit messy:
@@ -512,23 +504,23 @@ def _get_aug_flow(left, left_type, aug_op, right, right_type,
"""
op = aug_op.strip("=")
if _same_type(left_type, right_type):
- methods = [_aug_op(left, aug_op, right, context),
- _bin_op(left, op, right, context)]
+ methods = [_aug_op(left, aug_op, right, context, nodes),
+ _bin_op(left, op, right, context, nodes)]
elif inferenceutil.is_subtype(left_type, right_type):
- methods = [_aug_op(left, aug_op, right, context),
- _bin_op(left, op, right, context)]
+ methods = [_aug_op(left, aug_op, right, context, nodes),
+ _bin_op(left, op, right, context, nodes)]
elif inferenceutil.is_supertype(left_type, right_type):
- methods = [_aug_op(left, aug_op, right, context),
- _bin_op(right, op, left, reverse_context, reverse=True),
- _bin_op(left, op, right, context)]
+ methods = [_aug_op(left, aug_op, right, context, nodes),
+ _bin_op(right, op, left, reverse_context, nodes, reverse=True),
+ _bin_op(left, op, right, context, nodes)]
else:
- methods = [_aug_op(left, aug_op, right, context),
- _bin_op(left, op, right, context),
- _bin_op(right, op, left, reverse_context, reverse=True)]
+ methods = [_aug_op(left, aug_op, right, context, nodes),
+ _bin_op(left, op, right, context, nodes),
+ _bin_op(right, op, left, reverse_context, nodes, reverse=True)]
return methods
-def _infer_binary_operation(left, right, op, context, flow_factory):
+def _infer_binary_operation(left, right, op, context, flow_factory, nodes):
"""Infer a binary operation between a left operand and a right operand
This is used by both normal binary operations and augmented binary
@@ -539,12 +531,12 @@ def _infer_binary_operation(left, right, op, context, flow_factory):
left_type = helpers.object_type(left)
right_type = helpers.object_type(right)
methods = flow_factory(left, left_type, op, right, right_type,
- context, reverse_context)
+ context, reverse_context, nodes)
for method in methods:
try:
results = list(method())
except exceptions.BinaryOperationNotSupportedError:
- continue
+ continue
except (AttributeError, exceptions.NotFoundError):
continue
except exceptions.InferenceError:
@@ -575,7 +567,7 @@ def _infer_binary_operation(left, right, op, context, flow_factory):
yield exceptions.BinaryOperationError(left_type, op, right_type)
-def _infer_binop(self, context):
+def infer_binop(self, context, nodes):
"""Binary operation inferrence logic."""
if context is None:
context = contextmod.InferenceContext()
@@ -601,23 +593,21 @@ def _infer_binop(self, context):
yield util.YES
return
- results = _infer_binary_operation(lhs, rhs, op,
- context, _get_binop_flow)
+ results = _infer_binary_operation(lhs, rhs, op, context,
+ _get_binop_flow, nodes)
for result in results:
yield result
@decorators.yes_if_nothing_inferred
@decorators.path_wrapper
-def infer_binop(self, context=None):
- return _filter_operation_errors(self, _infer_binop, context,
+def filtered_infer_binop(self, context=None, nodes=None):
+ with_nodes_func = functools.partial(infer_binop, nodes=nodes)
+ return _filter_operation_errors(self, with_nodes_func, context,
exceptions.BinaryOperationError)
-nodes.BinOp._infer_binop = _infer_binop
-nodes.BinOp._infer = infer_binop
-
-def _infer_augassign(self, context=None):
+def infer_augassign(self, context=None, nodes=None):
"""Inferrence logic for augmented binary operations."""
if context is None:
context = contextmod.InferenceContext()
@@ -642,47 +632,46 @@ def _infer_augassign(self, context=None):
return
results = _infer_binary_operation(lhs, rhs, op,
- context, _get_aug_flow)
+ context, _get_aug_flow, nodes)
for result in results:
yield result
@decorators.path_wrapper
-def infer_augassign(self, context=None):
- return _filter_operation_errors(self, _infer_augassign, context,
+def filtered_infer_augassign(self, context=None, nodes=None):
+ with_nodes_func = functools.partial(infer_augassign, nodes=nodes)
+ return _filter_operation_errors(self, with_nodes_func, context,
exceptions.BinaryOperationError)
-nodes.AugAssign._infer_augassign = _infer_augassign
-nodes.AugAssign._infer = infer_augassign
# End of binary operation inference.
-def infer_arguments(self, context=None):
+def infer_arguments(self, context=None, nodes=None):
name = context.lookupname
if name is None:
raise exceptions.InferenceError()
return protocols._arguments_infer_argname(self, name, context, nodes)
-nodes.Arguments._infer = infer_arguments
+@infer.register(treeabc.AssignName)
+@infer.register(treeabc.AssignAttr)
@decorators.path_wrapper
def infer_assign(self, context=None):
"""infer a AssignName/AssignAttr: need to inspect the RHS part of the
assign node
"""
stmt = self.statement()
- if isinstance(stmt, nodes.AugAssign):
+ if isinstance(stmt, treeabc.AugAssign):
return stmt.infer(context)
stmts = list(self.assigned_stmts(context=context))
return inferenceutil.infer_stmts(stmts, context)
-nodes.AssignName._infer = infer_assign
-nodes.AssignAttr._infer = infer_assign
# no infer method on DelName and DelAttr (expected InferenceError)
+@infer.register(treeabc.EmptyNode)
@decorators.path_wrapper
def infer_empty_node(self, context=None):
if not self.has_underlying_object():
@@ -694,9 +683,8 @@ def infer_empty_node(self, context=None):
yield inferred
except exceptions.AstroidError:
yield util.YES
-nodes.EmptyNode._infer = infer_empty_node
+@infer.register(treeabc.Index)
def infer_index(self, context=None):
return self.value.infer(context)
-nodes.Index._infer = infer_index
diff --git a/astroid/interpreter/objects.py b/astroid/interpreter/objects.py
index 1c062878..504b9f9c 100644
--- a/astroid/interpreter/objects.py
+++ b/astroid/interpreter/objects.py
@@ -342,21 +342,20 @@ class Generator(Instance):
return 'Generator(%s)' % (self._proxied.name)
+@util.register_implementation(runtimeabc.FrozenSet)
class FrozenSet(base.BaseContainer, Instance):
"""Class representing a FrozenSet composite node."""
def pytype(self):
return '%s.frozenset' % BUILTINS
- def _infer(self, context=None):
- yield self
-
@decorators.cachedproperty
def _proxied(self):
builtins = MANAGER.astroid_cache[BUILTINS]
return builtins.getattr('frozenset')[0]
+@util.register_implementation(runtimeabc.Super)
class Super(base.NodeNG):
"""Proxy class over a super call.
@@ -383,9 +382,6 @@ class Super(base.NodeNG):
'__class__': self._proxied,
}
- def _infer(self, context=None):
- yield self
-
def super_mro(self):
"""Get the MRO which will be used to lookup attributes in this super."""
if not isinstance(self.mro_pointer, treeabc.ClassDef):
diff --git a/astroid/interpreter/runtimeabc.py b/astroid/interpreter/runtimeabc.py
index 612996ae..ad873ce9 100644
--- a/astroid/interpreter/runtimeabc.py
+++ b/astroid/interpreter/runtimeabc.py
@@ -46,3 +46,11 @@ class BoundMethod(UnboundMethod):
class Generator(RuntimeObject):
"""Class representing a Generator."""
+
+
+class Super(RuntimeObject):
+ """Class representing a super proxy."""
+
+
+class FrozenSet(RuntimeObject):
+ """Class representing a frozenset."""
diff --git a/astroid/protocols.py b/astroid/protocols.py
index 2ef24716..7eb8a1b1 100644
--- a/astroid/protocols.py
+++ b/astroid/protocols.py
@@ -28,7 +28,6 @@ import six
from astroid import context as contextmod
from astroid import decorators
from astroid import exceptions
-from astroid.interpreter import objects
from astroid.interpreter import runtimeabc
from astroid.interpreter import util as inferenceutil
from astroid.tree import treeabc
@@ -304,7 +303,7 @@ def _arguments_infer_argname(self, name, context, nodes):
yield cls
return
if functype == 'method':
- yield objects.Instance(self.parent.parent.frame())
+ yield self.parent.parent.frame().instanciate_class()
return
if context and context.callcontext:
@@ -394,7 +393,7 @@ def _resolve_asspart(parts, asspath, context):
def excepthandler_assigned_stmts(self, nodes, node=None, context=None, asspath=None):
for assigned in inferenceutil.unpack_infer(self.type):
if isinstance(assigned, treeabc.ClassDef):
- assigned = objects.Instance(assigned)
+ assigned = assigned.instanciate_class()
yield assigned
diff --git a/astroid/tree/base.py b/astroid/tree/base.py
index f4ca188a..f5b598a2 100644
--- a/astroid/tree/base.py
+++ b/astroid/tree/base.py
@@ -25,6 +25,7 @@ import six
from astroid import as_string
from astroid import decorators
from astroid import exceptions
+from astroid import inference
from astroid.interpreter import scope
from astroid import mixins
from astroid.tree import treeabc
@@ -75,14 +76,14 @@ class NodeNG(object):
pass
if not context:
- return self._infer(context, **kwargs)
+ return inference.infer(self, context, **kwargs)
key = (self, context.lookupname,
context.callcontext, context.boundnode)
if key in context.inferred:
return iter(context.inferred[key])
- return context.cache_generator(key, self._infer(context, **kwargs))
+ return context.cache_generator(key, inference.infer(self, context, **kwargs))
def _repr_name(self):
"""return self.name or self.attrname or '' for nice representation"""
diff --git a/astroid/tree/node_classes.py b/astroid/tree/node_classes.py
index 9963e2f5..479d8772 100644
--- a/astroid/tree/node_classes.py
+++ b/astroid/tree/node_classes.py
@@ -18,6 +18,7 @@
"""Module for some node classes. More nodes in scoped_nodes.py
"""
+import functools
import warnings
import sys
@@ -26,6 +27,7 @@ import six
from astroid import context as contextmod
from astroid import decorators
from astroid import exceptions
+from astroid import inference
from astroid.interpreter.util import infer_stmts
from astroid.interpreter import runtimeabc
from astroid.interpreter import objects
@@ -255,6 +257,8 @@ class AssignName(LookupMixIn, mixins.ParentAssignTypeMixin,
self.name = name
super(AssignName, self).__init__(lineno, col_offset, parent)
+ infer_lhs = inference.infer_name
+
@util.register_implementation(treeabc.DelName)
class DelName(LookupMixIn, mixins.ParentAssignTypeMixin, base.NodeNG):
@@ -435,6 +439,8 @@ class AssignAttr(mixins.ParentAssignTypeMixin,
def postinit(self, expr=None):
self.expr = expr
+ infer_lhs = inference.infer_attribute
+
@util.register_implementation(treeabc.Assert)
class Assert(Statement):
@@ -476,9 +482,9 @@ class AugAssign(mixins.AssignTypeMixin, AssignedStmtsMixin, Statement):
self.target = target
self.value = value
- # This is set by inference.py
- def _infer_augassign(self, context=None):
- raise NotImplementedError
+ def _infer_augassign(self, context):
+ return inference.infer_augassign(self, nodes=sys.modules[__name__],
+ context=context)
def type_errors(self, context=None):
"""Return a list of TypeErrors which can occur during inference.
@@ -520,9 +526,9 @@ class BinOp(base.NodeNG):
self.left = left
self.right = right
- # This is set by inference.py
- def _infer_binop(self, context=None):
- raise NotImplementedError
+ def _infer_binop(self, context):
+ return inference.infer_binop(self, nodes=sys.modules[__name__],
+ context=context)
def type_errors(self, context=None):
"""Return a list of TypeErrors which can occur during inference.
@@ -982,6 +988,11 @@ class Import(mixins.ImportFromMixin, Statement):
self.names = names
super(Import, self).__init__(lineno, col_offset, parent)
+ def infer_name_module(self, name):
+ context = contextmod.InferenceContext()
+ context.lookupname = name
+ return self.infer(context, asname=False)
+
@util.register_implementation(treeabc.Index)
class Index(base.NodeNG):
@@ -1166,6 +1177,8 @@ class Subscript(base.NodeNG):
self.value = value
self.slice = slice
+ infer_lhs = inference.infer_subscript
+
@util.register_implementation(treeabc.TryExcept)
class TryExcept(mixins.BlockRangeMixIn, Statement):
@@ -1242,9 +1255,9 @@ class UnaryOp(base.NodeNG):
def postinit(self, operand=None):
self.operand = operand
- # This is set by inference.py
def _infer_unaryop(self, context=None):
- raise NotImplementedError
+ return inference.infer_unaryop(self, nodes=sys.modules[__name__],
+ context=context)
def type_errors(self, context=None):
"""Return a list of TypeErrors which can occur during inference.
@@ -1379,3 +1392,24 @@ AssAttr = util.proxy_alias('AssAttr', AssignAttr)
Getattr = util.proxy_alias('Getattr', Attribute)
CallFunc = util.proxy_alias('CallFunc', Call)
From = util.proxy_alias('From', ImportFrom)
+
+
+# Register additional inference dispatched functions. We do
+# this here, since we need to pass this module as an argument
+# to these functions, in order to avoid circular dependencies
+# between inference and node_classes.
+
+_module = sys.modules[__name__]
+inference.infer.register(treeabc.UnaryOp,
+ functools.partial(inference.filtered_infer_unaryop,
+ nodes=_module))
+inference.infer.register(treeabc.Arguments,
+ functools.partial(inference.infer_arguments,
+ nodes=_module))
+inference.infer.register(treeabc.BinOp,
+ functools.partial(inference.filtered_infer_binop,
+ nodes=_module))
+inference.infer.register(treeabc.AugAssign,
+ functools.partial(inference.filtered_infer_augassign,
+ nodes=_module))
+del _module