def callable_default(self, min_args: int, *a: Type) -> CallableType: """callable_default(min_args, a1, ..., an, r) constructs a callable with argument types a1, ... an and return type r, with min_args mandatory fixed arguments. """ n = len(a) - 1 return CallableType(list(a[:-1]), [ARG_POS] * min_args + [ARG_OPT] * (n - min_args), [None] * n, a[-1], self.function)
def test_generic_function_type(self) -> None: c = CallableType([self.x, self.y], [ARG_POS, ARG_POS], [None, None], self.y, self.function, name=None, variables=[TypeVarDef('X', 'X', -1, [], self.fx.o)]) assert_equal(str(c), 'def [X] (X?, Y?) -> Y?') v = [ TypeVarDef('Y', 'Y', -1, [], self.fx.o), TypeVarDef('X', 'X', -2, [], self.fx.o) ] c2 = CallableType([], [], [], NoneTyp(), self.function, name=None, variables=v) assert_equal(str(c2), 'def [Y, X] ()')
def analyze_callable_type(self, t: UnboundType) -> Type: fallback = self.named_type('builtins.function') if len(t.args) == 0: # Callable (bare). Treat as Callable[..., Any]. any_type = AnyType(TypeOfAny.from_omitted_generics, line=t.line, column=t.column) ret = CallableType([any_type, any_type], [nodes.ARG_STAR, nodes.ARG_STAR2], [None, None], ret_type=any_type, fallback=fallback, is_ellipsis_args=True) elif len(t.args) == 2: ret_type = t.args[1] if isinstance(t.args[0], TypeList): # Callable[[ARG, ...], RET] (ordinary callable type) analyzed_args = self.analyze_callable_args(t.args[0]) if analyzed_args is None: return AnyType(TypeOfAny.from_error) args, kinds, names = analyzed_args ret = CallableType(args, kinds, names, ret_type=ret_type, fallback=fallback) elif isinstance(t.args[0], EllipsisType): # Callable[..., RET] (with literal ellipsis; accept arbitrary arguments) ret = CallableType( [AnyType(TypeOfAny.explicit), AnyType(TypeOfAny.explicit)], [nodes.ARG_STAR, nodes.ARG_STAR2], [None, None], ret_type=ret_type, fallback=fallback, is_ellipsis_args=True) else: self.fail( 'The first argument to Callable must be a list of types or "..."', t) return AnyType(TypeOfAny.from_error) else: self.fail('Invalid function type', t) return AnyType(TypeOfAny.from_error) assert isinstance(ret, CallableType) return ret.accept(self)
def visit_decorator(self, dec: Decorator) -> None: """Try to infer the type of the decorated function. This lets us resolve references to decorated functions during type checking when there are cyclic imports, as otherwise the type might not be available when we need it. This basically uses a simple special-purpose type inference engine just for decorators. """ # Don't just call the super method since we don't unconditionally traverse the decorated # function. dec.var.accept(self) for decorator in dec.decorators: decorator.accept(self) if self.recurse_into_functions: dec.func.accept(self) if dec.var.is_property: # Decorators are expected to have a callable type (it's a little odd). if dec.func.type is None: dec.var.type = CallableType( [AnyType(TypeOfAny.special_form)], [ARG_POS], [None], AnyType(TypeOfAny.special_form), self.builtin_type('function'), name=dec.var.name()) elif isinstance(dec.func.type, CallableType): dec.var.type = dec.func.type return decorator_preserves_type = True for expr in dec.decorators: preserve_type = False if isinstance(expr, RefExpr) and isinstance(expr.node, FuncDef): if expr.node.type and is_identity_signature(expr.node.type): preserve_type = True if not preserve_type: decorator_preserves_type = False break if decorator_preserves_type: # No non-identity decorators left. We can trivially infer the type # of the function here. dec.var.type = function_type(dec.func, self.builtin_type('function')) if dec.decorators: return_type = calculate_return_type(dec.decorators[0]) if return_type and isinstance(return_type, AnyType): # The outermost decorator will return Any so we know the type of the # decorated function. dec.var.type = AnyType(TypeOfAny.from_another_any, source_any=return_type) sig = find_fixed_callable_return(dec.decorators[0]) if sig: # The outermost decorator always returns the same kind of function, # so we know that this is the type of the decoratored function. orig_sig = function_type(dec.func, self.builtin_type('function')) sig.name = orig_sig.items()[0].name dec.var.type = sig
def callable_var_arg(self, min_args: int, *a: Type) -> CallableType: """callable_var_arg(min_args, a1, ..., an, r) constructs a callable with argument types a1, ... *an and return type r. """ n = len(a) - 1 return CallableType(list(a[:-1]), [ARG_POS] * min_args + [ARG_OPT] * (n - 1 - min_args) + [ARG_STAR], [None] * n, a[-1], self.function)
def get_trivial_type(self, fdef: FuncDef) -> CallableType: """Generate a trivial callable type from a func def, with all Anys""" # The Anys are marked as being from the suggestion engine # since they need some special treatment (specifically, # constraint generation ignores them.) return CallableType( [AnyType(TypeOfAny.suggestion_engine) for a in fdef.arg_kinds], fdef.arg_kinds, fdef.arg_names, AnyType(TypeOfAny.suggestion_engine), self.named_type('builtins.function'))
def _handle_iadd_isub(ctx: MethodSigContext) -> CallableType: target_method: CallableType = ctx.type.args[0] assert isinstance(target_method, CallableType) names = list(target_method.arg_names) names[0] = None simplified_target = CallableType( arg_types=target_method.arg_types, arg_kinds=target_method.arg_kinds, arg_names=names, fallback=ctx.api.named_type('function'), ret_type=target_method.ret_type) return CallableType(arg_types=[simplified_target], arg_names=['other'], arg_kinds=[0], ret_type=ctx.type, fallback=ctx.api.named_type('function'))
def cached_function_method_signature(ctx: MethodSigContext) -> CallableType: """Fixes the `_CachedFunction.__call__` signature to be correct. It already has *almost* the correct signature, except: 1. the `self` argument needs to be marked as "bound"; 2. any `cache_context` argument should be removed; 3. an optional keyword argument `on_invalidated` should be added. """ # First we mark this as a bound function signature. signature = bind_self(ctx.default_signature) # Secondly, we remove any "cache_context" args. # # Note: We should be only doing this if `cache_context=True` is set, but if # it isn't then the code will raise an exception when its called anyway, so # its not the end of the world. context_arg_index = None for idx, name in enumerate(signature.arg_names): if name == "cache_context": context_arg_index = idx break arg_types = list(signature.arg_types) arg_names = list(signature.arg_names) arg_kinds = list(signature.arg_kinds) if context_arg_index: arg_types.pop(context_arg_index) arg_names.pop(context_arg_index) arg_kinds.pop(context_arg_index) # Third, we add an optional "on_invalidate" argument. # # This is a callable which accepts no input and returns nothing. calltyp = CallableType( arg_types=[], arg_kinds=[], arg_names=[], ret_type=NoneType(), fallback=ctx.api.named_generic_type("builtins.function", []), ) arg_types.append(calltyp) arg_names.append("on_invalidate") arg_kinds.append(ARG_NAMED_OPT) # Arg is an optional kwarg. signature = signature.copy_modified( arg_types=arg_types, arg_names=arg_names, arg_kinds=arg_kinds, ) return signature
def analyze_function_type(self, t: UnboundType) -> Type: if len(t.args) != 2: self.fail('Invalid function type', t) if not isinstance(t.args[0], TypeList): self.fail('Invalid function type', t) return AnyType() args = (cast(TypeList, t.args[0])).items return CallableType(self.anal_array(args), [nodes.ARG_POS] * len(args), [None] * len(args), ret_type=t.args[1].accept(self), fallback=self.builtin_type('builtins.function'))
def visit_callable_type(self, t: CallableType) -> Type: res = CallableType(self.anal_array(t.arg_types), t.arg_kinds, t.arg_names, t.ret_type.accept(self), self.builtin_type('builtins.function'), t.name, self.anal_var_defs(t.variables), self.anal_bound_vars(t.bound_vars), t.line) return res
def visit_FunctionDef(self, n: ast35.FunctionDef) -> Node: args = self.transform_args(n.args, n.lineno) arg_kinds = [arg.kind for arg in args] arg_names = [arg.variable.name() for arg in args] arg_types = None # type: List[Type] if n.type_comment is not None: try: func_type_ast = ast35.parse(n.type_comment, '<func_type>', 'func_type') except SyntaxError: raise TypeCommentParseError(TYPE_COMMENT_SYNTAX_ERROR, n.lineno) assert isinstance(func_type_ast, ast35.FunctionType) # for ellipsis arg if (len(func_type_ast.argtypes) == 1 and isinstance(func_type_ast.argtypes[0], ast35.Ellipsis)): arg_types = [AnyType() for a in args] else: arg_types = [a if a is not None else AnyType() for a in TypeConverter(line=n.lineno).visit_list(func_type_ast.argtypes)] return_type = TypeConverter(line=n.lineno).visit(func_type_ast.returns) # add implicit self type if self.in_class() and len(arg_types) < len(args): arg_types.insert(0, AnyType()) else: arg_types = [a.type_annotation for a in args] return_type = TypeConverter(line=n.lineno).visit(n.returns) func_type = None if any(arg_types) or return_type: func_type = CallableType([a if a is not None else AnyType() for a in arg_types], arg_kinds, arg_names, return_type if return_type is not None else AnyType(), None) func_def = FuncDef(n.name, args, self.as_block(n.body, n.lineno), func_type) if func_type is not None: func_type.definition = func_def if n.decorator_list: var = Var(func_def.name()) var.is_ready = False var.set_line(n.decorator_list[0].lineno) func_def.is_decorated = True func_def.set_line(n.lineno + len(n.decorator_list)) func_def.body.set_line(func_def.get_line()) return Decorator(func_def, self.visit_list(n.decorator_list), var) else: return func_def
def set_hook(ctx): return CallableType( [ ctx.api.named_type("__main__.Cls"), ctx.api.named_type("builtins.int") ], ctx.default_signature.arg_kinds, ctx.default_signature.arg_names, ctx.default_signature.ret_type, ctx.default_signature.fallback, )
def add_method_to_class( api: Union[SemanticAnalyzerPluginInterface, CheckerPluginInterface], cls: ClassDef, name: str, args: List[Argument], return_type: Type, self_type: Optional[Type] = None, tvar_def: Optional[TypeVarType] = None, ) -> None: """Adds a new method to a class definition.""" info = cls.info # First remove any previously generated methods with the same name # to avoid clashes and problems in the semantic analyzer. if name in info.names: sym = info.names[name] if sym.plugin_generated and isinstance(sym.node, FuncDef): cls.defs.body.remove(sym.node) self_type = self_type or fill_typevars(info) if isinstance(api, SemanticAnalyzerPluginInterface): function_type = api.named_type('builtins.function') else: function_type = api.named_generic_type('builtins.function', []) args = [Argument(Var('self'), self_type, None, ARG_POS)] + args arg_types, arg_names, arg_kinds = [], [], [] for arg in args: assert arg.type_annotation, 'All arguments must be fully typed.' arg_types.append(arg.type_annotation) arg_names.append(arg.variable.name) arg_kinds.append(arg.kind) signature = CallableType(arg_types, arg_kinds, arg_names, return_type, function_type) if tvar_def: signature.variables = [tvar_def] func = FuncDef(name, args, Block([PassStmt()])) func.info = info func.type = set_callable_name(signature, func) func._fullname = info.fullname + '.' + name func.line = info.line # NOTE: we would like the plugin generated node to dominate, but we still # need to keep any existing definitions so they get semantically analyzed. if name in info.names: # Get a nice unique name instead. r_name = get_unique_redefinition_name(name, info.names) info.names[r_name] = info.names[name] info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True) info.defn.defs.body.append(func)
def visit_callable_type(self, t: CallableType) -> Type: # We must preserve the fallback type for overload resolution to work. any_type = AnyType(TypeOfAny.special_form) return CallableType( arg_types=[any_type, any_type], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=[None, None], ret_type=any_type, fallback=t.fallback, is_ellipsis_args=True, implicit=True, )
def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> Type: """Return the type of a type object. For a generic type G with type variables T and S the type is generally of form Callable[..., G[T, S]] where ... are argument types for the __init__/__new__ method (without the self argument). Also, the fallback type will be 'type' instead of 'function'. """ # We take the type from whichever of __init__ and __new__ is first # in the MRO, preferring __init__ if there is a tie. init_method = info.get_method('__init__') new_method = info.get_method('__new__') if not init_method: # Must be an invalid class definition. return AnyType(TypeOfAny.from_error) # There *should* always be a __new__ method except the test stubs # lack it, so just copy init_method in that situation new_method = new_method or init_method init_index = info.mro.index(init_method.info) new_index = info.mro.index(new_method.info) fallback = info.metaclass_type or builtin_type('builtins.type') if init_index < new_index: method = init_method elif init_index > new_index: method = new_method else: if init_method.info.fullname() == 'builtins.object': # Both are defined by object. But if we've got a bogus # base class, we can't know for sure, so check for that. if info.fallback_to_any: # Construct a universal callable as the prototype. any_type = AnyType(TypeOfAny.special_form) sig = CallableType(arg_types=[any_type, any_type], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=["_args", "_kwds"], ret_type=any_type, fallback=builtin_type('builtins.function')) return class_callable(sig, info, fallback, None) # Otherwise prefer __init__ in a tie. It isn't clear that this # is the right thing, but __new__ caused problems with # typeshed (#5647). method = init_method # Construct callable type based on signature of __init__. Adjust # return type and insert type arguments. return type_object_type_from_function(method, info, fallback)
def _lift_call_hook(context: MethodContext) -> Type: arg_types = [] for arg_type in context.arg_types[0]: arg_types.append(arg_type.args[-1]) args = context.type.args[:-1] ret_type = context.type.args[-1] function_type = CallableType( arg_types=args, arg_kinds=[ARG_POS] * len(args), arg_names=[None] * len(args), ret_type=ret_type, fallback=context.api.named_type('builtins.function')) context.api.expr_checker.check_call(callee=function_type, )
def callable(self, vars, *a) -> CallableType: """callable(args, a1, ..., an, r) constructs a callable with argument types a1, ... an and return type r and type arguments vars. """ tv = [] # type: List[TypeVarDef] n = -1 for v in vars: tv.append(TypeVarDef(v, n, None, self.fx.o)) n -= 1 return CallableType(list(a[:-1]), [ARG_POS] * (len(a) - 1), [None] * (len(a) - 1), a[-1], self.fx.function, None, tv)
def infer_decorator_signature_if_simple( dec: Decorator, analyzer: SemanticAnalyzerInterface) -> None: """Try to infer the type of the decorated function. This lets us resolve additional references to decorated functions during type checking. Otherwise the type might not be available when we need it, since module top levels can't be deferred. This basically uses a simple special-purpose type inference engine just for decorators. """ if dec.var.is_property: # Decorators are expected to have a callable type (it's a little odd). if dec.func.type is None: dec.var.type = CallableType( [AnyType(TypeOfAny.special_form)], [ARG_POS], [None], AnyType(TypeOfAny.special_form), analyzer.named_type('__builtins__.function'), name=dec.var.name()) elif isinstance(dec.func.type, CallableType): dec.var.type = dec.func.type return decorator_preserves_type = True for expr in dec.decorators: preserve_type = False if isinstance(expr, RefExpr) and isinstance(expr.node, FuncDef): if expr.node.type and is_identity_signature(expr.node.type): preserve_type = True if not preserve_type: decorator_preserves_type = False break if decorator_preserves_type: # No non-identity decorators left. We can trivially infer the type # of the function here. dec.var.type = function_type( dec.func, analyzer.named_type('__builtins__.function')) if dec.decorators: return_type = calculate_return_type(dec.decorators[0]) if return_type and isinstance(return_type, AnyType): # The outermost decorator will return Any so we know the type of the # decorated function. dec.var.type = AnyType(TypeOfAny.from_another_any, source_any=return_type) sig = find_fixed_callable_return(dec.decorators[0]) if sig: # The outermost decorator always returns the same kind of function, # so we know that this is the type of the decorated function. orig_sig = function_type( dec.func, analyzer.named_type('__builtins__.function')) sig.name = orig_sig.items()[0].name dec.var.type = sig
def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> Type: if mx.chk.should_suppress_optional_error([typ]): return AnyType(TypeOfAny.from_error) is_python_3 = mx.chk.options.python_version[0] >= 3 # In Python 2 "None" has exactly the same attributes as "object". Python 3 adds a single # extra attribute, "__bool__". if is_python_3 and name == '__bool__': return CallableType(arg_types=[], arg_kinds=[], arg_names=[], ret_type=mx.builtin_type('builtins.bool'), fallback=mx.builtin_type('builtins.function')) else: return _analyze_member_access(name, mx.builtin_type('builtins.object'), mx)
def apply_generic_arguments(callable: CallableType, types: List[Type], msg: MessageBuilder, context: Context) -> Type: """Apply generic type arguments to a callable type. For example, applying [int] to 'def [T] (T) -> T' results in 'def [-1:int] (int) -> int'. Here '[-1:int]' is an implicit bound type variable. Note that each type can be None; in this case, it will not be applied. """ tvars = callable.variables if len(tvars) != len(types): msg.incompatible_type_application(len(tvars), len(types), context) return AnyType() # Check that inferred type variable values are compatible with allowed # values. Also, promote subtype values to allowed values. types = types[:] for i, type in enumerate(types): values = callable.variables[i].values if values and type: if isinstance(type, AnyType): continue for value in values: if mypy.subtypes.is_subtype(type, value): types[i] = value break else: msg.incompatible_typevar_value(callable, i + 1, type, context) # Create a map from type variable id to target type. id_to_type = {} # type: Dict[int, Type] for i, tv in enumerate(tvars): if types[i]: id_to_type[tv.id] = types[i] # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] bound_vars = [(tv.id, id_to_type[tv.id]) for tv in tvars if tv.id in id_to_type] # The callable may retain some type vars if only some were applied. remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type] return CallableType(arg_types, callable.arg_kinds, callable.arg_names, expand_type(callable.ret_type, id_to_type), callable.fallback, callable.name, remaining_tvars, callable.bound_vars + bound_vars, callable.line)
def write_hook(ctx: MethodSigContext) -> CallableType: if not isinstance(ctx.type, Instance): return ctx.default_signature if ctx.type.type.name == "BaseModel": return ctx.default_signature vals = _build_vals_dict(ctx.type, ctx.api) fallback = ctx.api.named_type("typing._TypedDict") # type: ignore vals_type = TypedDictType(vals, set(), fallback) return CallableType( [vals_type], [ARG_POS], ["vals"], ctx.default_signature.ret_type, ctx.default_signature.fallback, )
def analyze_callable_type(self, t: UnboundType) -> Type: fallback = self.builtin_type('builtins.function') if len(t.args) == 0: # Callable (bare). Treat as Callable[..., Any]. return CallableType([AnyType(), AnyType()], [nodes.ARG_STAR, nodes.ARG_STAR2], [None, None], ret_type=AnyType(), fallback=fallback, is_ellipsis_args=True) elif len(t.args) == 2: ret_type = t.args[1].accept(self) if isinstance(t.args[0], TypeList): # Callable[[ARG, ...], RET] (ordinary callable type) args = t.args[0].items return CallableType(self.anal_array(args), [nodes.ARG_POS] * len(args), [None] * len(args), ret_type=ret_type, fallback=fallback) elif isinstance(t.args[0], EllipsisType): # Callable[..., RET] (with literal ellipsis; accept arbitrary arguments) return CallableType([AnyType(), AnyType()], [nodes.ARG_STAR, nodes.ARG_STAR2], [None, None], ret_type=ret_type, fallback=fallback, is_ellipsis_args=True) else: self.fail( 'The first argument to Callable must be a list of types or "..."', t) return AnyType() self.fail('Invalid function type', t) return AnyType()
def parse_signature(tokens: List[Token]) -> Tuple[CallableType, int]: """Parse signature of form (argtype, ...) -> ... Return tuple (signature type, token index). """ i = 0 if tokens[i].string != '(': raise TypeParseError(tokens[i], i) i += 1 arg_types = [] # type: List[Type] arg_kinds = [] # type: List[int] encountered_ellipsis = False while tokens[i].string != ')': if tokens[i].string == '*': arg_kinds.append(nodes.ARG_STAR) i += 1 elif tokens[i].string == '**': arg_kinds.append(nodes.ARG_STAR2) i += 1 else: arg_kinds.append(nodes.ARG_POS) arg, i = parse_type(tokens, i) arg_types.append(arg) next = tokens[i].string # Check for ellipsis. If it exists, assert it's the only arg_type. # Disallow '(..., int) -> None' for example. if isinstance(arg, EllipsisType): encountered_ellipsis = True if encountered_ellipsis and len(arg_types) != 1: raise TypeParseError( tokens[i], i, "Ellipses cannot accompany other argument types" " in function type signature.") if next not in ',)': raise TypeParseError(tokens[i], i) if next == ',': i += 1 i += 1 if tokens[i].string != '->': raise TypeParseError(tokens[i], i) i += 1 ret_type, i = parse_type(tokens, i) return CallableType(arg_types, arg_kinds, [None] * len(arg_types), ret_type, None, is_ellipsis_args=encountered_ellipsis), i
def class_callable(init_type: CallableType, info: TypeInfo, type_type: Instance) -> CallableType: """Create a type object type based on the signature of __init__.""" variables = [] # type: List[TypeVarDef] for i, tvar in enumerate(info.defn.type_vars): variables.append( TypeVarDef(tvar.name, i + 1, tvar.values, tvar.upper_bound, tvar.variance)) initvars = init_type.variables variables.extend(initvars) c = CallableType(init_type.arg_types, init_type.arg_kinds, init_type.arg_names, self_type(info), type_type, None, variables).with_name('"{}"'.format(info.name())) return convert_class_tvars_to_func_tvars(c, len(initvars))
def signal_type_analyze_callback(ctx: AnalyzeTypeContext) -> Type: if (len(ctx.type.args) != 1 or not isinstance(ctx.type.args[0], TypeList)): ctx.api.fail('Invalid "Signal" type (expected "Signal[[t, ...]]")', ctx.context) return AnyType() args = ctx.type.args[0] assert isinstance(args, TypeList) analyzed = ctx.api.analyze_callable_args(args) if analyzed is None: return AnyType() # Error generated elsewhere arg_types, arg_kinds, arg_names = analyzed arg_types = [ctx.api.analyze_type(arg) for arg in arg_types] type_arg = CallableType(arg_types, arg_kinds, arg_names, NoneTyp(), ctx.api.named_type('builtins.function', [])) return ctx.api.named_type('m.Signal', [type_arg])
def combine_similar_callables(t: CallableType, s: CallableType) -> CallableType: arg_types = [] # type: List[Type] for i in range(len(t.arg_types)): arg_types.append(join_types(t.arg_types[i], s.arg_types[i])) # TODO kinds and argument names # The fallback type can be either 'function' or 'type'. The result should have 'type' as # fallback only if both operands have it as 'type'. if t.fallback.type.fullname() != 'builtins.type': fallback = t.fallback else: fallback = s.fallback return CallableType(arg_types, t.arg_kinds, t.arg_names, join_types(t.ret_type, s.ret_type), fallback, None, t.variables) return s
def callable(self, vars: List[str], *a: Type) -> CallableType: """callable(args, a1, ..., an, r) constructs a callable with argument types a1, ... an and return type r and type arguments vars. """ tv: List[TypeVarType] = [] n = -1 for v in vars: tv.append(TypeVarType(v, v, n, [], self.fx.o)) n -= 1 return CallableType(list(a[:-1]), [ARG_POS] * (len(a) - 1), [None] * (len(a) - 1), a[-1], self.fx.function, name=None, variables=tv)
def _variadic_decorator_hook(context: FunctionContext) -> Type: arg_type = context.arg_types[0][0] function = _get_callable_type(arg_type, context) if function is None: return context.default_return_type ret_type = get_proper_type(context.default_return_type.ret_type) variables = list( set(function.variables + context.default_return_type.variables)) return CallableType(arg_types=function.arg_types, arg_kinds=function.arg_kinds, arg_names=function.arg_names, ret_type=ret_type, fallback=function.fallback, variables=variables, implicit=True)
def visit_FunctionDef(self, n): args = self.transform_args(n.args, n.lineno) arg_kinds = [arg.kind for arg in args] arg_names = [arg.variable.name() for arg in args] if n.type_comment is not None: func_type_ast = typed_ast.parse(n.type_comment, '<func_type>', 'func_type') arg_types = [ a if a is not None else AnyType() for a in TypeConverter( line=n.lineno).visit(func_type_ast.argtypes) ] return_type = TypeConverter(line=n.lineno).visit( func_type_ast.returns) # add implicit self type if self.in_class and len(arg_types) < len(args): arg_types.insert(0, AnyType()) else: arg_types = [a.type_annotation for a in args] return_type = TypeConverter(line=n.lineno).visit(n.returns) func_type = None if any(arg_types) or return_type: func_type = CallableType( [a if a is not None else AnyType() for a in arg_types], arg_kinds, arg_names, return_type if return_type is not None else AnyType(), None) func_def = FuncDef(n.name, args, self.as_block(n.body, n.lineno), func_type) if func_type is not None: func_type.definition = func_def if n.decorator_list: var = Var(func_def.name()) var.is_ready = False var.set_line(n.decorator_list[0].lineno) func_def.is_decorated = True func_def.set_line(n.lineno + len(n.decorator_list)) func_def.body.set_line(func_def.get_line()) return Decorator(func_def, self.visit(n.decorator_list), var) else: return func_def
def add_method( ctx: ClassDefContext, name: str, args: List[Argument], return_type: Type, self_type: Optional[Type] = None, tvar_def: Optional[TypeVarDef] = None, ) -> None: """Adds a new method to a class. """ info = ctx.cls.info # First remove any previously generated methods with the same name # to avoid clashes and problems in new semantic analyzer. if name in info.names: sym = info.names[name] if sym.plugin_generated and isinstance(sym.node, FuncDef): ctx.cls.defs.body.remove(sym.node) self_type = self_type or fill_typevars(info) function_type = ctx.api.named_type('__builtins__.function') args = [Argument(Var('self'), self_type, None, ARG_POS)] + args arg_types, arg_names, arg_kinds = [], [], [] for arg in args: assert arg.type_annotation, 'All arguments must be fully typed.' arg_types.append(arg.type_annotation) arg_names.append(arg.variable.name()) arg_kinds.append(arg.kind) signature = CallableType(arg_types, arg_kinds, arg_names, return_type, function_type) if tvar_def: signature.variables = [tvar_def] func = FuncDef(name, args, Block([PassStmt()])) func.info = info func.type = set_callable_name(signature, func) func._fullname = info.fullname() + '.' + name func.line = info.line info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True) info.defn.defs.body.append(func)