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 # first argument of instance/class method if self.arguments and getattr(self.arguments[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(cls) return if context and context.callcontext: 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 = [bases.Instance(cls)] 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) yield from self.default_value(name).infer(context) yield util.Uninferable except exceptions.NoDefault: yield util.Uninferable
def excepthandler_assigned_stmts(self, node=None, context=None, asspath=None): for assigned in node_classes.unpack_infer(self.type): if isinstance(assigned, nodes.ClassDef): assigned = bases.Instance(assigned) yield assigned # Explicit StopIteration to return error information, see comment # in raise_if_nothing_inferred. raise StopIteration( dict(node=self, unknown=node, assign_path=asspath, context=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 interfaces(node, herited=True, handler_func=_iface_hdlr): """Return an iterator on interfaces implemented by the given class node.""" try: implements = bases.Instance(node).getattr("__implements__")[0] except exceptions.NotFoundError: return if not herited and implements.frame() is not node: return found = set() missing = False for iface in node_classes.unpack_infer(implements): if iface is astroid.Uninferable: missing = True continue if iface not in found and handler_func(iface): found.add(iface) yield iface if missing: raise exceptions.InferenceError()
def excepthandler_assigned_stmts(self, node=None, context=None, asspath=None): for assigned in node_classes.unpack_infer(self.type): if isinstance(assigned, nodes.ClassDef): assigned = bases.Instance(assigned) yield assigned
def infer_argument(self, funcnode, name, context): """infer a function argument value according to the call context Arguments: funcnode: The function being called. name: The name of the argument whose value is being inferred. context: TODO """ if name in self.duplicated_keywords: raise exceptions.InferenceError( 'The arguments passed to {func!r} ' ' have duplicate keywords.', call_site=self, func=funcnode, arg=name, context=context) # Look into the keywords first, maybe it's already there. try: return self.keyword_arguments[name].infer(context) except KeyError: pass # Too many arguments given and no variable arguments. if len(self.positional_arguments) > len(funcnode.args.args): if not funcnode.args.vararg: raise exceptions.InferenceError( 'Too many positional arguments ' 'passed to {func!r} that does ' 'not have *args.', call_site=self, func=funcnode, arg=name, context=context) positional = self.positional_arguments[:len(funcnode.args.args)] vararg = self.positional_arguments[len(funcnode.args.args):] argindex = funcnode.args.find_argname(name)[0] kwonlyargs = set(arg.name for arg in funcnode.args.kwonlyargs) kwargs = { key: value for key, value in self.keyword_arguments.items() if key not in kwonlyargs } # If there are too few positionals compared to # what the function expects to receive, check to see # if the missing positional arguments were passed # as keyword arguments and if so, place them into the # positional args list. if len(positional) < len(funcnode.args.args): for func_arg in funcnode.args.args: if func_arg.name in kwargs: arg = kwargs.pop(func_arg.name) positional.append(arg) if argindex is not None: # 2. first argument of instance/class method if argindex == 0 and funcnode.type in ('method', 'classmethod'): if context.boundnode is not None: boundnode = context.boundnode else: # XXX can do better ? boundnode = funcnode.parent.frame() if isinstance(boundnode, nodes.ClassDef): # Verify that we're accessing a method # of the metaclass through a class, as in # `cls.metaclass_method`. In this case, the # first argument is always the class. method_scope = funcnode.parent.scope() if method_scope is boundnode.metaclass(): return iter((boundnode, )) if funcnode.type == 'method': if not isinstance(boundnode, bases.Instance): boundnode = bases.Instance(boundnode) return iter((boundnode, )) if funcnode.type == 'classmethod': return iter((boundnode, )) # if we have a method, extract one position # from the index, so we'll take in account # the extra parameter represented by `self` or `cls` if funcnode.type in ('method', 'classmethod'): argindex -= 1 # 2. search arg index try: return self.positional_arguments[argindex].infer(context) except IndexError: pass if funcnode.args.kwarg == name: # It wants all the keywords that were passed into # the call site. if self.has_invalid_keywords(): raise exceptions.InferenceError( "Inference failed to find values for all keyword arguments " "to {func!r}: {unpacked_kwargs!r} doesn't correspond to " "{keyword_arguments!r}.", keyword_arguments=self.keyword_arguments, unpacked_kwargs=self._unpacked_kwargs, call_site=self, func=funcnode, arg=name, context=context) kwarg = nodes.Dict(lineno=funcnode.args.lineno, col_offset=funcnode.args.col_offset, parent=funcnode.args) kwarg.postinit([(nodes.const_factory(key), value) for key, value in kwargs.items()]) return iter((kwarg, )) elif funcnode.args.vararg == name: # It wants all the args that were passed into # the call site. if self.has_invalid_arguments(): raise exceptions.InferenceError( "Inference failed to find values for all positional " "arguments to {func!r}: {unpacked_args!r} doesn't " "correspond to {positional_arguments!r}.", positional_arguments=self.positional_arguments, unpacked_args=self._unpacked_args, call_site=self, func=funcnode, arg=name, context=context) args = nodes.Tuple(lineno=funcnode.args.lineno, col_offset=funcnode.args.col_offset, parent=funcnode.args) args.postinit(vararg) return iter((args, )) # Check if it's a default parameter. try: return funcnode.args.default_value(name).infer(context) except exceptions.NoDefault: pass raise exceptions.InferenceError( 'No value found for argument {name} to ' '{func!r}', call_site=self, func=funcnode, arg=name, context=context)
def infer_argument(self, funcnode, name, context): """infer a function argument value according to the call context""" if name in self.duplicated_keywords: raise exceptions.InferenceError(name) # Look into the keywords first, maybe it's already there. try: return self.keyword_arguments[name].infer(context) except KeyError: pass # Too many arguments given and no variable arguments. if len(self.positional_arguments) > len(funcnode.args.args): if not funcnode.args.vararg: raise exceptions.InferenceError(name) positional = self.positional_arguments[:len(funcnode.args.args)] vararg = self.positional_arguments[len(funcnode.args.args):] argindex = funcnode.args.find_argname(name)[0] kwonlyargs = set(arg.name for arg in funcnode.args.kwonlyargs) kwargs = { key: value for key, value in self.keyword_arguments.items() if key not in kwonlyargs } # If there are too few positionals compared to # what the function expects to receive, check to see # if the missing positional arguments were passed # as keyword arguments and if so, place them into the # positional args list. if len(positional) < len(funcnode.args.args): for func_arg in funcnode.args.args: if func_arg.name in kwargs: arg = kwargs.pop(func_arg.name) positional.append(arg) if argindex is not None: # 2. first argument of instance/class method if argindex == 0 and funcnode.type in ('method', 'classmethod'): if context.boundnode is not None: boundnode = context.boundnode else: # XXX can do better ? boundnode = funcnode.parent.frame() if funcnode.type == 'method': if not isinstance(boundnode, bases.Instance): boundnode = bases.Instance(boundnode) return iter((boundnode, )) if funcnode.type == 'classmethod': return iter((boundnode, )) # if we have a method, extract one position # from the index, so we'll take in account # the extra parameter represented by `self` or `cls` if funcnode.type in ('method', 'classmethod'): argindex -= 1 # 2. search arg index try: return self.positional_arguments[argindex].infer(context) except IndexError: pass if funcnode.args.kwarg == name: # It wants all the keywords that were passed into # the call site. if self.has_invalid_keywords(): raise exceptions.InferenceError kwarg = nodes.Dict() kwarg.lineno = funcnode.args.lineno kwarg.col_offset = funcnode.args.col_offset kwarg.parent = funcnode.args items = [(nodes.const_factory(key), value) for key, value in kwargs.items()] kwarg.items = items return iter((kwarg, )) elif funcnode.args.vararg == name: # It wants all the args that were passed into # the call site. if self.has_invalid_arguments(): raise exceptions.InferenceError args = nodes.Tuple() args.lineno = funcnode.args.lineno args.col_offset = funcnode.args.col_offset args.parent = funcnode.args args.elts = vararg return iter((args, )) # Check if it's a default parameter. try: return funcnode.args.default_value(name).infer(context) except exceptions.NoDefault: pass raise exceptions.InferenceError(name)