def default(self, typ): if isinstance(typ, UnboundType): return AnyType() elif isinstance(typ, Void) or isinstance(typ, ErrorType): return ErrorType() else: return NoneTyp()
def make_optional_type(t: Type) -> Type: """Return the type corresponding to Optional[t]. Note that we can't use normal union simplification, since this function is called during semantic analysis and simplification only works during type checking. """ if isinstance(t, NoneTyp): return t elif isinstance(t, UnionType): items = [ item for item in union_items(t) if not isinstance(item, NoneTyp) ] return UnionType(items + [NoneTyp()], t.line, t.column) else: return UnionType([t, NoneTyp()], t.line, t.column)
def test_callable_type(self) -> None: c = CallableType([self.x, self.y], [ARG_POS, ARG_POS], [None, None], AnyType(TypeOfAny.special_form), self.function) assert_equal(str(c), 'def (X?, Y?) -> Any') c2 = CallableType([], [], [], NoneTyp(), self.fx.function) assert_equal(str(c2), 'def ()')
def typed_dict_get_callback(ctx: MethodContext) -> Type: """Infer a precise return type for TypedDict.get with literal first argument.""" if (isinstance(ctx.type, TypedDictType) and len(ctx.arg_types) >= 1 and len(ctx.arg_types[0]) == 1): key = try_getting_str_literal(ctx.args[0][0], ctx.arg_types[0][0]) if key is None: return ctx.default_return_type value_type = ctx.type.items.get(key) if value_type: if len(ctx.arg_types) == 1: return UnionType.make_simplified_union([value_type, NoneTyp()]) elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1 and len(ctx.args[1]) == 1): default_arg = ctx.args[1][0] if (isinstance(default_arg, DictExpr) and len(default_arg.items) == 0 and isinstance(value_type, TypedDictType)): # Special case '{}' as the default for a typed dict type. return value_type.copy_modified(required_keys=set()) else: return UnionType.make_simplified_union( [value_type, ctx.arg_types[1][0]]) else: ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context) return AnyType(TypeOfAny.from_error) return ctx.default_return_type
def _autoconvertible_to_cdata( tp: Type, api: 'mypy.plugin.CheckerPluginInterface') -> Type: """Get a type that is compatible with all types that can be implicitly converted to the given CData type. Examples: * c_int -> Union[c_int, int] * c_char_p -> Union[c_char_p, bytes, int, NoneType] * MyStructure -> MyStructure """ allowed_types = [] # If tp is a union, we allow all types that are convertible to at least one of the union # items. This is not quite correct - strictly speaking, only types convertible to *all* of the # union items should be allowed. This may be worth changing in the future, but the more # correct algorithm could be too strict to be useful. for t in union_items(tp): # Every type can be converted from itself (obviously). allowed_types.append(t) if isinstance(t, Instance): unboxed = _find_simplecdata_base_arg(t, api) if unboxed is not None: # If _SimpleCData appears in tp's (direct or indirect) bases, its type argument # specifies the type's "unboxed" version, which can always be converted back to # the original "boxed" type. allowed_types.append(unboxed) if t.type.has_base('ctypes._PointerLike'): # Pointer-like _SimpleCData subclasses can also be converted from # an int or None. allowed_types.append( api.named_generic_type('builtins.int', [])) allowed_types.append(NoneTyp()) return UnionType.make_simplified_union(allowed_types)
def column_hook(ctx: FunctionContext) -> Type: """Infer better types for Column calls. Examples: Column(String) -> Column[Optional[str]] Column(String, primary_key=True) -> Column[str] Column(String, nullable=False) -> Column[str] Column(String, default=...) -> Column[str] Column(String, default=..., nullable=True) -> Column[Optional[str]] TODO: check the type of 'default'. """ assert isinstance(ctx.default_return_type, Instance) nullable_arg = get_argument_by_name(ctx, 'nullable') primary_arg = get_argument_by_name(ctx, 'primary_key') default_arg = get_argument_by_name(ctx, 'default') if nullable_arg: nullable = parse_bool(nullable_arg) else: if primary_arg: nullable = not parse_bool(primary_arg) else: nullable = default_arg is None # TODO: Add support for literal types. if not nullable: return ctx.default_return_type assert len(ctx.default_return_type.args) == 1 arg_type = ctx.default_return_type.args[0] return Instance(ctx.default_return_type.type, [UnionType([arg_type, NoneTyp()])], line=ctx.default_return_type.line, column=ctx.default_return_type.column)
def narrow_declared_type(declared: Type, narrowed: Type) -> Type: """Return the declared type narrowed down to another type.""" if declared == narrowed: return declared if isinstance(declared, UnionType): return UnionType.make_simplified_union([ narrow_declared_type(x, narrowed) for x in declared.relevant_items() ]) elif not is_overlapping_types( declared, narrowed, prohibit_none_typevar_overlap=True): if state.strict_optional: return UninhabitedType() else: return NoneTyp() elif isinstance(narrowed, UnionType): return UnionType.make_simplified_union([ narrow_declared_type(declared, x) for x in narrowed.relevant_items() ]) elif isinstance(narrowed, AnyType): return narrowed elif isinstance(declared, (Instance, TupleType)): return meet_types(declared, narrowed) elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType): return TypeType.make_normalized( narrow_declared_type(declared.item, narrowed.item)) return narrowed
def add_model_init_hook(ctx: ClassDefContext) -> None: """Add a dummy __init__() to a model and record it is generated. Instantiation will be checked more precisely when we inferred types (using get_function_hook and model_hook). """ if '__init__' in ctx.cls.info.names: # Don't override existing definition. return any = AnyType(TypeOfAny.special_form) var = Var('kwargs', any) kw_arg = Argument(variable=var, type_annotation=any, initializer=None, kind=ARG_STAR2) add_method(ctx, '__init__', [kw_arg], NoneTyp()) ctx.cls.info.metadata.setdefault('sqlalchemy', {})['generated_init'] = True # Also add a selection of auto-generated attributes. sym = ctx.api.lookup_fully_qualified_or_none('sqlalchemy.sql.schema.Table') if sym: assert isinstance(sym.node, TypeInfo) typ = Instance(sym.node, []) # type: Type else: typ = AnyType(TypeOfAny.special_form) add_var_to_class('__table__', typ, ctx.cls.info)
def narrow_declared_type(declared: Type, narrowed: Type) -> Type: """Return the declared type narrowed down to another type.""" if declared == narrowed: return declared if isinstance(declared, UnionType): return UnionType.make_simplified_union([ narrow_declared_type(x, narrowed) for x in declared.relevant_items() ]) elif not is_overlapping_types(declared, narrowed, use_promotions=True): if experiments.STRICT_OPTIONAL: return UninhabitedType() else: return NoneTyp() elif isinstance(narrowed, UnionType): return UnionType.make_simplified_union([ narrow_declared_type(declared, x) for x in narrowed.relevant_items() ]) elif isinstance(narrowed, AnyType): return narrowed elif isinstance(declared, (Instance, TupleType)): return meet_types(declared, narrowed) elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType): return TypeType.make_normalized( narrow_declared_type(declared.item, narrowed.item)) return narrowed
def analyze_interface_base(classdef_ctx: ClassDefContext) -> None: # Create fake constructor to mimic adaptation signature info = classdef_ctx.cls.info api = classdef_ctx.api if "__init__" in info.names: # already patched return # Create a method: # # def __init__(self, obj, alternate=None) -> None # # This will make interfaces selftp = Instance(info, []) anytp = AnyType(TypeOfAny.implementation_artifact) init_fn = CallableType( arg_types=[selftp, anytp, anytp], arg_kinds=[ARG_POS, ARG_POS, ARG_OPT], arg_names=["self", "obj", "alternate"], ret_type=NoneTyp(), fallback=api.named_type("function"), ) newinit = FuncDef("__init__", [], Block([]), init_fn) newinit.info = info info.names["__init__"] = SymbolTableNode( MDEF, newinit, plugin_generated=True )
def default(self, typ: Type) -> Type: if isinstance(typ, UnboundType): return AnyType(TypeOfAny.special_form) else: if experiments.STRICT_OPTIONAL: return UninhabitedType() else: return NoneTyp()
def _add_init(ctx: 'mypy.plugin.ClassDefContext', attributes: List[Attribute], adder: 'MethodAdder') -> None: """Generate an __init__ method for the attributes and add it to the class.""" adder.add_method( '__init__', [attribute.argument(ctx) for attribute in attributes if attribute.init], NoneTyp() )
def default(self, typ: Type) -> Type: if isinstance(typ, UnboundType): return AnyType(TypeOfAny.special_form) else: if state.strict_optional: return UninhabitedType() else: return NoneTyp()
def test_error_type(self): self.assert_meet(self.fx.err, self.fx.anyt, self.fx.err) # Meet against any type except dynamic results in ErrorType. for t in [self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), self.fx.void, self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, self.fx.err, self.fx.err)
def solve_constraints(vars: List[int], constraints: List[Constraint], basic: BasicTypes) -> List[Type]: """Solve type constraints. Return the best type(s) for type variables; each type can be None if the value of the variable could not be solved. If a variable has no constraints, arbitrarily pick NoneTyp as the value of the type variable. """ # Collect a list of constraints for each type variable. cmap = Dict[int, List[Constraint]]() for con in constraints: a = cmap.get(con.type_var, []) a.append(con) cmap[con.type_var] = a res = [] # type: List[Type] # Solve each type variable separately. for tvar in vars: bottom = None # type: Type top = None # type: Type # Process each contraint separely, and calculate the lower and upper # bounds based on constraints. Note that we assume that the constraint # targets do not have constraint references. for c in cmap.get(tvar, []): if c.op == SUPERTYPE_OF: if bottom is None: bottom = c.target else: bottom = join_types(bottom, c.target, basic) else: if top is None: top = c.target else: top = meet_types(top, c.target, basic) if isinstance(top, AnyType) or isinstance(bottom, AnyType): res.append(AnyType()) continue elif bottom is None: if top: candidate = top else: # No constraints for type variable -- type 'None' is the most specific type. candidate = NoneTyp() elif top is None: candidate = bottom elif is_subtype(bottom, top): candidate = bottom else: candidate = None if isinstance(candidate, ErrorType): res.append(None) else: res.append(candidate) return res
def test_none(self): self.assert_meet(NoneTyp(), NoneTyp(), NoneTyp()) self.assert_meet(NoneTyp(), self.fx.anyt, NoneTyp()) self.assert_meet(NoneTyp(), self.fx.void, self.fx.err) # Any type t joined with None results in None, unless t is any or # void. for t in [self.fx.a, self.fx.o, UnboundType('x'), self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, NoneTyp(), NoneTyp())
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 test_void(self): self.assert_join(self.fx.void, self.fx.void, self.fx.void) self.assert_join(self.fx.void, self.fx.anyt, self.fx.anyt) # Join of any other type against void results in ErrorType, since there # is no other meaningful result. for t in [self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_join(t, self.fx.void, self.fx.err)
def default(self, typ): if isinstance(typ, UnboundType): return AnyType() elif isinstance(typ, Void) or isinstance(typ, ErrorType): return ErrorType() else: if experiments.STRICT_OPTIONAL: return UninhabitedType() else: return NoneTyp()
def test_void(self): self.assert_meet(self.fx.void, self.fx.void, self.fx.void) self.assert_meet(self.fx.void, self.fx.anyt, self.fx.void) # Meet of any other type against void results in ErrorType, since there # is no meaningful valid result. for t in [self.fx.a, self.fx.o, UnboundType('x'), NoneTyp(), self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: self.assert_meet(t, self.fx.void, self.fx.err)
def test_dynamic_type(self): # Meet against dynamic type always results in dynamic. for t in [ self.fx.anyt, self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), self.fx.void, self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b) ]: self.assert_meet(t, self.fx.anyt, t)
def join_type_list(types: List[Type]) -> Type: if not types: # This is a little arbitrary but reasonable. Any empty tuple should be compatible # with all variable length tuples, and this makes it possible. A better approach # would be to use a special bottom type. return NoneTyp() joined = types[0] for t in types[1:]: joined = join_types(joined, t) return joined
def add_init_to_cls(ctx: ClassDefContext) -> None: if "__init__" not in ctx.cls.info.names: anytype = AnyType(TypeOfAny.special_form) var = Var("kwargs", anytype) kw_arg = Argument(variable=var, type_annotation=anytype, initializer=None, kind=ARG_STAR2) add_method(ctx, "__init__", [kw_arg], NoneTyp()) set_declarative(ctx.cls.info)
def test_any_type(self): # Join against 'Any' type always results in 'Any'. for t in [ self.fx.anyt, self.fx.a, self.fx.o, NoneTyp(), UnboundType('x'), self.fx.void, self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b) ]: self.assert_join(t, self.fx.anyt, self.fx.anyt)
def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance) -> TypeInfo: info = self.api.basic_new_typeinfo(name, base_type) info.is_newtype = True # Add __init__ method args = [Argument(Var('self'), NoneTyp(), None, ARG_POS), self.make_argument('item', old_type)] signature = CallableType( arg_types=[Instance(info, []), old_type], arg_kinds=[arg.kind for arg in args], arg_names=['self', 'item'], ret_type=NoneTyp(), fallback=self.api.named_type('__builtins__.function'), name=name) init_func = FuncDef('__init__', args, Block([]), typ=signature) init_func.info = info init_func._fullname = self.api.qualified_name(name) + '.__init__' info.names['__init__'] = SymbolTableNode(MDEF, init_func) return info
def proper_types_hook(ctx: FunctionContext) -> Type: """Check if this get_proper_types() call is not redundant.""" arg_types = ctx.arg_types[0] if arg_types: arg_type = arg_types[0] proper_type = get_proper_type_instance(ctx) item_type = UnionType.make_union([NoneTyp(), proper_type]) ok_type = ctx.api.named_generic_type('typing.Iterable', [item_type]) if is_proper_subtype(arg_type, ok_type): ctx.api.fail('Redundant call to get_proper_types()', ctx.context) return ctx.default_return_type
def handle_partial_attribute_type(typ: PartialType, is_lvalue: bool, msg: MessageBuilder, context: Context) -> Type: if typ.type is None: # 'None' partial type. It has a well-defined type -- 'None'. # In an lvalue context we want to preserver the knowledge of # it being a partial type. if not is_lvalue: return NoneTyp() return typ else: msg.fail(messages.NEED_ANNOTATION_FOR_VAR, context) return AnyType()
def handle_partial_attribute_type(typ: PartialType, is_lvalue: bool, msg: MessageBuilder, node: SymbolNode) -> Type: if typ.type is None: # 'None' partial type. It has a well-defined type -- 'None'. # In an lvalue context we want to preserver the knowledge of # it being a partial type. if not is_lvalue: return NoneTyp() return typ else: msg.need_annotation_for_var(node, node) return AnyType(TypeOfAny.from_error)
def meet_simple(s: Type, t: Type, default_right: bool = True) -> Type: if s == t: return s if isinstance(s, UnionType): return UnionType.make_simplified_union([meet_types(x, t) for x in s.items]) elif not is_overlapping_types(s, t, use_promotions=True): return NoneTyp() else: if default_right: return t else: return s
def proper_type_hook(ctx: FunctionContext) -> Type: """Check if this get_proper_type() call is not redundant.""" arg_types = ctx.arg_types[0] if arg_types: arg_type = get_proper_type(arg_types[0]) proper_type = get_proper_type_instance(ctx) if is_proper_subtype(arg_type, UnionType.make_union([NoneTyp(), proper_type])): # Minimize amount of spurious errors from overload machinery. # TODO: call the hook on the overload as a whole? if isinstance(arg_type, (UnionType, Instance)): ctx.api.fail('Redundant call to get_proper_type()', ctx.context) return ctx.default_return_type