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
def query_call(self: nodes.Call, context=None): """query 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: # extra context saved the args, what's for? callcontext.extra_context = _populate_context_lookup( self, context.clone()) for callee in self.func.query(context): if callee is util.Uninferable: yield callee continue if callee is util.Unqueryable: if not isinstance(self.keywords, None): # not implemented print(kv) assert False return self.args try: if hasattr(callee, "query_call_result"): # no filed sensitive here yield from callee.query_call_result(caller=self, context=callcontext) except exceptions.InferenceError: continue return dict(node=self, context=context)
def infer_call_result(self, caller, context=None): if len(caller.args) != 2: raise exceptions.InferenceError( "Invalid arguments for descriptor binding", target=self, context=context) context = contextmod.copy_context(context) cls = next(caller.args[0].infer(context=context)) if cls is astroid.Uninferable: raise exceptions.InferenceError( "Invalid class inferred", target=self, context=context) # For some reason func is a Node that the below # code is not expecting if isinstance(func, bases.BoundMethod): yield func return # Rebuild the original value, but with the parent set as the # class where it will be bound. new_func = func.__class__(name=func.name, doc=func.doc, lineno=func.lineno, col_offset=func.col_offset, parent=cls) # pylint: disable=no-member new_func.postinit(func.args, func.body, func.decorators, func.returns) # Build a proper bound method that points to our newly built function. proxy = bases.UnboundMethod(new_func) yield bases.BoundMethod(proxy=proxy, bound=cls)
def infer_call_result(self, caller, context=None): if len(caller.args) != 2: raise exceptions.InferenceError( "Invalid arguments for descriptor binding", target=self, context=context) context = contextmod.copy_context(context) cls = next(caller.args[0].infer(context=context)) if cls is astroid.Uninferable: raise exceptions.InferenceError("Invalid class inferred", target=self, context=context) # For some reason func is a Node that the below # code is not expecting if isinstance(func, bases.BoundMethod): yield func return # Rebuild the original value, but with the parent set as the # class where it will be bound. new_func = func.__class__(name=func.name, doc=func.doc, lineno=func.lineno, col_offset=func.col_offset, parent=cls) # pylint: disable=no-member new_func.postinit(func.args, func.body, func.decorators, func.returns) # Build a proper bound method that points to our newly built function. proxy = bases.UnboundMethod(new_func) yield bases.BoundMethod(proxy=proxy, bound=cls)
def arguments_assigned_stmts(self, node=None, context=None, asspath=None): if context.callcontext: # reset call context/name callcontext = context.callcontext context = contextmod.copy_context(context) context.callcontext = None args = arguments.CallSite(callcontext) return args.infer_argument(self.parent, node.name, context) return _arguments_infer_argname(self, node.name, context)
def _arguments_infer_argname(self, name, context): # arguments information may be missing, in which case we can't do anything # more if not (self.arguments or self.vararg or self.kwarg): yield util.Uninferable return functype = self.parent.type # first argument of instance/class method if ( self.arguments and getattr(self.arguments[0], "name", None) == name and functype != "staticmethod" ): cls = self.parent.parent.scope() is_metaclass = isinstance(cls, nodes.ClassDef) and cls.type == "metaclass" # If this is a metaclass, then the first argument will always # be the class, not an instance. if context.boundnode and isinstance(context.boundnode, bases.Instance): cls = context.boundnode._proxied if is_metaclass or functype == "classmethod": yield cls return if functype == "method": yield cls.instantiate_class() return if context and context.callcontext: callee = context.callcontext.callee while hasattr(callee, "_proxied"): callee = callee._proxied if getattr(callee, "name", None) == self.parent.name: call_site = arguments.CallSite(context.callcontext, context.extra_context) yield from call_site.infer_argument(self.parent, name, context) return if name == self.vararg: vararg = nodes.const_factory(()) vararg.parent = self if not self.arguments and self.parent.name == "__init__": cls = self.parent.parent.scope() vararg.elts = [cls.instantiate_class()] yield vararg return if name == self.kwarg: kwarg = nodes.const_factory({}) kwarg.parent = self yield kwarg return # if there is a default value, yield it. And then yield Uninferable to reflect # we can't guess given argument value try: context = copy_context(context) yield from self.default_value(name).infer(context) yield util.Uninferable except NoDefault: yield util.Uninferable
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 AttributeInferenceError: yield util.BadUnaryOperationMessage( operand, self.op, exc) continue meth = methods[0] inferred = next(meth.infer(context=context), None) if inferred is util.Uninferable or not inferred.callable(): continue context = copy_context(context) context.boundnode = operand context.callcontext = CallContext(args=[], callee=inferred) 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 AttributeInferenceError as exc: # The unary operation special method was not found. yield util.BadUnaryOperationMessage(operand, self.op, exc) except InferenceError: yield util.Uninferable
def arguments_query_assigned_stmts(self, node=None, context=None, assign_path=None): if context.callcontext: # reset call context/name callcontext = context.callcontext context = contextmod.copy_context(context) context.callcontext = None args = arguments.CallSite(callcontext, context=context) return args.query_argument(self.parent, node.name, context) # no call context means that we get to the end point # print("end point here!!") node.query_end = True return [node]
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
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
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() if asname: name = self.real_name(name) module = self.do_import_module() 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.NotFoundError: raise exceptions.InferenceError(name)
def arguments_assigned_stmts(self, node=None, context=None, assign_path=None): if context.callcontext: callee = context.callcontext.callee while hasattr(callee, "_proxied"): callee = callee._proxied else: callee = None if (context.callcontext and node and getattr(callee, "name", None) == node.frame().name): # reset call context/name callcontext = context.callcontext context = copy_context(context) context.callcontext = None args = arguments.CallSite(callcontext, context=context) return args.infer_argument(self.parent, node.name, context) return _arguments_infer_argname(self, node.name, context)
def _arguments_infer_argname(self, name, context): # arguments information may be missing, in which case we can't do anything # more if not (self.args or self.vararg or self.kwarg): yield util.Uninferable return # first argument of instance/class method if self.args and getattr(self.args[0], 'name', None) == name: functype = self.parent.type cls = self.parent.parent.scope() is_metaclass = isinstance(cls, nodes.ClassDef) and cls.type == 'metaclass' # If this is a metaclass, then the first argument will always # be the class, not an instance. if is_metaclass or functype == 'classmethod': yield cls return if functype == 'method': yield bases.Instance(self.parent.parent.frame()) return if context and context.callcontext: call_site = arguments.CallSite(context.callcontext) for value in call_site.infer_argument(self.parent, name, context): yield value return # TODO: just provide the type here, no need to have an empty Dict. if name == self.vararg: vararg = nodes.const_factory(()) vararg.parent = self yield vararg return if name == self.kwarg: kwarg = nodes.const_factory({}) kwarg.parent = self yield kwarg return # if there is a default value, yield it. And then yield Uninferable to reflect # we can't guess given argument value try: context = contextmod.copy_context(context) for inferred in self.default_value(name).infer(context): yield inferred yield util.Uninferable except exceptions.NoDefault: yield util.Uninferable
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)
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)
def infer_call_result(self, caller, context=None): if len(caller.args) != 2: raise exceptions.InferenceError( "Invalid arguments for descriptor binding", target=self, context=context) context = contextmod.copy_context(context) cls = next(caller.args[0].infer(context=context)) # Rebuild the original value, but with the parent set as the # class where it will be bound. new_func = func.__class__(name=func.name, doc=func.doc, lineno=func.lineno, col_offset=func.col_offset, parent=cls) new_func.postinit(func.args, func.body, func.decorators, func.returns) # Build a proper bound method that points to our newly built function. proxy = bases.UnboundMethod(new_func) yield bases.BoundMethod(proxy=proxy, bound=cls)
def infer_name( self: nodes.Name | nodes.AssignName, context: InferenceContext | None = None, **kwargs: Any, ) -> Generator[InferenceResult, None, 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 NameInferenceError(name=self.name, scope=self.scope(), context=context) context = copy_context(context) context.lookupname = self.name return bases._infer_stmts(stmts, context, frame)
def arguments_assigned_stmts( self: nodes.Arguments, node: node_classes.AssignedStmtsPossibleNode = None, context: Optional[InferenceContext] = None, assign_path: Optional[List[int]] = None, ) -> Any: if context.callcontext: callee = context.callcontext.callee while hasattr(callee, "_proxied"): callee = callee._proxied else: callee = None if (context.callcontext and node and getattr(callee, "name", None) == node.frame(future=True).name): # reset call context/name callcontext = context.callcontext context = copy_context(context) context.callcontext = None args = arguments.CallSite(callcontext, context=context) return args.infer_argument(self.parent, node.name, context) return _arguments_infer_argname(self, node.name, context)
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
def query_call(self: nodes.Call, context=None): """query 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: # extra context saved the args, what's for? callcontext.extra_context = _populate_context_lookup( self, context.clone()) res = [] for callee in self.func.query(context): if callee is util.Unqueryable: if self.keywords is not None: # not implemented print(self.keywords) assert False for arg in self.args: res.extend(arg.query(context)) continue if hasattr(callee, "query_end") and callee.query_end: res.append(callee) continue try: if hasattr(callee, "query_call_result"): for result in callee.query_call_result(caller=self, context=callcontext): if result is util.Unqueryable: for arg in self.args: res.extend(arg.query(context)) else: res.append(result) except exceptions.InferenceError: continue return res
def __init__(self, parent=None, generator_initial_context=None): super().__init__() self.parent = parent self._call_context = copy_context(generator_initial_context)