def call(self, node, funcv, args): if len(args.posargs) != 1: raise function.WrongArgCount(self._SIGNATURE, args, self.ctx) arg = args.posargs[0] for d in arg.data: d.is_classmethod = True d.is_attribute_of_class = True return node, ClassMethodInstance(self.ctx, self, arg).to_variable(node)
def call(self, node, _, args): result = self.ctx.program.NewVariable() num_args = len(args.posargs) if num_args == 0: # The implicit type argument is available in a freevar named '__class__'. cls_var = None # If we are in a list comprehension we want the enclosing frame. index = -1 while self.ctx.vm.frames[index].f_code.co_name == "<listcomp>": index -= 1 frame = self.ctx.vm.frames[index] for i, free_var in enumerate(frame.f_code.co_freevars): if free_var == abstract.BuildClass.CLOSURE_NAME: cls_var = frame.cells[len(frame.f_code.co_cellvars) + i] break if not (cls_var and cls_var.bindings): self.ctx.errorlog.invalid_super_call( self.ctx.vm.frames, message="Missing __class__ closure for super call.", details= "Is 'super' being called from a method defined in a class?" ) return node, self.ctx.new_unsolvable(node) # The implicit super object argument is the first argument to the function # calling 'super'. self_arg = frame.first_arg if not self_arg: self.ctx.errorlog.invalid_super_call( self.ctx.vm.frames, message="Missing 'self' argument to 'super' call.") return node, self.ctx.new_unsolvable(node) super_objects = self_arg.bindings elif 1 <= num_args <= 2: cls_var = args.posargs[0] super_objects = args.posargs[1].bindings if num_args == 2 else [ None ] else: raise function.WrongArgCount(self._SIGNATURE, args, self.ctx) for cls in cls_var.bindings: if not isinstance(cls.data, (abstract.Class, abstract.AMBIGUOUS_OR_EMPTY)): bad = function.BadParam(name="cls", expected=self.ctx.convert.type_type) raise function.WrongArgTypes(self._SIGNATURE, args, self.ctx, bad_param=bad) for obj in super_objects: if obj: result.AddBinding( SuperInstance(cls.data, obj.data, self.ctx), [cls, obj], node) else: result.AddBinding(SuperInstance(cls.data, None, self.ctx), [cls], node) return node, result
def call(self, node, _, args): if len(args.posargs) == 1: a, = args.posargs t = None elif len(args.posargs) == 2: a, t = args.posargs else: raise function.WrongArgCount(self._SIGNATURE, args, self.ctx) self.ctx.errorlog.assert_type(self.ctx.vm.frames, node, a, t) return node, self.ctx.convert.build_none(node)
def call(self, node, _, args, alias_map=None): sig = None if isinstance(self.func.__self__, _classes.CallableClass): sig = function.Signature.from_callable(self.func.__self__) args = args.simplify(node, self.ctx, match_signature=sig) posargs = [u.AssignToNewVariable(node) for u in args.posargs] namedargs = { k: u.AssignToNewVariable(node) for k, u in args.namedargs.items() } try: inspect.signature(self.func).bind(node, *posargs, **namedargs) except ValueError as e: # Happens for, e.g., # def f((x, y)): pass # f((42,)) raise NotImplementedError( "Wrong number of values to unpack") from e except TypeError as e: # The possible errors here are: # (1) wrong arg count # (2) duplicate keyword # (3) unexpected keyword # The way we constructed namedargs rules out (2). if "keyword" in utils.message(e): # Happens for, e.g., # def f(*args): pass # f(x=42) raise NotImplementedError("Unexpected keyword") from e # The function was passed the wrong number of arguments. The signature is # ([self, ]node, ...). The length of "..." tells us how many variables # are expected. expected_argcount = len(inspect.getfullargspec(self.func).args) - 1 if inspect.ismethod(self.func) and self.func.__self__ is not None: expected_argcount -= 1 actual_argcount = len(posargs) + len(namedargs) if (actual_argcount > expected_argcount or (not args.starargs and not args.starstarargs)): # If we have too many arguments, or starargs and starstarargs are both # empty, then we can be certain of a WrongArgCount error. argnames = tuple("_" + str(i) for i in range(expected_argcount)) sig = function.Signature(self.name, argnames, 0, None, set(), None, {}, {}, {}) raise function.WrongArgCount(sig, args, self.ctx) assert actual_argcount < expected_argcount # Assume that starargs or starstarargs fills in the missing arguments. # Instead of guessing where these arguments should go, overwrite all of # the arguments with a list of unsolvables of the correct length, which # is guaranteed to give us a correct (but imprecise) analysis. posargs = [ self.ctx.new_unsolvable(node) for _ in range(expected_argcount) ] namedargs = {} return self.func(node, *posargs, **namedargs)
def call(self, node, unused, args): if len(args.posargs) != 1: sig = function.Signature.from_param_names( "%s.add_metaclass" % self.module_name, ("cls",)) raise function.WrongArgCount(sig, args, self.ctx) cls_var = args.posargs[0] for b in cls_var.bindings: cls = b.data log.debug("Adding metaclass %r to class %r", self.meta, cls) cls.cls = self.meta # For metaclasses defined natively or using with_metaclass, the # metaclass's initializer is called in vm.make_class. However, with # add_metaclass, the metaclass is not known until the decorator fires. if isinstance(cls, abstract.Class): node = cls.call_metaclass_init(node) return node, cls_var
def call_slot(self, node, *args, **kwargs): """Implementation of CallableClass.__call__.""" if kwargs: raise function.WrongKeywordArgs( function.Signature.from_callable(self), function.Args(posargs=args, namedargs=kwargs), self.ctx, kwargs.keys()) if len(args) != self.num_args: raise function.WrongArgCount( function.Signature.from_callable(self), function.Args(posargs=args), self.ctx) formal_args = [(function.argname(i), self.formal_type_parameters[i]) for i in range(self.num_args)] substs = [datatypes.AliasingDict()] bad_param = None for view in abstract_utils.get_views(args, node): arg_dict = { function.argname(i): view[args[i]] for i in range(self.num_args) } subst, bad_param = self.ctx.matcher(node).compute_subst( formal_args, arg_dict, view, None) if subst is not None: substs = [subst] break else: if bad_param: raise function.WrongArgTypes( function.Signature.from_callable(self), function.Args(posargs=args), self.ctx, bad_param=bad_param) ret = self.ctx.annotation_utils.sub_one_annotation( node, self.formal_type_parameters[abstract_utils.RET], substs) node, retvar = self.ctx.vm.init_class(node, ret) return node, retvar
def _map_args(self, args, view): """Map the passed arguments to a name->binding dictionary. Args: args: The passed arguments. view: A variable->binding dictionary. Returns: A tuple of: a list of formal arguments, each a (name, abstract value) pair; a name->binding dictionary of the passed arguments. Raises: InvalidParameters: If the passed arguments don't match this signature. """ formal_args = [(p.name, self.signature.annotations[p.name]) for p in self.pytd_sig.params] arg_dict = {} # positional args for name, arg in zip(self.signature.param_names, args.posargs): arg_dict[name] = view[arg] num_expected_posargs = len(self.signature.param_names) if len(args.posargs) > num_expected_posargs and not self.pytd_sig.starargs: raise function.WrongArgCount(self.signature, args, self.ctx) # Extra positional args are passed via the *args argument. varargs_type = self.signature.annotations.get(self.signature.varargs_name) if isinstance(varargs_type, _classes.ParameterizedClass): for (i, vararg) in enumerate(args.posargs[num_expected_posargs:]): name = function.argname(num_expected_posargs + i) arg_dict[name] = view[vararg] formal_args.append( (name, varargs_type.get_formal_type_parameter(abstract_utils.T))) # named args for name, arg in args.namedargs.items(): if name in arg_dict: raise function.DuplicateKeyword(self.signature, args, self.ctx, name) arg_dict[name] = view[arg] kws = set(args.namedargs) extra_kwargs = kws - {p.name for p in self.pytd_sig.params} if extra_kwargs and not self.pytd_sig.starstarargs: raise function.WrongKeywordArgs( self.signature, args, self.ctx, extra_kwargs) posonly_kwargs = kws.intersection(self.signature.posonly_params) if posonly_kwargs: raise function.WrongKeywordArgs( self.signature, args, self.ctx, posonly_kwargs) # Extra keyword args are passed via the **kwargs argument. kwargs_type = self.signature.annotations.get(self.signature.kwargs_name) if isinstance(kwargs_type, _classes.ParameterizedClass): # We sort the kwargs so that matching always happens in the same order. for name in sorted(extra_kwargs): formal_args.append( (name, kwargs_type.get_formal_type_parameter(abstract_utils.V))) # packed args packed_args = [("starargs", self.signature.varargs_name), ("starstarargs", self.signature.kwargs_name)] for arg_type, name in packed_args: actual = getattr(args, arg_type) pytd_val = getattr(self.pytd_sig, arg_type) if actual and pytd_val: arg_dict[name] = view[actual] # The annotation is Tuple or Dict, but the passed arg only has to be # Iterable or Mapping. typ = self.ctx.convert.widen_type(self.signature.annotations[name]) formal_args.append((name, typ)) return formal_args, arg_dict
def _map_args(self, node, args): """Map call args to function args. This emulates how Python would map arguments of function calls. It takes care of keyword parameters, default parameters, and *args and **kwargs. Args: node: The current CFG node. args: The arguments. Returns: A dictionary, mapping strings (parameter names) to cfg.Variable. Raises: function.FailedFunctionCall: If the caller supplied incorrect arguments. """ # Originate a new variable for each argument and call. posargs = [u.AssignToNewVariable(node) for u in args.posargs] kws = { k: u.AssignToNewVariable(node) for k, u in args.namedargs.items() } sig = self.signature callargs = { name: self.ctx.program.NewVariable(default.data, [], node) for name, default in sig.defaults.items() } positional = dict(zip(sig.param_names, posargs)) for key in positional: if key in kws: raise function.DuplicateKeyword(sig, args, self.ctx, key) kwnames = set(kws) extra_kws = kwnames.difference(sig.param_names + sig.kwonly_params) if extra_kws and not sig.kwargs_name: raise function.WrongKeywordArgs(sig, args, self.ctx, extra_kws) posonly_kws = kwnames.intersection(sig.posonly_params) if posonly_kws: raise function.WrongKeywordArgs(sig, args, self.ctx, posonly_kws) callargs.update(positional) callargs.update(kws) for key, kwonly in self.get_nondefault_params(): if key not in callargs: if args.starstarargs or (args.starargs and not kwonly): # We assume that because we have *args or **kwargs, we can use these # to fill in any parameters we might be missing. callargs[key] = self.ctx.new_unsolvable(node) else: raise function.MissingParameter(sig, args, self.ctx, key) for key in sig.kwonly_params: if key not in callargs: raise function.MissingParameter(sig, args, self.ctx, key) if sig.varargs_name: varargs_name = sig.varargs_name extraneous = posargs[self.argcount(node):] if args.starargs: if extraneous: log.warning("Not adding extra params to *%s", varargs_name) callargs[varargs_name] = args.starargs.AssignToNewVariable( node) else: callargs[varargs_name] = self.ctx.convert.build_tuple( node, extraneous) elif len(posargs) > self.argcount(node): raise function.WrongArgCount(sig, args, self.ctx) if sig.kwargs_name: kwargs_name = sig.kwargs_name # Build a **kwargs dictionary out of the extraneous parameters if args.starstarargs: callargs[kwargs_name] = args.starstarargs.AssignToNewVariable( node) else: omit = sig.param_names + sig.kwonly_params k = _instances.Dict(self.ctx) k.update(node, args.namedargs, omit=omit) callargs[kwargs_name] = k.to_variable(node) return callargs
def call(self, node, funcv, args): if len(args.posargs) != 1: raise function.WrongArgCount(self._SIGNATURE, args, self.ctx) arg = args.posargs[0] return node, StaticMethodInstance(self.ctx, self, arg).to_variable(node)