summaryrefslogtreecommitdiff
path: root/venv/Lib/site-packages/astroid/inference.py
diff options
context:
space:
mode:
Diffstat (limited to 'venv/Lib/site-packages/astroid/inference.py')
-rw-r--r--venv/Lib/site-packages/astroid/inference.py943
1 files changed, 0 insertions, 943 deletions
diff --git a/venv/Lib/site-packages/astroid/inference.py b/venv/Lib/site-packages/astroid/inference.py
deleted file mode 100644
index 77c6b1d..0000000
--- a/venv/Lib/site-packages/astroid/inference.py
+++ /dev/null
@@ -1,943 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
-# Copyright (c) 2013-2014 Google, Inc.
-# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com>
-# Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com>
-# Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2017 Michał Masłowski <m.maslowski@clearcode.cc>
-# Copyright (c) 2017 Calen Pennington <cale@edx.org>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
-# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
-# Copyright (c) 2018 Ashley Whetter <ashley@awhetter.co.uk>
-# Copyright (c) 2018 HoverHell <hoverhell@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_sequence_helper(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 not starred:
- raise exceptions.InferenceError(node=node, context=context)
- if not hasattr(starred, "elts"):
- raise exceptions.InferenceError(node=node, context=context)
- values.extend(_infer_sequence_helper(starred))
- elif isinstance(elt, nodes.NamedExpr):
- value = helpers.safe_infer(elt.value, context)
- if not value:
- raise exceptions.InferenceError(node=node, context=context)
- values.append(value)
- else:
- values.append(elt)
- return values
-
-
-@decorators.raise_if_nothing_inferred
-def infer_sequence(self, context=None):
- has_starred_named_expr = any(
- isinstance(e, (nodes.Starred, nodes.NamedExpr)) for e in self.elts
- )
- if has_starred_named_expr:
- values = _infer_sequence_helper(self, context)
- new_seq = type(self)(
- lineno=self.lineno, col_offset=self.col_offset, parent=self.parent
- )
- new_seq.postinit(values)
-
- yield new_seq
- else:
- yield self
-
-
-nodes.List._infer = infer_sequence
-nodes.Tuple._infer = infer_sequence
-nodes.Set._infer = infer_sequence
-
-
-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 _update_with_replacement(lhs_dict, rhs_dict):
- """Delete nodes that equate to duplicate keys
-
- Since an astroid node doesn't 'equal' another node with the same value,
- this function uses the as_string method to make sure duplicate keys
- don't get through
-
- Note that both the key and the value are astroid nodes
-
- Fixes issue with DictUnpack causing duplicte keys
- in inferred Dict items
-
- :param dict(nodes.NodeNG, nodes.NodeNG) lhs_dict: Dictionary to 'merge' nodes into
- :param dict(nodes.NodeNG, nodes.NodeNG) rhs_dict: Dictionary with nodes to pull from
- :return dict(nodes.NodeNG, nodes.NodeNG): merged dictionary of nodes
- """
- combined_dict = itertools.chain(lhs_dict.items(), rhs_dict.items())
- # Overwrite keys which have the same string values
- string_map = {key.as_string(): (key, value) for key, value in combined_dict}
- # Return to dictionary
- return dict(string_map.values())
-
-
-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 not double_starred:
- raise exceptions.InferenceError
- if not isinstance(double_starred, nodes.Dict):
- raise exceptions.InferenceError(node=node, context=context)
- unpack_items = _infer_map(double_starred, context)
- values = _update_with_replacement(values, unpack_items)
- else:
- key = helpers.safe_infer(name, context=context)
- value = helpers.safe_infer(value, context=context)
- if any(not elem for elem in (key, value)):
- raise exceptions.InferenceError(node=node, context=context)
- values = _update_with_replacement(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.
- 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 = contextmod.copy_context(context)
- context.lookupname = self.name
- return bases._infer_stmts(stmts, context, frame)
-
-
-# pylint: disable=no-value-for-parameter
-nodes.Name._infer = decorators.raise_if_nothing_inferred(
- 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 = contextmod.copy_context(context)
- callcontext.callcontext = contextmod.CallContext(
- args=self.args, keywords=self.keywords
- )
- callcontext.boundnode = None
- if context is not None:
- callcontext.extra_context = _populate_context_lookup(self, context.clone())
-
- for callee in self.func.infer(context):
- if callee is util.Uninferable:
- yield callee
- continue
- try:
- if hasattr(callee, "infer_call_result"):
- yield from callee.infer_call_result(caller=self, context=callcontext)
- except exceptions.InferenceError:
- continue
- return dict(node=self, context=context)
-
-
-nodes.Call._infer = infer_call
-
-
-@decorators.raise_if_nothing_inferred
-@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:
- raise exceptions.InferenceError(node=self, context=context) from exc
-
-
-nodes.Import._infer = infer_import
-
-
-@decorators.raise_if_nothing_inferred
-@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:
- raise exceptions.InferenceError(node=self, context=context) from exc
-
- 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:
- raise exceptions.InferenceError(
- error.message, target=self, attribute=name, context=context
- ) from error
-
-
-nodes.ImportFrom._infer = infer_import_from
-
-
-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
- yield from owner.igetattr(self.attrname, context)
- context.boundnode = None
- except (exceptions.AttributeInferenceError, exceptions.InferenceError):
- context.boundnode = None
- except AttributeError:
- # XXX method / function
- context.boundnode = None
- return dict(node=self, context=context)
-
-
-nodes.Attribute._infer = decorators.raise_if_nothing_inferred(
- decorators.path_wrapper(infer_attribute)
-)
-# won't work with a path wrapper
-nodes.AssignAttr.infer_lhs = decorators.raise_if_nothing_inferred(infer_attribute)
-
-
-@decorators.raise_if_nothing_inferred
-@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:
- raise exceptions.InferenceError(
- error.message, target=self, attribute=context.lookupname, context=context
- ) from error
-
-
-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.
- """
-
- found_one = False
- for value in self.value.infer(context):
- if value is util.Uninferable:
- yield util.Uninferable
- return None
- for index in self.slice.infer(context):
- if index is util.Uninferable:
- yield util.Uninferable
- return None
-
- # 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:
- raise exceptions.InferenceError(node=self, context=context) from exc
-
- # 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 None
- yield from assigned.infer(context)
- found_one = True
-
- if found_one:
- return dict(node=self, context=context)
- return None
-
-
-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 None
-
- 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
-
- return 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."""
- yield from _filter_operation_errors(
- self, _infer_unaryop, context, util.BadUnaryOperationMessage
- )
- return 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)
- context = contextmod.bind_context_to_node(context, instance)
- 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 inference 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
-
- 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 infer yet what this is.
- yield util.Uninferable
- return
-
- yield from results
- return
- # The operation doesn't seem to be supported so let the caller know about it
- yield util.BadBinaryOperationMessage(left_type, binary_opnode.op, right_type)
-
-
-def _infer_binop(self, context):
- """Binary operation inference logic."""
- 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
- context = context or contextmod.InferenceContext()
- lhs_context = contextmod.copy_context(context)
- rhs_context = contextmod.copy_context(context)
- lhs_iter = left.infer(context=lhs_context)
- rhs_iter = right.infer(context=rhs_context)
- for lhs, rhs in itertools.product(lhs_iter, rhs_iter):
- if any(value is util.Uninferable for value in (rhs, lhs)):
- # Don't know how to process this.
- yield util.Uninferable
- return
-
- try:
- yield from _infer_binary_operation(lhs, rhs, self, context, _get_binop_flow)
- 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()
-
- rhs_context = context.clone()
-
- lhs_iter = self.target.infer_lhs(context=context)
- rhs_iter = self.value.infer(context=rhs_context)
- for lhs, rhs in itertools.product(lhs_iter, rhs_iter):
- if any(value is util.Uninferable for value in (rhs, lhs)):
- # Don't know how to process this.
- yield util.Uninferable
- return
-
- try:
- yield from _infer_binary_operation(
- left=lhs,
- right=rhs,
- binary_opnode=self,
- context=context,
- flow_factory=_get_aug_flow,
- )
- except exceptions._NonDeducibleTypeHierarchy:
- yield util.Uninferable
-
-
-@decorators.raise_if_nothing_inferred
-@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.
-
-
-@decorators.raise_if_nothing_inferred
-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.raise_if_nothing_inferred
-@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
-
-
-@decorators.raise_if_nothing_inferred
-@decorators.path_wrapper
-def infer_empty_node(self, context=None):
- if not self.has_underlying_object():
- yield util.Uninferable
- else:
- try:
- yield from MANAGER.infer_ast_from_something(self.object, context=context)
- except exceptions.AstroidError:
- yield util.Uninferable
-
-
-nodes.EmptyNode._infer = infer_empty_node
-
-
-@decorators.raise_if_nothing_inferred
-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
- new_context = contextmod.bind_context_to_node(context, self)
- if not context:
- context = new_context
-
- # Create a new callcontext for providing index as an argument.
- new_context.callcontext = contextmod.CallContext(args=[index])
-
- method = next(self.igetattr("__getitem__", context=context), None)
- if not isinstance(method, bases.BoundMethod):
- raise exceptions.InferenceError(
- "Could not find __getitem__ for {node!r}.", node=self, context=context
- )
-
- return next(method.infer_call_result(self, new_context))
-
-
-bases.Instance.getitem = instance_getitem
-
-
-def _populate_context_lookup(call, context):
- # Allows context to be saved for later
- # for inference inside a function
- context_lookup = {}
- if context is None:
- return context_lookup
- for arg in call.args:
- if isinstance(arg, nodes.Starred):
- context_lookup[arg.value] = context
- else:
- context_lookup[arg] = context
- keywords = call.keywords if call.keywords is not None else []
- for keyword in keywords:
- context_lookup[keyword.value] = context
- return context_lookup
-
-
-@decorators.raise_if_nothing_inferred
-def infer_ifexp(self, context=None):
- """Support IfExp inference
-
- If we can't infer the truthiness of the condition, we default
- to inferring both branches. Otherwise, we infer either branch
- depending on the condition.
- """
- both_branches = False
- # We use two separate contexts for evaluating lhs and rhs because
- # evaluating lhs may leave some undesired entries in context.path
- # which may not let us infer right value of rhs.
-
- context = context or contextmod.InferenceContext()
- lhs_context = contextmod.copy_context(context)
- rhs_context = contextmod.copy_context(context)
- try:
- test = next(self.test.infer(context=context.clone()))
- except exceptions.InferenceError:
- both_branches = True
- else:
- if test is not util.Uninferable:
- if test.bool_value():
- yield from self.body.infer(context=lhs_context)
- else:
- yield from self.orelse.infer(context=rhs_context)
- else:
- both_branches = True
- if both_branches:
- yield from self.body.infer(context=lhs_context)
- yield from self.orelse.infer(context=rhs_context)
-
-
-nodes.IfExp._infer = infer_ifexp