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'. """ init_method = info.get_method('__init__') if not init_method: # Must be an invalid class definition. return AnyType() else: fallback = builtin_type('builtins.type') if init_method.info.fullname() == 'builtins.object': # No non-default __init__ -> look at __new__ instead. new_method = info.get_method('__new__') if new_method and new_method.info.fullname() != 'builtins.object': # Found one! Get signature from __new__. return type_object_type_from_function(new_method, info, fallback) # 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. sig = CallableType(arg_types=[AnyType(), AnyType()], arg_kinds=[ARG_STAR, ARG_STAR2], arg_names=["_args", "_kwds"], ret_type=AnyType(), fallback=builtin_type('builtins.function')) return class_callable(sig, info, fallback, None) # Construct callable type based on signature of __init__. Adjust # return type and insert type arguments. return type_object_type_from_function(init_method, info, fallback)
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 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 of form def [T, S](...) -> G[T, S], where ... are argument types for the __init__ method (without the self argument). """ init_method = info.get_method('__init__') if not init_method: # Must be an invalid class definition. return AnyType() else: # Construct callable type based on signature of __init__. Adjust # return type and insert type arguments. init_type = method_type_with_fallback(init_method, builtin_type('builtins.function')) if isinstance(init_type, CallableType): return class_callable(init_type, info, builtin_type('builtins.type')) else: # Overloaded __init__. items = [] # type: List[CallableType] for it in cast(Overloaded, init_type).items(): items.append(class_callable(it, info, builtin_type('builtins.type'))) return Overloaded(items)
def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, node: Context, is_lvalue: bool, is_super: bool, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, original_type: Type, chk: 'mypy.checker.TypeChecker' = None) -> 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, is_lvalue) vv = v if isinstance(vv, Decorator): # The associated Var node of a decorator contains the type. v = vv.var if isinstance(v, Var): return analyze_var(name, v, itype, info, node, is_lvalue, msg, original_type, not_ready_callback) elif isinstance(v, FuncDef): assert False, "Did not expect a function" elif not v and name not in ['__getattr__', '__setattr__', '__getattribute__']: if not 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, builtin_type('builtins.function')) bound_method = bind_self(function, original_type) typ = map_instance_to_supertype(itype, method.info) getattr_type = expand_type_by_instance(bound_method, typ) if isinstance(getattr_type, CallableType): return getattr_type.ret_type if itype.type.fallback_to_any: return AnyType() # Could not find the member. if is_super: msg.undefined_in_superclass(name, node) return AnyType() else: if chk and chk.should_suppress_optional_error([itype]): return AnyType() return msg.has_no_attr(original_type, name, node)
def analyze_member_var_access( name: str, itype: Instance, info: TypeInfo, node: Context, is_lvalue: bool, is_super: bool, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, report_type: Type = None, chk: "mypy.checker.TypeChecker" = None, ) -> Type: """Analyse attribute access that does not target a method. This is logically part of analyze_member_access and the arguments are similar. """ # It was not a method. Try looking up a variable. v = lookup_member_var_or_accessor(info, name, is_lvalue) vv = v if isinstance(vv, Decorator): # The associated Var node of a decorator contains the type. v = vv.var if isinstance(v, Var): return analyze_var(name, v, itype, info, node, is_lvalue, msg, not_ready_callback) elif isinstance(v, FuncDef): assert False, "Did not expect a function" elif not v and name not in ["__getattr__", "__setattr__"]: if not is_lvalue: method = info.get_method("__getattr__") if method: typ = map_instance_to_supertype(itype, method.info) getattr_type = expand_type_by_instance( method_type_with_fallback(method, builtin_type("builtins.function")), typ ) if isinstance(getattr_type, CallableType): return getattr_type.ret_type if itype.type.fallback_to_any: return AnyType() # Could not find the member. if is_super: msg.undefined_in_superclass(name, node) return AnyType() else: if chk and chk.should_suppress_optional_error([itype]): return AnyType() return msg.has_no_attr(report_type or itype, name, node)
def get_member_flags(name: str, info: TypeInfo) -> Set[int]: """Detect whether a member 'name' is settable, whether it is an instance or class variable, and whether it is class or static method. The flags are defined as following: * IS_SETTABLE: whether this attribute can be set, not set for methods and non-settable properties; * IS_CLASSVAR: set if the variable is annotated as 'x: ClassVar[t]'; * IS_CLASS_OR_STATIC: set for methods decorated with @classmethod or with @staticmethod. """ method = info.get_method(name) setattr_meth = info.get_method('__setattr__') if method: # this could be settable property if method.is_property: assert isinstance(method, OverloadedFuncDef) dec = method.items[0] assert isinstance(dec, Decorator) if dec.var.is_settable_property or setattr_meth: return {IS_SETTABLE} return set() node = info.get(name) if not node: if setattr_meth: return {IS_SETTABLE} return set() v = node.node if isinstance(v, Decorator): if v.var.is_staticmethod or v.var.is_classmethod: return {IS_CLASS_OR_STATIC} # just a variable if isinstance(v, Var): flags = {IS_SETTABLE} if v.is_classvar: flags.add(IS_CLASSVAR) return flags return set()
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(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.original_type) typ = map_instance_to_supertype(itype, method.info) getattr_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(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.original_type) typ = map_instance_to_supertype(itype, setattr_meth.info) setattr_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)
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(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.original_type) typ = map_instance_to_supertype(itype, method.info) getattr_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(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.original_type) typ = map_instance_to_supertype(itype, setattr_meth.info) setattr_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)
def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, node: Context, is_lvalue: bool, is_super: bool, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, original_type: Type, chk: 'mypy.checker.TypeChecker') -> 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, 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, builtin_type)) v.info = info if isinstance(v, Var): return analyze_var(name, v, itype, info, node, is_lvalue, msg, original_type, not_ready_callback, chk=chk) elif isinstance(v, FuncDef): assert False, "Did not expect a function" elif not v and name not in [ '__getattr__', '__setattr__', '__getattribute__' ]: if not 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, builtin_type('builtins.function')) bound_method = bind_self(function, original_type) typ = map_instance_to_supertype(itype, method.info) getattr_type = expand_type_by_instance(bound_method, typ) if isinstance(getattr_type, CallableType): return getattr_type.ret_type else: setattr_meth = info.get_method('__setattr__') if setattr_meth and setattr_meth.info.fullname( ) != 'builtins.object': setattr_func = function_type(setattr_meth, builtin_type('builtins.function')) bound_type = bind_self(setattr_func, original_type) typ = map_instance_to_supertype(itype, setattr_meth.info) setattr_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() # Could not find the member. if is_super: msg.undefined_in_superclass(name, node) return AnyType() else: if chk and chk.should_suppress_optional_error([itype]): return AnyType() return msg.has_no_attr(original_type, itype, name, node)
def get_member_reference_suffix(self, name: str, info: TypeInfo) -> str: if info.has_method(name): fdef = cast(FuncDef, info.get_method(name)) return self.type_suffix(fdef) else: return ''