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 not context: context = InferenceContext() old_boundnode = context.boundnode try: context.boundnode = owner yield from owner.igetattr(self.attrname, context) except ( AttributeInferenceError, InferenceError, AttributeError, ): pass finally: context.boundnode = old_boundnode return dict(node=self, context=context)
def class_instance_as_index(node): """Get the value as an index for the given instance. If an instance provides an __index__ method, then it can be used in some scenarios where an integer is expected, for instance when multiplying or subscripting a list. """ context = InferenceContext() try: for inferred in node.igetattr("__index__", context=context): if not isinstance(inferred, bases.BoundMethod): continue context.boundnode = node context.callcontext = CallContext(args=[], callee=inferred) for result in inferred.infer_call_result(node, context=context): if isinstance(result, nodes.Const) and isinstance( result.value, int): return result except InferenceError: pass return None
def tl_infer_binary_op( self, opnode: nodes.BinOp, operator: str, other: nodes.NodeNG, context: InferenceContext, method: nodes.FunctionDef, ) -> Generator[nodes.NodeNG | type[util.Uninferable], None, None]: """Infer a binary operation on a tuple or list. The instance on which the binary operation is performed is a tuple or list. This refers to the left-hand side of the operation, so: 'tuple() + 1' or '[] + A()' """ # For tuples and list the boundnode is no longer the tuple or list instance context.boundnode = None not_implemented = nodes.Const(NotImplemented) if isinstance(other, self.__class__) and operator == "+": node = self.__class__(parent=opnode) node.elts = list( itertools.chain( _filter_uninferable_nodes(self.elts, context), _filter_uninferable_nodes(other.elts, context), )) yield node elif isinstance(other, nodes.Const) and operator == "*": if not isinstance(other.value, int): yield not_implemented return yield _multiply_seq_by_int(self, opnode, other, context) elif isinstance(other, bases.Instance) and operator == "*": # Verify if the instance supports __index__. as_index = helpers.class_instance_as_index(other) if not as_index: yield util.Uninferable else: yield _multiply_seq_by_int(self, opnode, as_index, context) else: yield not_implemented