123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812 |
- # Copyright (c) 2006-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
- # Copyright (c) 2013-2014 Google, Inc.
- # Copyright (c) 2014-2016 Claudiu Popa <pcmanticore@gmail.com>
- # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
-
- # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
- # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
-
- """this module contains a set of functions to handle inference on astroid trees
- """
-
- import functools
- import itertools
- import operator
-
- from astroid import bases
- from astroid import context as contextmod
- from astroid import exceptions
- from astroid import decorators
- from astroid import helpers
- from astroid import manager
- from astroid import nodes
- from astroid.interpreter import dunder_lookup
- from astroid import protocols
- from astroid import util
-
-
- MANAGER = manager.AstroidManager()
-
-
- # .infer method ###############################################################
-
-
- 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.Slice._infer = infer_end
-
-
- def infer_seq(self, context=None):
- if not any(isinstance(e, nodes.Starred) for e in self.elts):
- yield self
- else:
- values = _infer_seq(self, context)
- new_seq = type(self)(self.lineno, self.col_offset, self.parent)
- new_seq.postinit(values)
- yield new_seq
-
-
- def _infer_seq(node, context=None):
- """Infer all values based on _BaseContainer.elts"""
- values = []
-
- for elt in node.elts:
- if isinstance(elt, nodes.Starred):
- starred = helpers.safe_infer(elt.value, context)
- if starred in (None, util.Uninferable):
- raise exceptions.InferenceError(node=node,
- context=context)
- if not hasattr(starred, 'elts'):
- raise exceptions.InferenceError(node=node,
- context=context)
- values.extend(_infer_seq(starred))
- else:
- values.append(elt)
- return values
-
-
- nodes.List._infer = infer_seq
- nodes.Tuple._infer = infer_seq
- nodes.Set._infer = infer_seq
-
-
- def infer_map(self, context=None):
- if not any(isinstance(k, nodes.DictUnpack) for k, _ in self.items):
- yield self
- else:
- items = _infer_map(self, context)
- new_seq = type(self)(self.lineno, self.col_offset, self.parent)
- new_seq.postinit(list(items.items()))
- yield new_seq
-
-
- def _infer_map(node, context):
- """Infer all values based on Dict.items"""
- values = {}
- for name, value in node.items:
- if isinstance(name, nodes.DictUnpack):
- double_starred = helpers.safe_infer(value, context)
- if double_starred in (None, util.Uninferable):
- raise exceptions.InferenceError
- if not isinstance(double_starred, nodes.Dict):
- raise exceptions.InferenceError(node=node,
- context=context)
- values.update(_infer_map(double_starred, context))
- else:
- key = helpers.safe_infer(name, context=context)
- value = helpers.safe_infer(value, context=context)
- if any(elem in (None, util.Uninferable) for elem in (key, value)):
- raise exceptions.InferenceError(node=node,
- context=context)
- values[key] = value
- return values
-
-
- nodes.Dict._infer = infer_map
-
-
- 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.FunctionDef):
- current = current.parent
- if current and current.parent:
- return current.parent
- return None
-
- 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 exceptions.NameInferenceError(name=self.name,
- scope=self.scope(),
- context=context)
- context = context.clone()
- context.lookupname = self.name
- return bases._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
-
-
- @decorators.raise_if_nothing_inferred
- @decorators.path_wrapper
- def infer_call(self, context=None):
- """infer a Call node by trying to guess what the function returns"""
- callcontext = context.clone()
- callcontext.callcontext = contextmod.CallContext(args=self.args,
- keywords=self.keywords)
- callcontext.boundnode = None
- for callee in self.func.infer(context):
- if callee is util.Uninferable:
- yield callee
- continue
- try:
- if hasattr(callee, 'infer_call_result'):
- for inferred in callee.infer_call_result(self, callcontext):
- yield inferred
- except exceptions.InferenceError:
- ## XXX log error ?
- continue
- # Explicit StopIteration to return error information, see comment
- # in raise_if_nothing_inferred.
- raise StopIteration(dict(node=self, context=context))
- nodes.Call._infer = infer_call
-
-
- @decorators.path_wrapper
- 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 exceptions.InferenceError(node=self, context=context)
-
- try:
- if asname:
- yield self.do_import_module(self.real_name(name))
- else:
- yield self.do_import_module(name)
- except exceptions.AstroidBuildingError as exc:
- util.reraise(exceptions.InferenceError(node=self, error=exc,
- context=context))
-
- 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
-
-
- @decorators.path_wrapper
- def infer_import_from(self, context=None, asname=True):
- """infer a ImportFrom node: return the imported module/object"""
- name = context.lookupname
- if name is None:
- raise exceptions.InferenceError(node=self, context=context)
- if asname:
- name = self.real_name(name)
-
- try:
- module = self.do_import_module()
- except exceptions.AstroidBuildingError as exc:
- util.reraise(exceptions.InferenceError(node=self, error=exc,
- context=context))
-
- try:
- context = contextmod.copy_context(context)
- context.lookupname = name
- stmts = module.getattr(name, ignore_locals=module is self.root())
- return bases._infer_stmts(stmts, context)
- except exceptions.AttributeInferenceError as error:
- util.reraise(exceptions.InferenceError(
- error.message, target=self, attribute=name, context=context))
- nodes.ImportFrom._infer = infer_import_from
-
-
- @decorators.raise_if_nothing_inferred
- def infer_attribute(self, context=None):
- """infer an Attribute node by using getattr on the associated object"""
- for owner in self.expr.infer(context):
- if owner is util.Uninferable:
- yield owner
- continue
-
- if context and context.boundnode:
- # This handles the situation where the attribute is accessed through a subclass
- # of a base class and the attribute is defined at the base class's level,
- # by taking in consideration a redefinition in the subclass.
- if (isinstance(owner, bases.Instance)
- and isinstance(context.boundnode, bases.Instance)):
- try:
- if helpers.is_subtype(helpers.object_type(context.boundnode),
- helpers.object_type(owner)):
- owner = context.boundnode
- except exceptions._NonDeducibleTypeHierarchy:
- # Can't determine anything useful.
- pass
-
- try:
- context.boundnode = owner
- for obj in owner.igetattr(self.attrname, context):
- yield obj
- context.boundnode = None
- except (exceptions.AttributeInferenceError, exceptions.InferenceError):
- context.boundnode = None
- except AttributeError:
- # XXX method / function
- context.boundnode = None
- # Explicit StopIteration to return error information, see comment
- # in raise_if_nothing_inferred.
- raise StopIteration(dict(node=self, context=context))
- nodes.Attribute._infer = decorators.path_wrapper(infer_attribute)
- nodes.AssignAttr.infer_lhs = infer_attribute # # won't work with a path wrapper
-
-
- @decorators.path_wrapper
- def infer_global(self, context=None):
- if context.lookupname is None:
- raise exceptions.InferenceError(node=self, context=context)
- try:
- return bases._infer_stmts(self.root().getattr(context.lookupname),
- context)
- except exceptions.AttributeInferenceError as error:
- util.reraise(exceptions.InferenceError(
- error.message, target=self, attribute=context.lookupname,
- context=context))
- nodes.Global._infer = infer_global
-
-
- _SUBSCRIPT_SENTINEL = object()
-
-
- @decorators.raise_if_nothing_inferred
- def infer_subscript(self, context=None):
- """Inference for subscripts
-
- We're understanding if the index is a Const
- or a slice, passing the result of inference
- to the value's `getitem` method, which should
- handle each supported index type accordingly.
- """
-
- value = next(self.value.infer(context))
- if value is util.Uninferable:
- yield util.Uninferable
- return
-
- index = next(self.slice.infer(context))
- if index is util.Uninferable:
- yield util.Uninferable
- return
-
- # Try to deduce the index value.
- index_value = _SUBSCRIPT_SENTINEL
- if value.__class__ == bases.Instance:
- index_value = index
- else:
- if index.__class__ == bases.Instance:
- instance_as_index = helpers.class_instance_as_index(index)
- if instance_as_index:
- index_value = instance_as_index
- else:
- index_value = index
- if index_value is _SUBSCRIPT_SENTINEL:
- raise exceptions.InferenceError(node=self, context=context)
-
- try:
- assigned = value.getitem(index_value, context)
- except (exceptions.AstroidTypeError,
- exceptions.AstroidIndexError,
- exceptions.AttributeInferenceError,
- AttributeError) as exc:
- util.reraise(exceptions.InferenceError(node=self, error=exc,
- context=context))
-
- # Prevent inferring if the inferred subscript
- # is the same as the original subscripted object.
- if self is assigned or assigned is util.Uninferable:
- yield util.Uninferable
- return
- for inferred in assigned.infer(context):
- yield inferred
-
- # Explicit StopIteration to return error information, see comment
- # in raise_if_nothing_inferred.
- raise StopIteration(dict(node=self, context=context))
-
- nodes.Subscript._infer = decorators.path_wrapper(infer_subscript)
- nodes.Subscript.infer_lhs = infer_subscript
-
-
- @decorators.raise_if_nothing_inferred
- @decorators.path_wrapper
- def _infer_boolop(self, context=None):
- """Infer a boolean operation (and / or / not).
-
- The function will calculate the boolean operation
- for all pairs generated through inference for each component
- node.
- """
- values = self.values
- if self.op == 'or':
- predicate = operator.truth
- else:
- predicate = operator.not_
-
- try:
- values = [value.infer(context=context) for value in values]
- except exceptions.InferenceError:
- yield util.Uninferable
- return
-
- for pair in itertools.product(*values):
- if any(item is util.Uninferable for item in pair):
- # Can't infer the final result, just yield Uninferable.
- yield util.Uninferable
- continue
-
- bool_values = [item.bool_value() for item in pair]
- if any(item is util.Uninferable for item in bool_values):
- # Can't infer the final result, just yield Uninferable.
- yield util.Uninferable
- continue
-
- # Since the boolean operations are short circuited operations,
- # this code yields the first value for which the predicate is True
- # and if no value respected the predicate, then the last value will
- # be returned (or Uninferable if there was no last value).
- # This is conforming to the semantics of `and` and `or`:
- # 1 and 0 -> 1
- # 0 and 1 -> 0
- # 1 or 0 -> 1
- # 0 or 1 -> 1
- value = util.Uninferable
- for value, bool_value in zip(pair, bool_values):
- if predicate(bool_value):
- yield value
- break
- else:
- yield value
-
- # Explicit StopIteration to return error information, see comment
- # in raise_if_nothing_inferred.
- raise StopIteration(dict(node=self, context=context))
-
- nodes.BoolOp._infer = _infer_boolop
-
-
- # UnaryOp, BinOp and AugAssign inferences
-
- def _filter_operation_errors(self, infer_callable, context, error):
- for result in infer_callable(self, context):
- if isinstance(result, error):
- # For the sake of .infer(), we don't care about operation
- # errors, which is the job of pylint. So return something
- # which shows that we can't infer the result.
- yield util.Uninferable
- else:
- yield result
-
-
- def _infer_unaryop(self, context=None):
- """Infer what an UnaryOp should return when evaluated."""
- for operand in self.operand.infer(context):
- try:
- yield operand.infer_unary_op(self.op)
- except TypeError as exc:
- # The operand doesn't support this operation.
- yield util.BadUnaryOperationMessage(operand, self.op, exc)
- except AttributeError as exc:
- meth = protocols.UNARY_OP_METHOD[self.op]
- if meth is None:
- # `not node`. Determine node's boolean
- # value and negate its result, unless it is
- # Uninferable, which will be returned as is.
- bool_value = operand.bool_value()
- if bool_value is not util.Uninferable:
- yield nodes.const_factory(not bool_value)
- else:
- yield util.Uninferable
- else:
- if not isinstance(operand, (bases.Instance, nodes.ClassDef)):
- # The operation was used on something which
- # doesn't support it.
- yield util.BadUnaryOperationMessage(operand, self.op, exc)
- continue
-
- try:
- try:
- methods = dunder_lookup.lookup(operand, meth)
- except exceptions.AttributeInferenceError:
- yield util.BadUnaryOperationMessage(operand, self.op, exc)
- continue
-
- meth = methods[0]
- inferred = next(meth.infer(context=context))
- if inferred is util.Uninferable or not inferred.callable():
- continue
-
- context = contextmod.copy_context(context)
- context.callcontext = contextmod.CallContext(args=[operand])
- call_results = inferred.infer_call_result(self, context=context)
- result = next(call_results, None)
- if result is None:
- # Failed to infer, return the same type.
- yield operand
- else:
- yield result
- except exceptions.AttributeInferenceError as exc:
- # The unary operation special method was not found.
- yield util.BadUnaryOperationMessage(operand, self.op, exc)
- except exceptions.InferenceError:
- yield util.Uninferable
-
-
- @decorators.raise_if_nothing_inferred
- @decorators.path_wrapper
- def infer_unaryop(self, context=None):
- """Infer what an UnaryOp should return when evaluated."""
- for inferred in _filter_operation_errors(self, _infer_unaryop, context,
- util.BadUnaryOperationMessage):
- yield inferred
- # Explicit StopIteration to return error information, see comment
- # in raise_if_nothing_inferred.
- raise StopIteration(dict(node=self, context=context))
-
- 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
-
-
- def _invoke_binop_inference(instance, opnode, op, other, context, method_name):
- """Invoke binary operation inference on the given instance."""
- methods = dunder_lookup.lookup(instance, method_name)
- method = methods[0]
- inferred = next(method.infer(context=context))
- if inferred is util.Uninferable:
- raise exceptions.InferenceError
- return instance.infer_binary_op(opnode, op, other, context, inferred)
-
-
- def _aug_op(instance, opnode, op, other, context, 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, opnode=opnode, other=other,
- context=context,
- method_name=method_name)
-
-
- def _bin_op(instance, opnode, op, other, context, reverse=False):
- """Get an inference callable for a normal binary operation.
-
- If *reverse* is True, then the reflected method will be used instead.
- """
- if reverse:
- method_name = protocols.REFLECTED_BIN_OP_METHOD[op]
- else:
- method_name = protocols.BIN_OP_METHOD[op]
- return functools.partial(_invoke_binop_inference,
- instance=instance,
- op=op, opnode=opnode, other=other,
- context=context,
- method_name=method_name)
-
-
- def _get_binop_contexts(context, left, right):
- """Get contexts for binary operations.
-
- This will return two inferrence contexts, the first one
- for x.__op__(y), the other one for y.__rop__(x), where
- only the arguments are inversed.
- """
- # The order is important, since the first one should be
- # left.__op__(right).
- for arg in (right, left):
- new_context = context.clone()
- new_context.callcontext = contextmod.CallContext(args=[arg])
- new_context.boundnode = None
- yield new_context
-
-
- def _same_type(type1, type2):
- """Check if type1 is the same as type2."""
- return type1.qname() == type2.qname()
-
-
- def _get_binop_flow(left, left_type, binary_opnode, right, right_type,
- context, reverse_context):
- """Get the flow for binary operations.
-
- The rules are a bit messy:
-
- * if left and right have the same type, then only one
- method will be called, left.__op__(right)
- * if left and right are unrelated typewise, then first
- left.__op__(right) is tried and if this does not exist
- or returns NotImplemented, then right.__rop__(left) is tried.
- * if left is a subtype of right, then only left.__op__(right)
- is tried.
- * if left is a supertype of right, then right.__rop__(left)
- is first tried and then left.__op__(right)
- """
- op = binary_opnode.op
- if _same_type(left_type, right_type):
- methods = [_bin_op(left, binary_opnode, op, right, context)]
- elif helpers.is_subtype(left_type, right_type):
- methods = [_bin_op(left, binary_opnode, op, right, context)]
- elif helpers.is_supertype(left_type, right_type):
- methods = [_bin_op(right, binary_opnode, op, left, reverse_context, reverse=True),
- _bin_op(left, binary_opnode, op, right, context)]
- else:
- methods = [_bin_op(left, binary_opnode, op, right, context),
- _bin_op(right, binary_opnode, op, left, reverse_context, reverse=True)]
- return methods
-
-
- def _get_aug_flow(left, left_type, aug_opnode, right, right_type,
- context, reverse_context):
- """Get the flow for augmented binary operations.
-
- The rules are a bit messy:
-
- * if left and right have the same type, then left.__augop__(right)
- is first tried and then left.__op__(right).
- * if left and right are unrelated typewise, then
- left.__augop__(right) is tried, then left.__op__(right)
- is tried and then right.__rop__(left) is tried.
- * if left is a subtype of right, then left.__augop__(right)
- is tried and then left.__op__(right).
- * if left is a supertype of right, then left.__augop__(right)
- is tried, then right.__rop__(left) and then
- left.__op__(right)
- """
- bin_op = aug_opnode.op.strip("=")
- aug_op = aug_opnode.op
- if _same_type(left_type, right_type):
- methods = [_aug_op(left, aug_opnode, aug_op, right, context),
- _bin_op(left, aug_opnode, bin_op, right, context)]
- elif helpers.is_subtype(left_type, right_type):
- methods = [_aug_op(left, aug_opnode, aug_op, right, context),
- _bin_op(left, aug_opnode, bin_op, right, context)]
- elif helpers.is_supertype(left_type, right_type):
- methods = [_aug_op(left, aug_opnode, aug_op, right, context),
- _bin_op(right, aug_opnode, bin_op, left, reverse_context, reverse=True),
- _bin_op(left, aug_opnode, bin_op, right, context)]
- else:
- methods = [_aug_op(left, aug_opnode, aug_op, right, context),
- _bin_op(left, aug_opnode, bin_op, right, context),
- _bin_op(right, aug_opnode, bin_op, left, reverse_context, reverse=True)]
- return methods
-
-
- def _infer_binary_operation(left, right, binary_opnode, context, flow_factory):
- """Infer a binary operation between a left operand and a right operand
-
- This is used by both normal binary operations and augmented binary
- operations, the only difference is the flow factory used.
- """
-
- context, reverse_context = _get_binop_contexts(context, left, right)
- left_type = helpers.object_type(left)
- right_type = helpers.object_type(right)
- methods = flow_factory(left, left_type, binary_opnode, right, right_type,
- context, reverse_context)
- for method in methods:
- try:
- results = list(method())
- except AttributeError:
- continue
- except exceptions.AttributeInferenceError:
- continue
- except exceptions.InferenceError:
- yield util.Uninferable
- return
- else:
- if any(result is util.Uninferable for result in results):
- yield util.Uninferable
- return
-
- # TODO(cpopa): since the inference engine might return
- # more values than are actually possible, we decide
- # to return util.Uninferable if we have union types.
- if all(map(_is_not_implemented, results)):
- continue
- not_implemented = sum(1 for result in results
- if _is_not_implemented(result))
- if not_implemented and not_implemented != len(results):
- # Can't decide yet what this is, not yet though.
- yield util.Uninferable
- return
-
- for result in results:
- yield result
- return
- # TODO(cpopa): yield a BadBinaryOperationMessage here,
- # since the operation is not supported
- yield util.BadBinaryOperationMessage(left_type, binary_opnode.op, right_type)
-
-
- def _infer_binop(self, context):
- """Binary operation inferrence logic."""
- if context is None:
- context = contextmod.InferenceContext()
- left = self.left
- right = self.right
-
- # we use two separate contexts for evaluating lhs and rhs because
- # 1. evaluating lhs may leave some undesired entries in context.path
- # which may not let us infer right value of rhs
- lhs_context = context.clone()
- rhs_context = context.clone()
-
- for lhs in left.infer(context=lhs_context):
- if lhs is util.Uninferable:
- # Don't know how to process this.
- yield util.Uninferable
- return
-
- for rhs in right.infer(context=rhs_context):
- if rhs is util.Uninferable:
- # Don't know how to process this.
- yield util.Uninferable
- return
-
- try:
- for result in _infer_binary_operation(lhs, rhs, self,
- context, _get_binop_flow):
- yield result
- except exceptions._NonDeducibleTypeHierarchy:
- yield util.Uninferable
-
-
- @decorators.yes_if_nothing_inferred
- @decorators.path_wrapper
- def infer_binop(self, context=None):
- return _filter_operation_errors(self, _infer_binop, context,
- util.BadBinaryOperationMessage)
-
- nodes.BinOp._infer_binop = _infer_binop
- nodes.BinOp._infer = infer_binop
-
-
- def _infer_augassign(self, context=None):
- """Inference logic for augmented binary operations."""
- if context is None:
- context = contextmod.InferenceContext()
-
- for lhs in self.target.infer_lhs(context=context):
- if lhs is util.Uninferable:
- # Don't know how to process this.
- yield util.Uninferable
- return
-
- rhs_context = context.clone()
- for rhs in self.value.infer(context=rhs_context):
- if rhs is util.Uninferable:
- # Don't know how to process this.
- yield util.Uninferable
- return
-
- try:
- for result in _infer_binary_operation(lhs, rhs, self, context, _get_aug_flow):
- yield result
- except exceptions._NonDeducibleTypeHierarchy:
- yield util.Uninferable
-
-
- @decorators.path_wrapper
- def infer_augassign(self, context=None):
- return _filter_operation_errors(self, _infer_augassign, context,
- util.BadBinaryOperationMessage)
-
- nodes.AugAssign._infer_augassign = _infer_augassign
- nodes.AugAssign._infer = infer_augassign
-
- # End of binary operation inference.
-
-
- def infer_arguments(self, context=None):
- name = context.lookupname
- if name is None:
- raise exceptions.InferenceError(node=self, context=context)
- return protocols._arguments_infer_argname(self, name, context)
- nodes.Arguments._infer = infer_arguments
-
-
- @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):
- return stmt.infer(context)
-
- stmts = list(self.assigned_stmts(context=context))
- return bases._infer_stmts(stmts, context)
- nodes.AssignName._infer = infer_assign
- nodes.AssignAttr._infer = infer_assign
-
-
- # no infer method on DelName and DelAttr (expected InferenceError)
-
- @decorators.path_wrapper
- def infer_empty_node(self, context=None):
- if not self.has_underlying_object():
- yield util.Uninferable
- else:
- try:
- for inferred in MANAGER.infer_ast_from_something(self.object,
- context=context):
- yield inferred
- except exceptions.AstroidError:
- yield util.Uninferable
- nodes.EmptyNode._infer = infer_empty_node
-
-
- def infer_index(self, context=None):
- return self.value.infer(context)
- nodes.Index._infer = infer_index
-
- # TODO: move directly into bases.Instance when the dependency hell
- # will be solved.
- def instance_getitem(self, index, context=None):
- # Rewrap index to Const for this case
- if context:
- new_context = context.clone()
- else:
- context = new_context = contextmod.InferenceContext()
-
- # Create a new callcontext for providing index as an argument.
- new_context.callcontext = contextmod.CallContext(args=[index])
- new_context.boundnode = self
-
- method = next(self.igetattr('__getitem__', context=context))
- if not isinstance(method, bases.BoundMethod):
- raise exceptions.InferenceError(
- 'Could not find __getitem__ for {node!r}.',
- node=self, context=context)
-
- try:
- return next(method.infer_call_result(self, new_context))
- except StopIteration:
- util.reraise(exceptions.InferenceError(
- message='Inference for {node!r}[{index!s}] failed.',
- node=self, index=index, context=context))
-
- bases.Instance.getitem = instance_getitem
|