def assert_simplified_union(self, original: List[Type], union: Type) -> None: assert_equal(make_simplified_union(original), union) assert_equal(make_simplified_union(list(reversed(original))), union)
def simplify_union(t: Type) -> ProperType: t = get_proper_type(t) if isinstance(t, UnionType): return make_simplified_union(t.items) return t
def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument: """Return this attribute as an argument to __init__.""" assert self.init init_type = self.init_type or 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_fully_qualified(self.converter.name, ctx.api.modules, raise_on_missing=False) 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: Optional[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 converter_type = get_proper_type(converter_type) 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: 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 = 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 visit_union_type(self, t: UnionType) -> ProperType: erased_items = [erase_type(item) for item in t.items] from mypy.typeops import make_simplified_union return make_simplified_union(erased_items)
def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type: """Type check descriptor access. Arguments: descriptor_type: The type of the descriptor attribute being accessed (the type of ``f`` in ``a.f`` when ``f`` is a descriptor). mx: The current member access context. Return: The return type of the appropriate ``__get__`` overload for the descriptor. """ instance_type = get_proper_type(mx.original_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(typ, mx) 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: mx.msg.fail( message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format( descriptor_type), mx.context) return AnyType(TypeOfAny.from_error) bound_method = analyze_decorator_or_funcbase_access( defn=dunder_get, itype=descriptor_type, info=descriptor_type.type, self_type=descriptor_type, name='__set__', mx=mx) 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 callable_name = mx.chk.expr_checker.method_fullname( descriptor_type, "__get__") dunder_get_type = mx.chk.expr_checker.transform_callee_type( callable_name, dunder_get_type, [ TempNode(instance_type, context=mx.context), TempNode(TypeType.make_normalized(owner_type), context=mx.context) ], [ARG_POS, ARG_POS], mx.context, object_type=descriptor_type, ) _, inferred_dunder_get_type = mx.chk.expr_checker.check_call( dunder_get_type, [ TempNode(instance_type, context=mx.context), TempNode(TypeType.make_normalized(owner_type), context=mx.context) ], [ARG_POS, ARG_POS], mx.context, object_type=descriptor_type, callable_name=callable_name) 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): mx.msg.fail( message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format( descriptor_type), mx.context) return AnyType(TypeOfAny.from_error) return inferred_dunder_get_type.ret_type
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 visit_union_type(self, t: UnionType) -> ProperType: # After substituting for type variables in t.items, # some of the resulting types might be subtypes of others. from mypy.typeops import make_simplified_union # asdf return make_simplified_union(self.expand_types(t.items), t.line, t.column)
def fixed_mapping_callback(ctx: FunctionContext) -> Type: """The callback to infer a better type for ``FixedMapping``. """ fallback = ctx.api.named_generic_type('typing_extensions._TypedDict', []) required_keys = set() items = OrderedDict() for idx, arg in enumerate(ctx.arg_types[0]): if isinstance(arg, AnyType): ctx.api.fail(( 'Argument {} was an "Any" which is not allowed as an' ' argument to FixedMapping' ).format(idx + 1), ctx.context) continue if isinstance(arg, Instance): typ = arg.type.fullname else: # pragma: no cover typ = '????' if typ not in ( 'cg_request_args.RequiredArgument', 'cg_request_args.OptionalArgument' ): ctx.api.fail(( 'Argument {} provided was of wrong type, expected' ' cg_request_args._RequiredArgument or' ' cg_request_args._OptionalArgument, but got {}.' ).format(idx + 1, typ), ctx.context) continue assert isinstance(arg, Instance) key_typevar = arg.args[1] if not isinstance(key_typevar, LiteralType): ctx.api.fail(( 'Second parameter of the argument should be a literal, this' ' was not the case for argument {}' ).format(idx + 1), ctx.context) continue key = key_typevar.value if not isinstance(key, str): ctx.api.fail(( 'Key should be of type string, but was of type {} for argument' ' {}.' ).format(type(key).__name__, idx + 1), ctx.context) continue if key in items: ctx.api.fail(( 'Key {!r} was already present, but given again as argument {}.' ).format(key, idx + 1), ctx.context) continue required_keys.add(key) value_type = arg.args[0] if typ == 'cg_request_args.OptionalArgument': value_type = make_simplified_union([ ctx.api.named_generic_type( 'cg_maybe.Just', [value_type], ), ctx.api.named_generic_type( 'cg_maybe._Nothing', [value_type], ), ]) items[key] = value_type assert isinstance(ctx.default_return_type, Instance) return ctx.default_return_type.copy_modified( args=[ TypedDictType(OrderedDict(items), required_keys, fallback), ] )