def visit_raw_str(self, s: str) -> Type: # An escape hatch that allows the AST walker in fastparse2 to # directly hook into the Python 3.5 type converter in some cases # without needing to create an intermediary `ast3.Str` object. return (parse_type_comment(s.strip(), self.line, self.errors) or AnyType(TypeOfAny.from_error))
def visit_Str(self, n: ast3.Str) -> Type: return (parse_type_comment(n.s.strip(), self.line, self.errors) or AnyType(TypeOfAny.from_error))
def analyze_descriptor_access(instance_type: Type, descriptor_type: Type, builtin_type: Callable[[str], Instance], msg: MessageBuilder, context: Context, *, chk: 'mypy.checker.TypeChecker') -> Type: """Type check descriptor access. Arguments: instance_type: The type of the instance on which the descriptor attribute is being accessed (the type of ``a`` in ``a.f`` when ``f`` is a descriptor). descriptor_type: The type of the descriptor attribute being accessed (the type of ``f`` in ``a.f`` when ``f`` is a descriptor). context: The node defining the context of this inference. Return: The return type of the appropriate ``__get__`` overload for the descriptor. """ instance_type = get_proper_type(instance_type) descriptor_type = get_proper_type(descriptor_type) if isinstance(descriptor_type, UnionType): # Map the access over union types return make_simplified_union([ analyze_descriptor_access(instance_type, typ, builtin_type, msg, context, chk=chk) for typ in descriptor_type.items ]) elif not isinstance(descriptor_type, Instance): return descriptor_type if not descriptor_type.type.has_readable_member('__get__'): return descriptor_type dunder_get = descriptor_type.type.get_method('__get__') if dunder_get is None: msg.fail( message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format( descriptor_type), context) return AnyType(TypeOfAny.from_error) function = function_type(dunder_get, builtin_type('builtins.function')) bound_method = bind_self(function, descriptor_type) typ = map_instance_to_supertype(descriptor_type, dunder_get.info) dunder_get_type = expand_type_by_instance(bound_method, typ) if isinstance(instance_type, FunctionLike) and instance_type.is_type_obj(): owner_type = instance_type.items()[0].ret_type instance_type = NoneType() elif isinstance(instance_type, TypeType): owner_type = instance_type.item instance_type = NoneType() else: owner_type = instance_type _, inferred_dunder_get_type = chk.expr_checker.check_call( dunder_get_type, [ TempNode(instance_type, context=context), TempNode(TypeType.make_normalized(owner_type), context=context) ], [ARG_POS, ARG_POS], context) inferred_dunder_get_type = get_proper_type(inferred_dunder_get_type) if isinstance(inferred_dunder_get_type, AnyType): # check_call failed, and will have reported an error return inferred_dunder_get_type if not isinstance(inferred_dunder_get_type, CallableType): msg.fail( message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format( descriptor_type), context) return AnyType(TypeOfAny.from_error) return inferred_dunder_get_type.ret_type
def analyze_class_attribute_access( itype: Instance, name: str, mx: MemberContext, override_info: Optional[TypeInfo] = None, original_vars: Optional[List[TypeVarDef]] = None) -> Optional[Type]: """Analyze access to an attribute on a class object. itype is the return type of the class object callable, original_type is the type of E in the expression E.var, original_vars are type variables of the class callable (for generic classes). """ info = itype.type if override_info: info = override_info node = info.get(name) if not node: if info.fallback_to_any: return AnyType(TypeOfAny.special_form) return None is_decorated = isinstance(node.node, Decorator) is_method = is_decorated or isinstance(node.node, FuncBase) if mx.is_lvalue: if is_method: mx.msg.cant_assign_to_method(mx.context) if isinstance(node.node, TypeInfo): mx.msg.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, mx.context) # If a final attribute was declared on `self` in `__init__`, then it # can't be accessed on the class object. if node.implicit and isinstance(node.node, Var) and node.node.is_final: mx.msg.fail( message_registry.CANNOT_ACCESS_FINAL_INSTANCE_ATTR.format( node.node.name), mx.context) # An assignment to final attribute on class object is also always an error, # independently of types. if mx.is_lvalue and not mx.chk.get_final_context(): check_final_member(name, info, mx.msg, mx.context) if info.is_enum and not (mx.is_lvalue or is_decorated or is_method): # Skip "_order_" and "__order__", since Enum will remove it if name in ("_order_", "__order__"): return mx.msg.has_no_attr(mx.original_type, itype, name, mx.context, mx.module_symbol_table) enum_literal = LiteralType(name, fallback=itype) # When we analyze enums, the corresponding Instance is always considered to be erased # due to how the signature of Enum.__new__ is `(cls: Type[_T], value: object) -> _T` # in typeshed. However, this is really more of an implementation detail of how Enums # are typed, and we really don't want to treat every single Enum value as if it were # from type variable substitution. So we reset the 'erased' field here. return itype.copy_modified(erased=False, last_known_value=enum_literal) t = node.type if t: if isinstance(t, PartialType): symnode = node.node assert isinstance(symnode, Var) return mx.chk.handle_partial_var_type(t, mx.is_lvalue, symnode, mx.context) # Find the class where method/variable was defined. if isinstance(node.node, Decorator): super_info = node.node.var.info # type: Optional[TypeInfo] elif isinstance(node.node, (Var, SYMBOL_FUNCBASE_TYPES)): super_info = node.node.info else: super_info = None # Map the type to how it would look as a defining class. For example: # class C(Generic[T]): ... # class D(C[Tuple[T, S]]): ... # D[int, str].method() # Here itype is D[int, str], isuper is C[Tuple[int, str]]. if not super_info: isuper = None else: isuper = map_instance_to_supertype(itype, super_info) if isinstance(node.node, Var): assert isuper is not None # Check if original variable type has type variables. For example: # class C(Generic[T]): # x: T # C.x # Error, ambiguous access # C[int].x # Also an error, since C[int] is same as C at runtime if isinstance(t, TypeVarType) or has_type_vars(t): # Exception: access on Type[...], including first argument of class methods is OK. if not isinstance(get_proper_type(mx.original_type), TypeType) or node.implicit: if node.node.is_classvar: message = message_registry.GENERIC_CLASS_VAR_ACCESS else: message = message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS mx.msg.fail(message, mx.context) # Erase non-mapped variables, but keep mapped ones, even if there is an error. # In the above example this means that we infer following types: # C.x -> Any # C[int].x -> int t = erase_typevars(expand_type_by_instance(t, isuper)) is_classmethod = ( (is_decorated and cast(Decorator, node.node).func.is_class) or (isinstance(node.node, FuncBase) and node.node.is_class)) t = get_proper_type(t) if isinstance(t, FunctionLike) and is_classmethod: t = check_self_arg(t, mx.self_type, False, mx.context, name, mx.msg) result = add_class_tvars(t, isuper, is_classmethod, mx.self_type, original_vars=original_vars) if not mx.is_lvalue: result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk) return result elif isinstance(node.node, Var): mx.not_ready_callback(name, mx.context) return AnyType(TypeOfAny.special_form) if isinstance(node.node, TypeVarExpr): mx.msg.fail( message_registry.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format( info.name, name), mx.context) return AnyType(TypeOfAny.from_error) if isinstance(node.node, TypeInfo): return type_object_type(node.node, mx.builtin_type) if isinstance(node.node, MypyFile): # Reference to a module object. return mx.builtin_type('types.ModuleType') if (isinstance(node.node, TypeAlias) and isinstance(get_proper_type(node.node.target), Instance)): return instance_alias_type(node.node, mx.builtin_type) if is_decorated: assert isinstance(node.node, Decorator) if node.node.type: return node.node.type else: mx.not_ready_callback(name, mx.context) return AnyType(TypeOfAny.from_error) else: assert isinstance(node.node, FuncBase) typ = function_type(node.node, mx.builtin_type('builtins.function')) # Note: if we are accessing class method on class object, the cls argument is bound. # Annotated and/or explicit class methods go through other code paths above, for # unannotated implicit class methods we do this here. if node.node.is_class: typ = bind_self(typ, is_classmethod=True) return typ
def check_namedtuple_classdef( self, defn: ClassDef, is_stub_file: bool ) -> Optional[Tuple[List[str], List[Type], Dict[str, Expression]]]: """Parse and validate fields in named tuple class definition. Return a three tuple: * field names * field types * field default values or None, if any of the types are not ready. """ if self.options.python_version < (3, 6) and not is_stub_file: self.fail( 'NamedTuple class syntax is only supported in Python 3.6', defn) return [], [], {} if len(defn.base_type_exprs) > 1: self.fail('NamedTuple should be a single base', defn) items = [] # type: List[str] types = [] # type: List[Type] default_items = {} # type: Dict[str, Expression] for stmt in defn.defs.body: if not isinstance(stmt, AssignmentStmt): # Still allow pass or ... (for empty namedtuples). if (isinstance(stmt, PassStmt) or (isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, EllipsisExpr))): continue # Also allow methods, including decorated ones. if isinstance(stmt, (Decorator, FuncBase)): continue # And docstrings. if (isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, StrExpr)): continue self.fail(NAMEDTUP_CLASS_ERROR, stmt) elif len(stmt.lvalues) > 1 or not isinstance( stmt.lvalues[0], NameExpr): # An assignment, but an invalid one. self.fail(NAMEDTUP_CLASS_ERROR, stmt) else: # Append name and type in this case... name = stmt.lvalues[0].name items.append(name) if stmt.type is None: types.append(AnyType(TypeOfAny.unannotated)) else: analyzed = self.api.anal_type(stmt.type) if analyzed is None: # Something is incomplete. We need to defer this named tuple. return None types.append(analyzed) # ...despite possible minor failures that allow further analyzis. if name.startswith('_'): self.fail( 'NamedTuple field name cannot start with an underscore: {}' .format(name), stmt) if stmt.type is None or hasattr( stmt, 'new_syntax') and not stmt.new_syntax: self.fail(NAMEDTUP_CLASS_ERROR, stmt) elif isinstance(stmt.rvalue, TempNode): # x: int assigns rvalue to TempNode(AnyType()) if default_items: self.fail( 'Non-default NamedTuple fields cannot follow default fields', stmt) else: default_items[name] = stmt.rvalue return items, types, default_items
def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement: self.class_and_function_stack.append('F') lineno = n.lineno converter = TypeConverter(self.errors, line=lineno, override_column=n.col_offset, assume_str_is_unicode=self.unicode_literals) args, decompose_stmts = self.transform_args(n.args, lineno) if special_function_elide_names(n.name): for arg in args: arg.pos_only = True arg_kinds = [arg.kind for arg in args] arg_names = [ None if arg.pos_only else arg.variable.name for arg in args ] arg_types: List[Optional[Type]] = [] type_comment = n.type_comment if (n.decorator_list and any( is_no_type_check_decorator(d) for d in n.decorator_list)): arg_types = [None] * len(args) return_type = None elif type_comment is not None and len(type_comment) > 0: try: func_type_ast = ast3_parse(type_comment, '<func_type>', 'func_type') assert isinstance(func_type_ast, ast3.FunctionType) # for ellipsis arg if (len(func_type_ast.argtypes) == 1 and isinstance( func_type_ast.argtypes[0], ast3.Ellipsis)): arg_types = [ a.type_annotation if a.type_annotation is not None else AnyType(TypeOfAny.unannotated) for a in args ] else: # PEP 484 disallows both type annotations and type comments if any(a.type_annotation is not None for a in args): self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset) arg_types = [ a if a is not None else AnyType(TypeOfAny.unannotated) for a in converter.translate_expr_list( func_type_ast.argtypes) ] return_type = converter.visit(func_type_ast.returns) # add implicit self type if self.in_method_scope() and len(arg_types) < len(args): arg_types.insert(0, AnyType(TypeOfAny.special_form)) except SyntaxError: stripped_type = type_comment.split("#", 2)[0].strip() err_msg = '{} "{}"'.format(TYPE_COMMENT_SYNTAX_ERROR, stripped_type) self.fail(err_msg, lineno, n.col_offset) arg_types = [AnyType(TypeOfAny.from_error)] * len(args) return_type = AnyType(TypeOfAny.from_error) else: arg_types = [a.type_annotation for a in args] return_type = converter.visit(None) for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) func_type = None if any(arg_types) or return_type: if len(arg_types) != 1 and any( isinstance(t, EllipsisType) for t in arg_types): self.fail( "Ellipses cannot accompany other argument types " "in function type signature", lineno, n.col_offset) elif len(arg_types) > len(arg_kinds): self.fail('Type signature has too many arguments', lineno, n.col_offset, blocker=False) elif len(arg_types) < len(arg_kinds): self.fail('Type signature has too few arguments', lineno, n.col_offset, blocker=False) else: any_type = AnyType(TypeOfAny.unannotated) func_type = CallableType( [a if a is not None else any_type for a in arg_types], arg_kinds, arg_names, return_type if return_type is not None else any_type, _dummy_fallback) body = self.as_required_block(n.body, lineno) if decompose_stmts: body.body = decompose_stmts + body.body func_def = FuncDef(n.name, args, body, func_type) if isinstance(func_def.type, CallableType): # semanal.py does some in-place modifications we want to avoid func_def.unanalyzed_type = func_def.type.copy_modified() if func_type is not None: func_type.definition = func_def func_type.line = lineno 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(lineno + len(n.decorator_list)) func_def.body.set_line(func_def.get_line()) dec = Decorator(func_def, self.translate_expr_list(n.decorator_list), var) dec.set_line(lineno, n.col_offset) retval: Statement = dec else: # Overrides set_line -- can't use self.set_line func_def.set_line(lineno, n.col_offset) retval = func_def self.class_and_function_stack.pop() return retval
def test_true_only_of_true_type_is_idempotent(self) -> None: always_true = self.tuple(AnyType(TypeOfAny.special_form)) to = true_only(always_true) assert_true(always_true is to)
def parse_namedtuple_args( self, call: CallExpr, fullname: str ) -> Optional[Tuple[List[str], List[Type], List[Expression], bool]]: """Parse a namedtuple() call into data needed to construct a type. Returns a 4-tuple: - List of argument names - List of argument types - Number of arguments that have a default value - Whether the definition typechecked. Return None if at least one of the types is not ready. """ # TODO: Share code with check_argument_count in checkexpr.py? args = call.args if len(args) < 2: return self.fail_namedtuple_arg( "Too few arguments for namedtuple()", call) defaults = [] # type: List[Expression] if len(args) > 2: # Typed namedtuple doesn't support additional arguments. if fullname == 'typing.NamedTuple': return self.fail_namedtuple_arg( "Too many arguments for NamedTuple()", call) for i, arg_name in enumerate(call.arg_names[2:], 2): if arg_name == 'defaults': arg = args[i] # We don't care what the values are, as long as the argument is an iterable # and we can count how many defaults there are. if isinstance(arg, (ListExpr, TupleExpr)): defaults = list(arg.items) else: self.fail( "List or tuple literal expected as the defaults argument to " "namedtuple()", arg) break if call.arg_kinds[:2] != [ARG_POS, ARG_POS]: return self.fail_namedtuple_arg( "Unexpected arguments to namedtuple()", call) if not isinstance(args[0], (StrExpr, BytesExpr, UnicodeExpr)): return self.fail_namedtuple_arg( "namedtuple() expects a string literal as the first argument", call) types = [] # type: List[Type] ok = True if not isinstance(args[1], (ListExpr, TupleExpr)): if (fullname == 'collections.namedtuple' and isinstance(args[1], (StrExpr, BytesExpr, UnicodeExpr))): str_expr = args[1] items = str_expr.value.replace(',', ' ').split() else: return self.fail_namedtuple_arg( "List or tuple literal expected as the second argument to namedtuple()", call) else: listexpr = args[1] if fullname == 'collections.namedtuple': # The fields argument contains just names, with implicit Any types. if any(not isinstance(item, (StrExpr, BytesExpr, UnicodeExpr)) for item in listexpr.items): return self.fail_namedtuple_arg( "String literal expected as namedtuple() item", call) items = [ cast(Union[StrExpr, BytesExpr, UnicodeExpr], item).value for item in listexpr.items ] else: # The fields argument contains (name, type) tuples. result = self.parse_namedtuple_fields_with_types( listexpr.items, call) if result: items, types, _, ok = result else: # One of the types is not ready, defer. return None if not types: types = [AnyType(TypeOfAny.unannotated) for _ in items] underscore = [item for item in items if item.startswith('_')] if underscore: self.fail( "namedtuple() field names cannot start with an underscore: " + ', '.join(underscore), call) if len(defaults) > len(items): self.fail("Too many defaults given in call to namedtuple()", call) defaults = defaults[:len(items)] return items, types, defaults, ok
def test_nonempty_tuple_always_true(self) -> None: tuple_type = self.tuple(AnyType(TypeOfAny.special_form), AnyType(TypeOfAny.special_form)) assert_true(tuple_type.can_be_true) assert_false(tuple_type.can_be_false)
def test_any(self) -> None: assert_equal(str(AnyType(TypeOfAny.special_form)), 'Any')
def visit_type_type(self, t: TypeType) -> Type: if self.check_recursion(t): return AnyType(TypeOfAny.from_error) return super().visit_type_type(t)
def visit_overloaded(self, t: Overloaded) -> Type: if self.check_recursion(t): return AnyType(TypeOfAny.from_error) return super().visit_overloaded(t)
def get_expected_types(self, api: TypeChecker, model_cls: Type[Model], *, method: str) -> Dict[str, MypyType]: contenttypes_in_apps = self.apps_registry.is_installed( "django.contrib.contenttypes") if contenttypes_in_apps: from django.contrib.contenttypes.fields import GenericForeignKey expected_types = {} # add pk if not abstract=True if not model_cls._meta.abstract: primary_key_field = self.get_primary_key_field(model_cls) field_set_type = self.get_field_set_type(api, primary_key_field, method=method) expected_types["pk"] = field_set_type def get_field_set_type_from_model_type_info( info: Optional[TypeInfo], field_name: str) -> Optional[MypyType]: if info is None: return None field_node = info.names.get(field_name) if field_node is None or not isinstance(field_node.type, Instance): return None elif not field_node.type.args: # Field declares a set and a get type arg. Fallback to `None` when we can't find any args return None set_type = field_node.type.args[0] return set_type model_info = helpers.lookup_class_typeinfo(api, model_cls) for field in model_cls._meta.get_fields(): if isinstance(field, Field): field_name = field.attname # Try to retrieve set type from a model's TypeInfo object and fallback to retrieving it manually # from django-stubs own declaration. This is to align with the setter types declared for # assignment. field_set_type = get_field_set_type_from_model_type_info( model_info, field_name) or self.get_field_set_type( api, field, method=method) expected_types[field_name] = field_set_type if isinstance(field, ForeignKey): field_name = field.name foreign_key_info = helpers.lookup_class_typeinfo( api, field.__class__) if foreign_key_info is None: # maybe there's no type annotation for the field expected_types[field_name] = AnyType( TypeOfAny.unannotated) continue related_model = self.get_field_related_model_cls(field) if related_model is None: expected_types[field_name] = AnyType( TypeOfAny.from_error) continue if related_model._meta.proxy_for_model is not None: related_model = related_model._meta.proxy_for_model related_model_info = helpers.lookup_class_typeinfo( api, related_model) if related_model_info is None: expected_types[field_name] = AnyType( TypeOfAny.unannotated) continue is_nullable = self.get_field_nullability(field, method) foreign_key_set_type = helpers.get_private_descriptor_type( foreign_key_info, "_pyi_private_set_type", is_nullable=is_nullable) model_set_type = helpers.convert_any_to_type( foreign_key_set_type, Instance(related_model_info, [])) expected_types[field_name] = model_set_type elif contenttypes_in_apps and isinstance(field, GenericForeignKey): # it's generic, so cannot set specific model field_name = field.name gfk_info = helpers.lookup_class_typeinfo(api, field.__class__) if gfk_info is None: gfk_set_type: MypyType = AnyType(TypeOfAny.unannotated) else: gfk_set_type = helpers.get_private_descriptor_type( gfk_info, "_pyi_private_set_type", is_nullable=True) expected_types[field_name] = gfk_set_type return expected_types
def visit_instance(self, t: Instance) -> None: info = t.type if info.replaced or info.tuple_type: self.indicator['synthetic'] = True # Check type argument count. if len(t.args) != len(info.type_vars): if len(t.args) == 0: from_builtins = t.type.fullname() in nongen_builtins and not t.from_generic_builtin if (self.options.disallow_any_generics and not self.is_typeshed_stub and from_builtins): alternative = nongen_builtins[t.type.fullname()] self.fail(messages.IMPLICIT_GENERIC_ANY_BUILTIN.format(alternative), t) # Insert implicit 'Any' type arguments. if from_builtins: # this 'Any' was already reported elsewhere any_type = AnyType(TypeOfAny.special_form, line=t.line, column=t.column) else: any_type = AnyType(TypeOfAny.from_omitted_generics, line=t.line, column=t.column) t.args = [any_type] * len(info.type_vars) return # Invalid number of type parameters. n = len(info.type_vars) s = '{} type arguments'.format(n) if n == 0: s = 'no type arguments' elif n == 1: s = '1 type argument' act = str(len(t.args)) if act == '0': act = 'none' self.fail('"{}" expects {}, but {} given'.format( info.name(), s, act), t) # Construct the correct number of type arguments, as # otherwise the type checker may crash as it expects # things to be right. t.args = [AnyType(TypeOfAny.from_error) for _ in info.type_vars] t.invalid = True elif info.defn.type_vars: # Check type argument values. # TODO: Calling is_subtype and is_same_types in semantic analysis is a bad idea for (i, arg), tvar in zip(enumerate(t.args), info.defn.type_vars): if tvar.values: if isinstance(arg, TypeVarType): arg_values = arg.values if not arg_values: self.fail('Type variable "{}" not valid as type ' 'argument value for "{}"'.format( arg.name, info.name()), t) continue else: arg_values = [arg] self.check_type_var_values(info, arg_values, tvar.name, tvar.values, i + 1, t) # TODO: These hacks will be not necessary when this will be moved to later stage. arg = self.resolve_type(arg) bound = self.resolve_type(tvar.upper_bound) if not is_subtype(arg, bound): self.fail('Type argument "{}" of "{}" must be ' 'a subtype of "{}"'.format( arg, info.name(), bound), t) for arg in t.args: arg.accept(self) if info.is_newtype: for base in info.bases: base.accept(self)
def test_false_only_of_true_type_is_uninhabited(self) -> None: fo = false_only(self.tuple(AnyType(TypeOfAny.special_form))) assert_type(UninhabitedType, fo)
def not_implemented(self, msg: str, context: Context) -> Type: self.fail('Feature not implemented yet ({})'.format(msg), context) return AnyType()
def test_generic_unbound_type(self) -> None: u = UnboundType('Foo', [UnboundType('T'), AnyType(TypeOfAny.special_form)]) assert_equal(str(u), 'Foo?[T?, Any]')
def build_namedtuple_typeinfo(self, name: str, items: List[str], types: List[Type], default_items: Mapping[str, Expression], line: int) -> TypeInfo: strtype = self.api.named_type('__builtins__.str') implicit_any = AnyType(TypeOfAny.special_form) basetuple_type = self.api.named_type('__builtins__.tuple', [implicit_any]) dictype = (self.api.named_type_or_none('builtins.dict', [strtype, implicit_any]) or self.api.named_type('__builtins__.object')) # Actual signature should return OrderedDict[str, Union[types]] ordereddictype = (self.api.named_type_or_none('builtins.dict', [strtype, implicit_any]) or self.api.named_type('__builtins__.object')) fallback = self.api.named_type('__builtins__.tuple', [implicit_any]) # Note: actual signature should accept an invariant version of Iterable[UnionType[types]]. # but it can't be expressed. 'new' and 'len' should be callable types. iterable_type = self.api.named_type_or_none('typing.Iterable', [implicit_any]) function_type = self.api.named_type('__builtins__.function') info = self.api.basic_new_typeinfo(name, fallback) info.is_named_tuple = True tuple_base = TupleType(types, fallback) info.tuple_type = tuple_base info.line = line # We can't calculate the complete fallback type until after semantic # analysis, since otherwise base classes might be incomplete. Postpone a # callback function that patches the fallback. self.api.schedule_patch(PRIORITY_FALLBACKS, lambda: calculate_tuple_fallback(tuple_base)) def add_field(var: Var, is_initialized_in_class: bool = False, is_property: bool = False) -> None: var.info = info var.is_initialized_in_class = is_initialized_in_class var.is_property = is_property var._fullname = '%s.%s' % (info.fullname(), var.name()) info.names[var.name()] = SymbolTableNode(MDEF, var) fields = [Var(item, typ) for item, typ in zip(items, types)] for var in fields: add_field(var, is_property=True) # We can't share Vars between fields and method arguments, since they # have different full names (the latter are normally used as local variables # in functions, so their full names are set to short names when generated methods # are analyzed). vars = [Var(item, typ) for item, typ in zip(items, types)] tuple_of_strings = TupleType([strtype for _ in items], basetuple_type) add_field(Var('_fields', tuple_of_strings), is_initialized_in_class=True) add_field(Var('_field_types', dictype), is_initialized_in_class=True) add_field(Var('_field_defaults', dictype), is_initialized_in_class=True) add_field(Var('_source', strtype), is_initialized_in_class=True) add_field(Var('__annotations__', ordereddictype), is_initialized_in_class=True) add_field(Var('__doc__', strtype), is_initialized_in_class=True) tvd = TypeVarDef(SELF_TVAR_NAME, info.fullname() + '.' + SELF_TVAR_NAME, -1, [], info.tuple_type) selftype = TypeVarType(tvd) def add_method( funcname: str, ret: Type, args: List[Argument], is_classmethod: bool = False, is_new: bool = False, ) -> None: if is_classmethod or is_new: first = [ Argument(Var('_cls'), TypeType.make_normalized(selftype), None, ARG_POS) ] else: first = [Argument(Var('_self'), selftype, None, ARG_POS)] args = first + args types = [arg.type_annotation for arg in args] items = [arg.variable.name() for arg in args] arg_kinds = [arg.kind for arg in args] assert None not in types signature = CallableType(cast(List[Type], types), arg_kinds, items, ret, function_type) signature.variables = [tvd] func = FuncDef(funcname, args, Block([])) func.info = info func.is_class = is_classmethod func.type = set_callable_name(signature, func) func._fullname = info.fullname() + '.' + funcname func.line = line if is_classmethod: v = Var(funcname, func.type) v.is_classmethod = True v.info = info v._fullname = func._fullname func.is_decorated = True dec = Decorator(func, [NameExpr('classmethod')], v) dec.line = line sym = SymbolTableNode(MDEF, dec) else: sym = SymbolTableNode(MDEF, func) sym.plugin_generated = True info.names[funcname] = sym add_method('_replace', ret=selftype, args=[ Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars ]) def make_init_arg(var: Var) -> Argument: default = default_items.get(var.name(), None) kind = ARG_POS if default is None else ARG_OPT return Argument(var, var.type, default, kind) add_method('__new__', ret=selftype, args=[make_init_arg(var) for var in vars], is_new=True) add_method('_asdict', args=[], ret=ordereddictype) special_form_any = AnyType(TypeOfAny.special_form) add_method('_make', ret=selftype, is_classmethod=True, args=[ Argument(Var('iterable', iterable_type), iterable_type, None, ARG_POS), Argument(Var('new'), special_form_any, EllipsisExpr(), ARG_NAMED_OPT), Argument(Var('len'), special_form_any, EllipsisExpr(), ARG_NAMED_OPT) ]) self_tvar_expr = TypeVarExpr(SELF_TVAR_NAME, info.fullname() + '.' + SELF_TVAR_NAME, [], info.tuple_type) info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr) return info
def resolve_f_expression_type(self, f_expression_type: Instance) -> MypyType: return AnyType(TypeOfAny.explicit)
def visit_FunctionDef(self, n: ast27.FunctionDef) -> Node: converter = TypeConverter(line=n.lineno) 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 and len(n.type_comment) > 0: 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 = [ a.type_annotation if a.type_annotation is not None else AnyType() for a in args ] else: arg_types = [ a if a is not None else AnyType() for a in converter.visit_list(func_type_ast.argtypes) ] return_type = converter.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 = converter.visit(None) for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) if isinstance(return_type, UnboundType): return_type.is_ret_type = True 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 func_type.line = n.lineno 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 visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement: converter = TypeConverter(self.errors, line=n.lineno) args, decompose_stmts = self.transform_args(n.args, n.lineno) arg_kinds = [arg.kind for arg in args] arg_names = [arg.variable.name() for arg in args] # type: List[Optional[str]] arg_names = [ None if argument_elide_name(name) else name for name in arg_names ] if special_function_elide_names(n.name): arg_names = [None] * len(arg_names) arg_types = None # type: List[Type] if (n.decorator_list and any( is_no_type_check_decorator(d) for d in n.decorator_list)): arg_types = [None] * len(args) return_type = None elif n.type_comment is not None and len(n.type_comment) > 0: try: func_type_ast = ast3.parse(n.type_comment, '<func_type>', 'func_type') assert isinstance(func_type_ast, ast3.FunctionType) # for ellipsis arg if (len(func_type_ast.argtypes) == 1 and isinstance( func_type_ast.argtypes[0], ast3.Ellipsis)): arg_types = [ a.type_annotation if a.type_annotation is not None else AnyType() for a in args ] else: # PEP 484 disallows both type annotations and type comments if any(a.type_annotation is not None for a in args): self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno, n.col_offset) arg_types = [ a if a is not None else AnyType() for a in converter.translate_expr_list(func_type_ast.argtypes) ] return_type = converter.visit(func_type_ast.returns) # add implicit self type if self.in_class() and len(arg_types) < len(args): arg_types.insert(0, AnyType()) except SyntaxError: self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset) arg_types = [AnyType()] * len(args) return_type = AnyType() else: arg_types = [a.type_annotation for a in args] return_type = converter.visit(None) for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) func_type = None if any(arg_types) or return_type: if len(arg_types) != 1 and any( isinstance(t, EllipsisType) for t in arg_types): self.fail( "Ellipses cannot accompany other argument types " "in function type signature.", n.lineno, 0) elif len(arg_types) > len(arg_kinds): self.fail('Type signature has too many arguments', n.lineno, 0) elif len(arg_types) < len(arg_kinds): self.fail('Type signature has too few arguments', n.lineno, 0) else: 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) body = self.as_block(n.body, n.lineno) if decompose_stmts: body.body = decompose_stmts + body.body func_def = FuncDef(n.name, args, body, func_type) if func_type is not None: func_type.definition = func_def func_type.line = n.lineno 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.translate_expr_list(n.decorator_list), var) else: return func_def
def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, mx: MemberContext) -> Type: """Analyse attribute access that does not target a method. This is logically part of analyze_member_access and the arguments are similar. original_type is the type of E in the expression E.var """ # It was not a method. Try looking up a variable. v = lookup_member_var_or_accessor(info, name, mx.is_lvalue) vv = v if isinstance(vv, Decorator): # The associated Var node of a decorator contains the type. v = vv.var if isinstance(vv, TypeInfo): # If the associated variable is a TypeInfo synthesize a Var node for # the purposes of type checking. This enables us to type check things # like accessing class attributes on an inner class. v = Var(name, type=type_object_type(vv, mx.builtin_type)) v.info = info if isinstance(vv, TypeAlias) and isinstance(get_proper_type(vv.target), Instance): # Similar to the above TypeInfo case, we allow using # qualified type aliases in runtime context if it refers to an # instance type. For example: # class C: # A = List[int] # x = C.A() <- this is OK typ = instance_alias_type(vv, mx.builtin_type) v = Var(name, type=typ) v.info = info if isinstance(v, Var): implicit = info[name].implicit # An assignment to final attribute is always an error, # independently of types. if mx.is_lvalue and not mx.chk.get_final_context(): check_final_member(name, info, mx.msg, mx.context) return analyze_var(name, v, itype, info, mx, implicit=implicit) elif isinstance(v, FuncDef): assert False, "Did not expect a function" elif (not v and name not in ['__getattr__', '__setattr__', '__getattribute__'] and not mx.is_operator): if not mx.is_lvalue: for method_name in ('__getattribute__', '__getattr__'): method = info.get_method(method_name) # __getattribute__ is defined on builtins.object and returns Any, so without # the guard this search will always find object.__getattribute__ and conclude # that the attribute exists if method and method.info.fullname != 'builtins.object': function = function_type( method, mx.builtin_type('builtins.function')) bound_method = bind_self(function, mx.self_type) typ = map_instance_to_supertype(itype, method.info) getattr_type = get_proper_type( expand_type_by_instance(bound_method, typ)) if isinstance(getattr_type, CallableType): result = getattr_type.ret_type # Call the attribute hook before returning. fullname = '{}.{}'.format(method.info.fullname, name) hook = mx.chk.plugin.get_attribute_hook(fullname) if hook: result = hook( AttributeContext( get_proper_type(mx.original_type), result, mx.context, mx.chk)) return result else: setattr_meth = info.get_method('__setattr__') if setattr_meth and setattr_meth.info.fullname != 'builtins.object': setattr_func = function_type( setattr_meth, mx.builtin_type('builtins.function')) bound_type = bind_self(setattr_func, mx.self_type) typ = map_instance_to_supertype(itype, setattr_meth.info) setattr_type = get_proper_type( expand_type_by_instance(bound_type, typ)) if isinstance( setattr_type, CallableType) and len(setattr_type.arg_types) > 0: return setattr_type.arg_types[-1] if itype.type.fallback_to_any: return AnyType(TypeOfAny.special_form) # Could not find the member. if mx.is_super: mx.msg.undefined_in_superclass(name, mx.context) return AnyType(TypeOfAny.from_error) else: if mx.chk and mx.chk.should_suppress_optional_error([itype]): return AnyType(TypeOfAny.from_error) return mx.msg.has_no_attr(mx.original_type, itype, name, mx.context, mx.module_symbol_table)
def infer_against_any(self, types: List[Type]) -> List[Constraint]: res = [] # type: List[Constraint] for t in types: res.extend(infer_constraints(t, AnyType(), self.direction)) return res
def analyze_var(name: str, var: Var, itype: Instance, info: TypeInfo, mx: MemberContext, *, implicit: bool = False) -> Type: """Analyze access to an attribute via a Var node. This is conceptually part of analyze_member_access and the arguments are similar. itype is the class object in which var is defined original_type is the type of E in the expression E.var if implicit is True, the original Var was created as an assignment to self """ # Found a member variable. itype = map_instance_to_supertype(itype, var.info) typ = var.type if typ: if isinstance(typ, PartialType): return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context) if mx.is_lvalue and var.is_property and not var.is_settable_property: # TODO allow setting attributes in subclass (although it is probably an error) mx.msg.read_only_property(name, itype.type, mx.context) if mx.is_lvalue and var.is_classvar: mx.msg.cant_assign_to_classvar(name, mx.context) t = get_proper_type(expand_type_by_instance(typ, itype)) result = t # type: Type typ = get_proper_type(typ) if var.is_initialized_in_class and isinstance( typ, FunctionLike) and not typ.is_type_obj(): if mx.is_lvalue: if var.is_property: if not var.is_settable_property: mx.msg.read_only_property(name, itype.type, mx.context) else: mx.msg.cant_assign_to_method(mx.context) if not var.is_staticmethod: # Class-level function objects and classmethods become bound methods: # the former to the instance, the latter to the class. functype = typ # Use meet to narrow original_type to the dispatched type. # For example, assume # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A) # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B) # * x: Union[A1, B1] # In `x.f`, when checking `x` against A1 we assume x is compatible with A # and similarly for B1 when checking against B dispatched_type = meet.meet_types(mx.original_type, itype) signature = freshen_function_type_vars(functype) signature = check_self_arg(signature, dispatched_type, var.is_classmethod, mx.context, name, mx.msg) signature = bind_self(signature, mx.self_type, var.is_classmethod) expanded_signature = get_proper_type( expand_type_by_instance(signature, itype)) freeze_type_vars(expanded_signature) if var.is_property: # A property cannot have an overloaded type => the cast is fine. assert isinstance(expanded_signature, CallableType) result = expanded_signature.ret_type else: result = expanded_signature else: if not var.is_ready: mx.not_ready_callback(var.name, mx.context) # Implicit 'Any' type. result = AnyType(TypeOfAny.special_form) fullname = '{}.{}'.format(var.info.fullname, name) hook = mx.chk.plugin.get_attribute_hook(fullname) if result and not mx.is_lvalue and not implicit: result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk) if hook: result = hook( AttributeContext(get_proper_type(mx.original_type), result, mx.context, mx.chk)) return result
def visit_unbound_type(self, t: UnboundType) -> ProperType: return AnyType(TypeOfAny.special_form)
def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) -> ProperType: """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('__init__') new_method = info.get('__new__') if not init_method or not is_valid_constructor(init_method.node): # 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 if not is_valid_constructor(new_method.node): # Must be an invalid class definition. return AnyType(TypeOfAny.from_error) # The two is_valid_constructor() checks ensure this. assert isinstance(new_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator)) assert isinstance(init_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator)) init_index = info.mro.index(init_method.node.info) new_index = info.mro.index(new_method.node.info) fallback = info.metaclass_type or builtin_type('builtins.type') if init_index < new_index: method = init_method.node # type: Union[FuncBase, Decorator] is_new = False elif init_index > new_index: method = new_method.node is_new = True else: if init_method.node.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, is_new=False) # 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.node is_new = False # Construct callable type based on signature of __init__. Adjust # return type and insert type arguments. if isinstance(method, FuncBase): t = function_type(method, fallback) else: assert isinstance(method.type, ProperType) assert isinstance(method.type, FunctionLike) # is_valid_constructor() ensures this t = method.type return type_object_type_from_function(t, info, method.info, fallback, is_new)
def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.info[self.name].type if self.converter.name: # When a converter is set the init_type is overridden by the first argument # of the converter method. converter = lookup_qualified_stnode(ctx.api.modules, self.converter.name, True) if not converter: # The converter may be a local variable. Check there too. converter = ctx.api.lookup_qualified(self.converter.name, self.info, True) # Get the type of the converter. converter_type = None if converter and isinstance(converter.node, TypeInfo): from mypy.checkmember import type_object_type # To avoid import cycle. converter_type = type_object_type(converter.node, ctx.api.builtin_type) elif converter and isinstance(converter.node, OverloadedFuncDef): converter_type = converter.node.type elif converter and converter.type: converter_type = converter.type init_type = None if isinstance(converter_type, CallableType) and converter_type.arg_types: init_type = ctx.api.anal_type(converter_type.arg_types[0]) elif isinstance(converter_type, Overloaded): types = [] # type: List[Type] for item in converter_type.items(): # Walk the overloads looking for methods that can accept one argument. num_arg_types = len(item.arg_types) if not num_arg_types: continue if num_arg_types > 1 and any( kind == ARG_POS for kind in item.arg_kinds[1:]): continue types.append(item.arg_types[0]) # Make a union of all the valid types. if types: args = UnionType.make_simplified_union(types) init_type = ctx.api.anal_type(args) if self.converter.is_attr_converters_optional and init_type: # If the converter was attr.converter.optional(type) then add None to # the allowed init_type. init_type = UnionType.make_union([init_type, NoneType()]) if not init_type: ctx.api.fail("Cannot determine __init__ type from converter", self.context) init_type = AnyType(TypeOfAny.from_error) elif self.converter.name == '': # This means we had a converter but it's not of a type we can infer. # Error was shown in _get_converter_name init_type = AnyType(TypeOfAny.from_error) if init_type is None: if ctx.api.options.disallow_untyped_defs: # This is a compromise. If you don't have a type here then the # __init__ will be untyped. But since the __init__ is added it's # pointing at the decorator. So instead we also show the error in the # assignment, which is where you would fix the issue. node = self.info[self.name].node assert node is not None ctx.api.msg.need_annotation_for_var(node, self.context) # Convert type not set to Any. init_type = AnyType(TypeOfAny.unannotated) if self.kw_only: arg_kind = ARG_NAMED_OPT if self.has_default else ARG_NAMED else: arg_kind = ARG_OPT if self.has_default else ARG_POS # Attrs removes leading underscores when creating the __init__ arguments. return Argument(Var(self.name.lstrip("_"), init_type), init_type, None, arg_kind)
def generic_visit(self, node: ast3.AST) -> Type: # type: ignore self.fail(TYPE_COMMENT_AST_ERROR, self.line, getattr(node, 'col_offset', -1)) return AnyType(TypeOfAny.from_error)
def not_callable(self, typ: Type, context: Context) -> Type: self.fail('{} not callable'.format(self.format(typ)), context) return AnyType()
def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef], is_coroutine: bool = False) -> Union[FuncDef, Decorator]: """Helper shared between visit_FunctionDef and visit_AsyncFunctionDef.""" no_type_check = bool( n.decorator_list and any(is_no_type_check_decorator(d) for d in n.decorator_list)) args = self.transform_args(n.args, n.lineno, no_type_check=no_type_check) arg_kinds = [arg.kind for arg in args] arg_names = [arg.variable.name() for arg in args] # type: List[Optional[str]] arg_names = [ None if argument_elide_name(name) else name for name in arg_names ] if special_function_elide_names(n.name): arg_names = [None] * len(arg_names) arg_types = [] # type: List[Optional[Type]] if no_type_check: arg_types = [None] * len(args) return_type = None elif n.type_comment is not None: try: func_type_ast = ast3.parse(n.type_comment, '<func_type>', 'func_type') assert isinstance(func_type_ast, ast3.FunctionType) # for ellipsis arg if (len(func_type_ast.argtypes) == 1 and isinstance( func_type_ast.argtypes[0], ast3.Ellipsis)): if n.returns: # PEP 484 disallows both type annotations and type comments self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno, n.col_offset) arg_types = [ a.type_annotation if a.type_annotation is not None else AnyType(TypeOfAny.unannotated) for a in args ] else: # PEP 484 disallows both type annotations and type comments if n.returns or any(a.type_annotation is not None for a in args): self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno, n.col_offset) translated_args = (TypeConverter( self.errors, line=n.lineno).translate_expr_list( func_type_ast.argtypes)) arg_types = [ a if a is not None else AnyType(TypeOfAny.unannotated) for a in translated_args ] return_type = TypeConverter(self.errors, 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(TypeOfAny.special_form)) except SyntaxError: self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset) if n.type_comment and n.type_comment[0] != "(": self.note('Suggestion: wrap argument types in parentheses', n.lineno, n.col_offset) arg_types = [AnyType(TypeOfAny.from_error)] * len(args) return_type = AnyType(TypeOfAny.from_error) else: arg_types = [a.type_annotation for a in args] return_type = TypeConverter( self.errors, line=n.returns.lineno if n.returns else n.lineno).visit( n.returns) for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) func_type = None if any(arg_types) or return_type: if len(arg_types) != 1 and any( isinstance(t, EllipsisType) for t in arg_types): self.fail( "Ellipses cannot accompany other argument types " "in function type signature.", n.lineno, 0) elif len(arg_types) > len(arg_kinds): self.fail('Type signature has too many arguments', n.lineno, 0) elif len(arg_types) < len(arg_kinds): self.fail('Type signature has too few arguments', n.lineno, 0) else: func_type = CallableType([ a if a is not None else AnyType(TypeOfAny.unannotated) for a in arg_types ], arg_kinds, arg_names, return_type if return_type is not None else AnyType(TypeOfAny.unannotated), _dummy_fallback) func_def = FuncDef(n.name, args, self.as_required_block(n.body, n.lineno), func_type) if is_coroutine: # A coroutine is also a generator, mostly for internal reasons. func_def.is_generator = func_def.is_coroutine = True if func_type is not None: func_type.definition = func_def func_type.line = n.lineno 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.translate_expr_list(n.decorator_list), var) else: return func_def
def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement: converter = TypeConverter(self.errors, line=n.lineno) args, decompose_stmts = self.transform_args(n.args, n.lineno) arg_kinds = [arg.kind for arg in args] arg_names = [arg.variable.name() for arg in args] # type: List[Optional[str]] arg_names = [None if argument_elide_name(name) else name for name in arg_names] if special_function_elide_names(n.name): arg_names = [None] * len(arg_names) arg_types = None # type: List[Type] if (n.decorator_list and any(is_no_type_check_decorator(d) for d in n.decorator_list)): arg_types = [None] * len(args) return_type = None elif n.type_comment is not None and len(n.type_comment) > 0: try: func_type_ast = ast35.parse(n.type_comment, '<func_type>', 'func_type') 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 = [a.type_annotation if a.type_annotation is not None else AnyType() for a in args] else: # PEP 484 disallows both type annotations and type comments if any(a.type_annotation is not None for a in args): self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno, n.col_offset) arg_types = [a if a is not None else AnyType() for a in converter.translate_expr_list(func_type_ast.argtypes)] return_type = converter.visit(func_type_ast.returns) # add implicit self type if self.in_class() and len(arg_types) < len(args): arg_types.insert(0, AnyType()) except SyntaxError: self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset) arg_types = [AnyType()] * len(args) return_type = AnyType() else: arg_types = [a.type_annotation for a in args] return_type = converter.visit(None) for arg, arg_type in zip(args, arg_types): self.set_type_optional(arg_type, arg.initializer) if isinstance(return_type, UnboundType): return_type.is_ret_type = True func_type = None if any(arg_types) or return_type: if len(arg_types) != 1 and any(isinstance(t, EllipsisType) for t in arg_types): self.fail("Ellipses cannot accompany other argument types " "in function type signature.", n.lineno, 0) elif len(arg_types) > len(arg_kinds): self.fail('Type signature has too many arguments', n.lineno, 0) elif len(arg_types) < len(arg_kinds): self.fail('Type signature has too few arguments', n.lineno, 0) else: 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) body = self.as_block(n.body, n.lineno) if decompose_stmts: body.body = decompose_stmts + body.body func_def = FuncDef(n.name, args, body, func_type) if func_type is not None: func_type.definition = func_def func_type.line = n.lineno 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.translate_expr_list(n.decorator_list), var) else: return func_def