Ejemplo n.º 1
0
Archivo: meet.py Proyecto: ecprice/mypy
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.meet(t.items[i], self.s.items[i]))
         # TODO: What if the fallbacks are different?
         return TupleType(items, t.fallback)
     else:
         return self.default(self.s)
Ejemplo n.º 2
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.join(t.items[i], self.s.items[i]))
         fallback = join_instances(self.s.fallback, t.fallback)
         assert isinstance(fallback, Instance)
         return TupleType(items, fallback)
     else:
         return self.default(self.s)
Ejemplo n.º 3
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.join(t.items[i], self.s.items[i]))
         # join fallback types if they are different
         from typing import cast
         return TupleType(items, cast(Instance, join_instances(self.s.fallback, t.fallback)))
     else:
         return self.default(self.s)
Ejemplo n.º 4
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     if (isinstance(self.s, TupleType) and
             cast(TupleType, self.s).length() == t.length()):
         items = [] # type: List[Type]
         for i in range(t.length()):
             items.append(self.join(t.items[i],
                                    (cast(TupleType, self.s)).items[i]))
         return TupleType(items)
     else:
         return self.default(self.s)
Ejemplo n.º 5
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.meet(t.items[i], self.s.items[i]))
         # TODO: What if the fallbacks are different?
         return TupleType(items, t.fallback)
     # meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
     elif (isinstance(self.s, Instance) and
           self.s.type.fullname() == 'builtins.tuple' and self.s.args):
         return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items])
     else:
         return self.default(self.s)
Ejemplo n.º 6
0
Archivo: meet.py Proyecto: python/mypy
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.meet(t.items[i], self.s.items[i]))
         # TODO: What if the fallbacks are different?
         return TupleType(items, tuple_fallback(t))
     elif isinstance(self.s, Instance):
         # meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
         if self.s.type.fullname() == 'builtins.tuple' and self.s.args:
             return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items])
         elif is_proper_subtype(t, self.s):
             # A named tuple that inherits from a normal class
             return t
     return self.default(self.s)
Ejemplo n.º 7
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     return TupleType(
         self.translate_types(t.items),
         # TODO: This appears to be unsafe.
         cast(Any, t.fallback.accept(self)),
         t.line,
         t.column)
Ejemplo n.º 8
0
 def visit_tuple_type(self, t: TupleType) -> ProperType:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items: List[Type] = []
         for i in range(t.length()):
             items.append(self.meet(t.items[i], self.s.items[i]))
         # TODO: What if the fallbacks are different?
         return TupleType(items, tuple_fallback(t))
     elif isinstance(self.s, Instance):
         # meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
         if self.s.type.fullname == 'builtins.tuple' and self.s.args:
             return t.copy_modified(
                 items=[meet_types(it, self.s.args[0]) for it in t.items])
         elif is_proper_subtype(t, self.s):
             # A named tuple that inherits from a normal class
             return t
     return self.default(self.s)
Ejemplo n.º 9
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     # Types such as (t1, t2, ...) only allowed in assignment statements. They'll
     # generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.
     if t.implicit and not self.allow_tuple_literal:
         self.fail('Invalid tuple literal type', t)
         return AnyType()
     star_count = sum(1 for item in t.items if isinstance(item, StarType))
     if star_count > 1:
         self.fail('At most one star type allowed in a tuple', t)
         if t.implicit:
             return TupleType([AnyType() for _ in t.items],
                              self.named_type('builtins.tuple'), t.line)
         else:
             return AnyType()
     fallback = t.fallback if t.fallback else self.named_type(
         'builtins.tuple', [AnyType()])
     return TupleType(self.anal_array(t.items), fallback, t.line)
Ejemplo n.º 10
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.meet(t.items[i], self.s.items[i]))
         # TODO: What if the fallbacks are different?
         return TupleType(items, t.fallback)
     # meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
     elif (isinstance(self.s, Instance) and
           self.s.type.fullname() == 'builtins.tuple' and self.s.args):
         return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items])
     elif (isinstance(self.s, Instance) and t.fallback.type == self.s.type):
         # Uh oh, a broken named tuple type (https://github.com/python/mypy/issues/3016).
         # Do something reasonable until that bug is fixed.
         return t
     else:
         return self.default(self.s)
Ejemplo n.º 11
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     star_count = sum(1 for item in t.items if isinstance(item, StarType))
     if star_count > 1:
         self.fail('At most one star type allowed in a tuple', t)
         return AnyType()
     fallback = t.fallback if t.fallback else self.builtin_type(
         'builtins.tuple')
     return TupleType(self.anal_array(t.items), fallback, t.line)
Ejemplo n.º 12
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.meet(t.items[i], self.s.items[i]))
         # TODO: What if the fallbacks are different?
         return TupleType(items, t.fallback)
     # meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
     elif (isinstance(self.s, Instance) and
           self.s.type.fullname() == 'builtins.tuple' and self.s.args):
         return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items])
     elif (isinstance(self.s, Instance) and t.fallback.type == self.s.type):
         # Uh oh, a broken named tuple type (https://github.com/python/mypy/issues/3016).
         # Do something reasonable until that bug is fixed.
         return t
     else:
         return self.default(self.s)
Ejemplo n.º 13
0
 def visit_unbound_type(self, t: UnboundType) -> Type:
     sym = self.lookup(t.name, t)
     if sym is not None:
         if sym.kind == TVAR:
             if len(t.args) > 0:
                 self.fail(
                     'Type variable "{}" used with arguments'.format(
                         t.name), t)
             if t.repr:
                 rep = TypeVarRepr(t.repr.components[0])
             else:
                 rep = None
             values = cast(TypeVarExpr, sym.node).values
             return TypeVar(t.name, sym.tvar_id, values, False, t.line, rep)
         elif sym.node.fullname() == 'builtins.None':
             return Void()
         elif sym.node.fullname() == 'typing.Any':
             return AnyType()
         elif sym.node.fullname() == 'typing.Tuple':
             return TupleType(self.anal_array(t.args))
         elif sym.node.fullname() == 'typing.Union':
             return UnionType(self.anal_array(t.args))
         elif sym.node.fullname() == 'typing.Function':
             return self.analyze_function_type(t)
         elif not isinstance(sym.node, TypeInfo):
             name = sym.fullname
             if name is None:
                 name = sym.node.name()
             if sym.node in self.stored_vars:
                 return self.stored_vars[sym.node]
             self.fail('Invalid type "{}"'.format(name), t)
             return t
         info = cast(TypeInfo, sym.node)
         if len(t.args) > 0 and info.fullname() == 'builtins.tuple':
             return TupleType(self.anal_array(t.args), t.line, t.repr)
         else:
             # Analyze arguments and construct Instance type. The
             # number of type arguments and their values are
             # checked only later, since we do not always know the
             # valid count at this point. Thus we may construct an
             # Instance with an invalid number of type arguments.
             return Instance(info, self.anal_array(t.args), t.line, t.repr)
     else:
         return t
Ejemplo n.º 14
0
def make_oneoff_named_tuple(api: TypeChecker, name: str,
                            fields: 'OrderedDict[str, MypyType]') -> TupleType:
    current_module = get_current_module(api)
    namedtuple_info = add_new_class_for_module(
        current_module,
        name,
        bases=[api.named_generic_type('typing.NamedTuple', [])],
        fields=fields)
    return TupleType(list(fields.values()),
                     fallback=Instance(namedtuple_info, []))
Ejemplo n.º 15
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     # Types such as (t1, t2, ...) only allowed in assignment statements. They'll
     # generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.
     if t.implicit and not self.allow_tuple_literal:
         self.fail('Invalid tuple literal type', t)
         if len(t.items) == 1:
             self.note_func('Suggestion: Is there a spurious trailing comma?', t)
         return AnyType(TypeOfAny.from_error)
     star_count = sum(1 for item in t.items if isinstance(item, StarType))
     if star_count > 1:
         self.fail('At most one star type allowed in a tuple', t)
         if t.implicit:
             return TupleType([AnyType(TypeOfAny.from_error) for _ in t.items],
                              self.named_type('builtins.tuple'),
                              t.line)
         else:
             return AnyType(TypeOfAny.from_error)
     any_type = AnyType(TypeOfAny.special_form)
     fallback = t.fallback if t.fallback else self.named_type('builtins.tuple', [any_type])
     return TupleType(self.anal_array(t.items), fallback, t.line)
Ejemplo n.º 16
0
 def visit_tuple_type(self, t: TupleType) -> ProperType:
     # When given two fixed-length tuples:
     # * If they have the same length, join their subtypes item-wise:
     #   Tuple[int, bool] + Tuple[bool, bool] becomes Tuple[int, bool]
     #
     # Otherwise, `t` is a fixed-length tuple but `self.s` is NOT:
     # * Joining with a variadic tuple returns variadic tuple:
     #   Tuple[int, bool] + Tuple[bool, ...] becomes Tuple[int, ...]
     # * Joining with any Sequence also returns a Sequence:
     #   Tuple[int, bool] + List[bool] becomes Sequence[int]
     if isinstance(self.s, TupleType) and self.s.length() == t.length():
         items = []  # type: List[Type]
         for i in range(t.length()):
             items.append(self.join(t.items[i], self.s.items[i]))
         fallback = join_instances(mypy.typeops.tuple_fallback(self.s),
                                   mypy.typeops.tuple_fallback(t))
         assert isinstance(fallback, Instance)
         return TupleType(items, fallback)
     else:
         return join_types(self.s, mypy.typeops.tuple_fallback(t))
Ejemplo n.º 17
0
def session_hook(ctx: MethodContext) -> Type:
    if not isinstance(ctx.default_return_type, Instance):
        return ctx.default_return_type

    if ctx.default_return_type.type.fullname(
    ) != 'typed_sqlalchemy.session.QueryPlaceholder':
        return ctx.default_return_type

    assert isinstance(ctx.type, Instance)
    assert ctx.type.type.fullname() == 'typed_sqlalchemy.session.Session'

    base_model_type = ctx.type.args[0]

    # We hijack these from the generic return value in order to construct them.
    query_type_info = ctx.default_return_type.args[0].type
    singular_query_type_info = ctx.default_return_type.args[1].type
    typed_column_type_info = ctx.default_return_type.args[2].type

    # For now, we support exactly two arg types: typed columns and models.
    # We record whether we found a model because if we only have one non-model
    # then we are still a tuple, but a single model becomes a singular query.
    has_model = False
    return_types = []
    for arg_type in ctx.arg_types[0]:
        # I'm kind of surprised that its a CallableType
        if isinstance(arg_type, CallableType) and is_subtype(
                arg_type.ret_type, base_model_type):
            has_model = True
            return_types.append(arg_type.ret_type)

        # Case 2: TypedColumn
        elif isinstance(arg_type, Instance) and arg_type.type.fullname(
        ) == typed_column_type_info.fullname():
            return_types.append(arg_type.args[1])

    if has_model and len(return_types) == 1:
        model_type = return_types[0]
        primary_key_type = model_type.type.bases[0].args[0]

        return Instance(
            singular_query_type_info,
            # Base model, return type, primary key
            [base_model_type, return_types[0], primary_key_type],
        )
    else:
        fallback = ctx.api.named_generic_type('builtins.tuple', [])
        return Instance(
            query_type_info,
            # Base model, return type tuple
            [base_model_type,
             TupleType(return_types, fallback)],
        )
Ejemplo n.º 18
0
def make_named_tuple(api: 'TypeChecker', fields: 'OrderedDict[str, Type]', name: str) -> Type:
    if not fields:
        # No fields specified, so fallback to a subclass of NamedTuple that allows
        # __getattr__ / __setattr__ for any attribute name.
        fallback = api.named_generic_type('django._NamedTupleAnyAttr', [])
    else:
        fallback = build_class_with_annotated_fields(
            api=api,
            base=api.named_generic_type('typing.NamedTuple', []),
            fields=fields,
            name=name
        )
    return TupleType(list(fields.values()), fallback=fallback)
Ejemplo n.º 19
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     # Types such as (t1, t2, ...) only allowed in assignment statements. They'll
     # generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.
     if t.implicit and not self.allow_tuple_literal:
         self.fail(errorcode.INVALID_TUPLE_LITERAL_TYPE(), t)
         if len(t.items) == 1:
             self.note_func(
                 errorcode.SUGGESTION_IS_THERE_SPURIOUS_TRAILING_COMMA(), t)
         return AnyType(TypeOfAny.from_error)
     star_count = sum(1 for item in t.items if isinstance(item, StarType))
     if star_count > 1:
         self.fail(errorcode.AT_MOST_ONE_STAR_TYPE_ALLOWED_IN_TUPLE(), t)
         if t.implicit:
             return TupleType(
                 [AnyType(TypeOfAny.from_error) for _ in t.items],
                 self.named_type('builtins.tuple'), t.line)
         else:
             return AnyType(TypeOfAny.from_error)
     any_type = AnyType(TypeOfAny.special_form)
     fallback = t.fallback if t.fallback else self.named_type(
         'builtins.tuple', [any_type])
     return TupleType(self.anal_array(t.items), fallback, t.line)
Ejemplo n.º 20
0
    def analyze_type_with_type_info(self, info: TypeInfo, args: List[Type], ctx: Context) -> Type:
        """Bind unbound type when were able to find target TypeInfo.

        This handles simple cases like 'int', 'modname.UserClass[str]', etc.
        """
        if len(args) > 0 and info.fullname() == 'builtins.tuple':
            fallback = Instance(info, [AnyType(TypeOfAny.special_form)], ctx.line)
            return TupleType(self.anal_array(args), fallback, ctx.line)
        # Analyze arguments and (usually) construct Instance type. The
        # number of type arguments and their values are
        # checked only later, since we do not always know the
        # valid count at this point. Thus we may construct an
        # Instance with an invalid number of type arguments.
        instance = Instance(info, self.anal_array(args), ctx.line, ctx.column)
        # Check type argument count.
        if len(instance.args) != len(info.type_vars) and not self.defining_alias:
            fix_instance(instance, self.fail)
        if not args and self.options.disallow_any_generics and not self.defining_alias:
            # We report/patch invalid built-in instances already during second pass.
            # This is done to avoid storing additional state on instances.
            # All other (including user defined) generics will be patched/reported
            # in the third pass.
            if not self.is_typeshed_stub and info.fullname() in nongen_builtins:
                alternative = nongen_builtins[info.fullname()]
                self.fail(message_registry.IMPLICIT_GENERIC_ANY_BUILTIN.format(alternative), ctx)
                any_type = AnyType(TypeOfAny.from_error, line=ctx.line)
            else:
                any_type = AnyType(TypeOfAny.from_omitted_generics, line=ctx.line)
            instance.args = [any_type] * len(info.type_vars)

        tup = info.tuple_type
        if tup is not None:
            # The class has a Tuple[...] base class so it will be
            # represented as a tuple type.
            if args:
                self.fail('Generic tuple types not supported', ctx)
                return AnyType(TypeOfAny.from_error)
            return tup.copy_modified(items=self.anal_array(tup.items),
                                     fallback=instance)
        td = info.typeddict_type
        if td is not None:
            # The class has a TypedDict[...] base class so it will be
            # represented as a typeddict type.
            if args:
                self.fail('Generic TypedDict types not supported', ctx)
                return AnyType(TypeOfAny.from_error)
            # Create a named TypedDictType
            return td.copy_modified(item_types=self.anal_array(list(td.items.values())),
                                    fallback=instance)
        return instance
Ejemplo n.º 21
0
def make_oneoff_named_tuple(
        api: TypeChecker,
        name: str,
        fields: "OrderedDict[str, MypyType]",
        extra_bases: Optional[List[Instance]] = None) -> TupleType:
    current_module = get_current_module(api)
    if extra_bases is None:
        extra_bases = []
    namedtuple_info = add_new_class_for_module(
        current_module,
        name,
        bases=[api.named_generic_type("typing.NamedTuple", [])] + extra_bases,
        fields=fields)
    return TupleType(list(fields.values()),
                     fallback=Instance(namedtuple_info, []))
Ejemplo n.º 22
0
 def parse_types(self) -> Type:
     parens = False
     if self.current_token_str() == '(':
         self.skip()
         parens = True
     type = self.parse_type()
     if self.current_token_str() == ',':
         items = [type]
         while self.current_token_str() == ',':
             self.skip()
             items.append(self.parse_type())
         type = TupleType(items)
     if parens:
         self.expect(')')
     return type
Ejemplo n.º 23
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     # Types such as (t1, t2, ...) only allowed in assignment statements. They'll
     # generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.
     if t.implicit and not self.allow_tuple_literal:
         self.fail('Syntax error in type annotation', t)
         if len(t.items) == 1:
             self.note_func('Suggestion: Is there a spurious trailing comma?', t)
         else:
             self.note_func('Suggestion: Use Tuple[T1, ..., Tn] instead of (T1, ..., Tn)', t)
         return AnyType(TypeOfAny.from_error)
     star_count = sum(1 for item in t.items if isinstance(item, StarType))
     if star_count > 1:
         self.fail('At most one star type allowed in a tuple', t)
         if t.implicit:
             return TupleType([AnyType(TypeOfAny.from_error) for _ in t.items],
                              self.named_type('builtins.tuple'),
                              t.line)
         else:
             return AnyType(TypeOfAny.from_error)
     any_type = AnyType(TypeOfAny.special_form)
     # If the fallback isn't filled in yet, its type will be the falsey FakeInfo
     fallback = (t.partial_fallback if t.partial_fallback.type
                 else self.named_type('builtins.tuple', [any_type]))
     return TupleType(self.anal_array(t.items), fallback, t.line)
Ejemplo n.º 24
0
def session_query_hook(ctx: MethodContext) -> Type:
    """
    Turns session.query(...) into typed Query.

    Examples:

        session.query(User) -> Query[User]
        session.query(User, Order) -> Query[Tuple[User, Order]]
        session.query(User, User.id) -> Query[Tuple[User, int]]
        session.query(User.id) -> Query[Tuple[int]]
    """
    # TODO take a look at Session.query_cls? Do we have to do this with generics?

    cnt_entities = 0

    def map_arg(arg: Type) -> Type:
        nonlocal cnt_entities
        # A model class (well, in this case a callable constructor)
        # Example:
        # session.query(Employee) -> Query[Employee]
        if isinstance(arg, CallableType) and arg.is_type_obj():
            cnt_entities += 1
            return arg.ret_type

        # Example:
        # session.query(Employee.id, ...) -> Query[int, ...]
        if isinstance(arg, Instance) and fullname(arg.type) == COLUMN_NAME:
            assert (len(arg.args) == 1
                    ), "Column[...] should have only one generic argument"
            return arg.args[0]

        return AnyType(TypeOfAny.implementation_artifact)

    # take positional arguments and map them
    args = [map_arg(arg) for arg in ctx.arg_types[0]]

    if len(args) == 1 and (cnt_entities == 1 or isinstance(args[0], AnyType)):
        # when there is a single class passed as an argument
        # or when we can't detect what the single argument is (Any)
        final_arg = args[0]
    else:
        fallback = ctx.api.named_type(
            "sqlalchemy.util.KeyedTuple")  # type: ignore
        final_arg = TupleType(args, fallback, implicit=True)

    return ctx.api.named_generic_type("sqlalchemy.orm.Query", [final_arg])
Ejemplo n.º 25
0
def _add_match_args(ctx: 'mypy.plugin.ClassDefContext',
                    attributes: List[Attribute]) -> None:
    if ('__match_args__' not in ctx.cls.info.names
            or ctx.cls.info.names['__match_args__'].plugin_generated):
        str_type = ctx.api.named_type('builtins.str')
        match_args = TupleType(
            [
                str_type.copy_modified(last_known_value=LiteralType(
                    attr.name, fallback=str_type), )
                for attr in attributes if not attr.kw_only and attr.init
            ],
            fallback=ctx.api.named_type('builtins.tuple'),
        )
        add_attribute_to_class(
            api=ctx.api,
            cls=ctx.cls,
            name='__match_args__',
            typ=match_args,
        )
Ejemplo n.º 26
0
    def parse_types(self) -> Type:
        """ Parse either a single type or a comma separated
        list of types as a tuple type. In the latter case, a
        trailing comma is needed when the list contains only
        a single type (and optional otherwise).

        int   ->   int
        int,  ->   TupleType[int]
        int, int, int  ->  TupleType[int, int, int]
        """
        type = self.parse_type()
        if self.current_token_str() == ',':
            items = [type]
            while self.current_token_str() == ',':
                self.skip()
                if self.current_token_str() == ')':
                    break
                items.append(self.parse_type())
            type = TupleType(items, None, type.line, implicit=True)
        return type
Ejemplo n.º 27
0
def _add_attrs_magic_attribute(ctx: 'mypy.plugin.ClassDefContext',
                               raw_attr_types: 'List[Optional[Type]]') -> None:
    attr_name = '__attrs_attrs__'
    any_type = AnyType(TypeOfAny.explicit)
    attributes_types: 'List[Type]' = [
        ctx.api.named_type_or_none('attr.Attribute', [attr_type or any_type])
        or any_type for attr_type in raw_attr_types
    ]
    fallback_type = ctx.api.named_type('builtins.tuple', [
        ctx.api.named_type_or_none('attr.Attribute', [any_type]) or any_type,
    ])
    var = Var(name=attr_name,
              type=TupleType(attributes_types, fallback=fallback_type))
    var.info = ctx.cls.info
    var._fullname = ctx.cls.info.fullname + '.' + attr_name
    ctx.cls.info.names[attr_name] = SymbolTableNode(
        kind=MDEF,
        node=var,
        plugin_generated=True,
    )
Ejemplo n.º 28
0
def session_query_hook(ctx: MethodContext) -> Type:
    """
    Turns session.query(...) into typed Query.

    Examples:

        session.query(User) -> Query[User]
        session.query(User, Order) -> Query[Tuple[User, Order]]
        session.query(User, User.id) -> Query[Tuple[User, int]]
    """

    # TODO take a look at Session.query_cls? Do we have to do this with generics?

    def map_arg(arg: Type) -> Type:
        # A model class (well, in this case a callable constructor)
        # Example:
        # session.query(Employee) -> Query[Employee]
        if isinstance(arg, CallableType) and arg.is_type_obj():
            return arg.ret_type

        # Example:
        # session.query(Employee.id) -> Query[int]
        if isinstance(arg, Instance) and arg.type.fullname() == COLUMN_NAME:
            assert len(
                arg.args
            ) == 1, "Column[...] should have only one generic argument"
            return arg.args[0]

        return AnyType(TypeOfAny.implementation_artifact)

    # take positional arguments and map them
    args = [map_arg(arg) for arg in ctx.arg_types[0]]

    if len(args) == 1:
        final_arg = args[0]
    else:
        fallback = ctx.api.named_type(
            'sqlalchemy.util._collections.AbstractKeyedTuple')
        final_arg = TupleType(args, fallback, implicit=True)

    return ctx.default_return_type.copy_modified(args=[final_arg])
Ejemplo n.º 29
0
    def visit_instance(self, t: Instance, from_fallback: bool = False) -> Type:
        """This visitor method tracks situations like this:

               x: A  # When analyzing this type we will get an Instance from SemanticAnalyzerPass1.
                     # Now we need to update this to actual analyzed TupleType.
               class A(NamedTuple):
                   attr: str

        If from_fallback is True, then we always return an Instance type. This is needed
        since TupleType and TypedDictType fallbacks are always instances.
        """
        info = t.type
        # Special case, analyzed bases transformed the type into TupleType.
        if info.tuple_type and not from_fallback:
            items = [it.accept(self) for it in info.tuple_type.items]
            info.tuple_type.items = items
            return TupleType(items, Instance(info, []))
        # Update forward Instances to corresponding analyzed NamedTuples.
        if info.replaced and info.replaced.tuple_type:
            tp = info.replaced.tuple_type
            if self.check_recursion(tp):
                # The key idea is that when we recursively return to a type already traversed,
                # then we break the cycle and put AnyType as a leaf.
                return AnyType(TypeOfAny.from_error)
            return tp.copy_modified(
                fallback=Instance(info.replaced, [], line=t.line)).accept(self)
        # Same as above but for TypedDicts.
        if info.replaced and info.replaced.typeddict_type:
            td = info.replaced.typeddict_type
            if self.check_recursion(td):
                # We also break the cycles for TypedDicts as explained above for NamedTuples.
                return AnyType(TypeOfAny.from_error)
            return td.copy_modified(
                fallback=Instance(info.replaced, [], line=t.line)).accept(self)
        if self.check_recursion(t):
            # We also need to break a potential cycle with normal (non-synthetic) instance types.
            return Instance(t.type, [AnyType(TypeOfAny.from_error)] *
                            len(t.type.defn.type_vars),
                            line=t.line)
        return super().visit_instance(t)
Ejemplo n.º 30
0
    def visit_tuple_type(self, t: TupleType) -> Type:
        items = []
        for item in t.items:
            proper_item = get_proper_type(item)
            if isinstance(proper_item, UnpackType):
                unpacked_items = self.expand_unpack(proper_item)
                if unpacked_items is None:
                    # TODO: better error, something like tuple of unknown?
                    return UninhabitedType()
                elif isinstance(unpacked_items, Instance):
                    if len(t.items) == 1:
                        return unpacked_items
                    else:
                        assert False, "Invalid unpack of variable length tuple"
                elif isinstance(unpacked_items, AnyType):
                    return unpacked_items
                else:
                    items.extend(unpacked_items)
            else:
                items.append(proper_item.accept(self))

        return t.copy_modified(items=items)
Ejemplo n.º 31
0
def mutate_typeclass_instance_def(
    instance: Instance,
    *,
    passed_types: List[MypyType],
    typeclass: Instance,
    ctx: Union[MethodContext, FunctionContext],
) -> None:
    """
    Mutates ``TypeClassInstanceDef`` args.

    That's where we fill their values.
    Why? Because we need all types from ``some.instance()`` call.
    Including ``is_protocol`` for later checks.
    """
    tuple_type = TupleType(
        # We now store passed arg types in a single tuple:
        passed_types,
        fallback=ctx.api.named_type('builtins.tuple'),  # type: ignore
    )

    instance.args = (
        tuple_type,  # Passed runtime types, like str in `@some.instance(str)`
        typeclass,  # `_TypeClass` instance itself
    )
Ejemplo n.º 32
0
def _add_attrs_magic_attribute(
        ctx: 'mypy.plugin.ClassDefContext',
        attrs: 'List[Tuple[str, Optional[Type]]]') -> None:
    any_type = AnyType(TypeOfAny.explicit)
    attributes_types: 'List[Type]' = [
        ctx.api.named_type_or_none('attr.Attribute', [attr_type or any_type])
        or any_type for _, attr_type in attrs
    ]
    fallback_type = ctx.api.named_type('builtins.tuple', [
        ctx.api.named_type_or_none('attr.Attribute', [any_type]) or any_type,
    ])

    ti = ctx.api.basic_new_typeinfo(MAGIC_ATTR_CLS_NAME, fallback_type, 0)
    ti.is_named_tuple = True
    for (name, _), attr_type in zip(attrs, attributes_types):
        var = Var(name, attr_type)
        var.is_property = True
        proper_type = get_proper_type(attr_type)
        if isinstance(proper_type, Instance):
            var.info = proper_type.type
        ti.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True)
    attributes_type = Instance(ti, [])

    # TODO: refactor using `add_attribute_to_class`
    var = Var(name=MAGIC_ATTR_NAME,
              type=TupleType(attributes_types, fallback=attributes_type))
    var.info = ctx.cls.info
    var.is_classvar = True
    var._fullname = f"{ctx.cls.fullname}.{MAGIC_ATTR_CLS_NAME}"
    var.allow_incompatible_override = True
    ctx.cls.info.names[MAGIC_ATTR_NAME] = SymbolTableNode(
        kind=MDEF,
        node=var,
        plugin_generated=True,
        no_serialize=True,
    )
Ejemplo n.º 33
0
 def tuple_type(self, items: List[Type]) -> TupleType:
     any_type = AnyType(TypeOfAny.special_form)
     return TupleType(items,
                      fallback=self.named_type('builtins.tuple',
                                               [any_type]))
Ejemplo n.º 34
0
 def visit_unbound_type(self, t: UnboundType) -> Type:
     if t.optional:
         t.optional = False
         # We don't need to worry about double-wrapping Optionals or
         # wrapping Anys: Union simplification will take care of that.
         return make_optional_type(self.visit_unbound_type(t))
     sym = self.lookup(t.name, t,
                       suppress_errors=self.third_pass)  # type: ignore
     if sym is not None:
         if sym.node is None:
             # UNBOUND_IMPORTED can happen if an unknown name was imported.
             if sym.kind != UNBOUND_IMPORTED:
                 self.fail(errorcode.INTERNAL_ERROR_NODE_IS_NONE(sym.kind),
                           t)
             return AnyType(TypeOfAny.special_form)
         fullname = sym.node.fullname()
         hook = self.plugin.get_type_analyze_hook(fullname)
         if hook:
             return hook(AnalyzeTypeContext(t, t, self))
         if (fullname in nongen_builtins and t.args and not sym.normalized
                 and not self.allow_unnormalized):
             self.fail(errorcode.NO_SUBSCRIPT_BUILTIN_ALIAS(fullname), t)
         if self.tvar_scope:
             tvar_def = self.tvar_scope.get_binding(sym)
         else:
             tvar_def = None
         if self.warn_bound_tvar and sym.kind == TVAR and tvar_def is not None:
             self.fail(
                 errorcode.
                 CANNOT_USE_BOUND_TYPE_VAR_TO_DEFINE_GENERIC_ALIAS(t.name),
                 t)
             return AnyType(TypeOfAny.from_error)
         elif sym.kind == TVAR and tvar_def is not None:
             if len(t.args) > 0:
                 self.fail(errorcode.TYPE_VAR_USED_WITH_ARG(t.name), t)
             return TypeVarType(tvar_def, t.line)
         elif fullname == 'builtins.None':
             return NoneTyp()
         elif fullname == 'typing.Any' or fullname == 'builtins.Any':
             return AnyType(TypeOfAny.explicit)
         elif fullname == 'typing.Tuple':
             if len(t.args) == 0 and not t.empty_tuple_index:
                 # Bare 'Tuple' is same as 'tuple'
                 if self.options.disallow_any_generics and not self.is_typeshed_stub:
                     self.fail(errorcode.BARE_GENERIC(), t)
                 typ = self.named_type('builtins.tuple',
                                       line=t.line,
                                       column=t.column)
                 typ.from_generic_builtin = True
                 return typ
             if len(t.args) == 2 and isinstance(t.args[1], EllipsisType):
                 # Tuple[T, ...] (uniform, variable-length tuple)
                 instance = self.named_type('builtins.tuple',
                                            [self.anal_type(t.args[0])])
                 instance.line = t.line
                 return instance
             return self.tuple_type(self.anal_array(t.args))
         elif fullname == 'typing.Union':
             items = self.anal_array(t.args)
             return UnionType.make_union(items)
         elif fullname == 'typing.Optional':
             if len(t.args) != 1:
                 self.fail(errorcode.OPTIONAL_MUST_HAVE_ONE_ARGUMENT(), t)
                 return AnyType(TypeOfAny.from_error)
             item = self.anal_type(t.args[0])
             return make_optional_type(item)
         elif fullname == 'typing.Callable':
             return self.analyze_callable_type(t)
         elif fullname == 'typing.Type':
             if len(t.args) == 0:
                 any_type = AnyType(TypeOfAny.from_omitted_generics,
                                    line=t.line,
                                    column=t.column)
                 return TypeType(any_type, line=t.line, column=t.column)
             if len(t.args) != 1:
                 self.fail(errorcode.TYPE_MUST_HAVE_EXACTLY_ONE_TYPE(), t)
             item = self.anal_type(t.args[0])
             return TypeType.make_normalized(item, line=t.line)
         elif fullname == 'typing.ClassVar':
             if self.nesting_level > 0:
                 self.fail(
                     errorcode.INVALID_TYPE_CLASSVAR_NESTED_INSIDE_TYPE(),
                     t)
             if len(t.args) == 0:
                 return AnyType(TypeOfAny.from_omitted_generics,
                                line=t.line,
                                column=t.column)
             if len(t.args) != 1:
                 self.fail(
                     errorcode.CLASS_VAR_MUST_HAVE_AT_MOST_ONE_TYPE_ARG(),
                     t)
                 return AnyType(TypeOfAny.from_error)
             item = self.anal_type(t.args[0])
             if isinstance(item, TypeVarType) or get_type_vars(item):
                 self.fail(errorcode.CLASSVAR_CANNOT_BE_GENERIC(), t)
                 return AnyType(TypeOfAny.from_error)
             return item
         elif fullname in ('mypy_extensions.NoReturn', 'typing.NoReturn'):
             return UninhabitedType(is_noreturn=True)
         elif sym.kind == TYPE_ALIAS:
             override = sym.type_override
             all_vars = sym.alias_tvars
             assert override is not None
             an_args = self.anal_array(t.args)
             if all_vars is not None:
                 exp_len = len(all_vars)
             else:
                 exp_len = 0
             act_len = len(an_args)
             if exp_len > 0 and act_len == 0:
                 # Interpret bare Alias same as normal generic, i.e., Alias[Any, Any, ...]
                 assert all_vars is not None
                 return set_any_tvars(override, all_vars, t.line, t.column)
             if exp_len == 0 and act_len == 0:
                 return override
             if act_len != exp_len:
                 self.fail(
                     errorcode.BAD_NUMBER_ARGUMENT_FOR_TYPEALIAS(
                         exp_len, act_len), t)
                 return set_any_tvars(override,
                                      all_vars or [],
                                      t.line,
                                      t.column,
                                      implicit=False)
             assert all_vars is not None
             return replace_alias_tvars(override, all_vars, an_args, t.line,
                                        t.column)
         elif not isinstance(sym.node, TypeInfo):
             name = sym.fullname
             if name is None:
                 name = sym.node.name()
             if isinstance(sym.node, Var) and isinstance(
                     sym.node.type, AnyType):
                 # Something with an Any type -- make it an alias for Any in a type
                 # context. This is slightly problematic as it allows using the type 'Any'
                 # as a base class -- however, this will fail soon at runtime so the problem
                 # is pretty minor.
                 return AnyType(TypeOfAny.from_unimported_type)
             # Allow unbound type variables when defining an alias
             if not (self.aliasing and sym.kind == TVAR and
                     (not self.tvar_scope
                      or self.tvar_scope.get_binding(sym) is None)):
                 if (not self.third_pass and not self.in_dynamic_func
                         and not (isinstance(sym.node, (FuncDef, Decorator))
                                  or isinstance(sym.node, Var)
                                  and sym.node.is_ready)
                         and not (sym.kind == TVAR and tvar_def is None)):
                     if t.args and not self.global_scope:
                         self.fail(
                             errorcode.UNSUPPORTED_FORWARD_REFERENCE(
                                 t.name), t)
                         return AnyType(TypeOfAny.from_error)
                     return ForwardRef(t)
                 self.fail(errorcode.INVALID_TYPE_X(name), t)
                 if self.third_pass and sym.kind == TVAR:
                     self.note_func(
                         errorcode.FORWARD_REERENCES_TO_TYPE_VAR_PROHIBITED(
                         ), t)
             return t
         info = sym.node  # type: TypeInfo
         if len(t.args) > 0 and info.fullname() == 'builtins.tuple':
             fallback = Instance(info, [AnyType(TypeOfAny.special_form)],
                                 t.line)
             return TupleType(self.anal_array(t.args), fallback, t.line)
         else:
             # Analyze arguments and construct Instance type. The
             # number of type arguments and their values are
             # checked only later, since we do not always know the
             # valid count at this point. Thus we may construct an
             # Instance with an invalid number of type arguments.
             instance = Instance(info, self.anal_array(t.args), t.line,
                                 t.column)
             instance.from_generic_builtin = sym.normalized
             tup = info.tuple_type
             if tup is not None:
                 # The class has a Tuple[...] base class so it will be
                 # represented as a tuple type.
                 if t.args:
                     self.fail(
                         errorcode.GENERIC_TUPLE_TYPES_NOT_SUPPORTED(), t)
                     return AnyType(TypeOfAny.from_error)
                 return tup.copy_modified(items=self.anal_array(tup.items),
                                          fallback=instance)
             td = info.typeddict_type
             if td is not None:
                 # The class has a TypedDict[...] base class so it will be
                 # represented as a typeddict type.
                 if t.args:
                     self.fail(
                         errorcode.GENERIC_TYPEDDICT_TYPES_NOT_SUPPORTED(),
                         t)
                     return AnyType(TypeOfAny.from_error)
                 # Create a named TypedDictType
                 return td.copy_modified(item_types=self.anal_array(
                     list(td.items.values())),
                                         fallback=instance)
             return instance
     else:
         if self.third_pass:
             self.fail(errorcode.INVALID_TYPE_X(t.name), t)
             return AnyType(TypeOfAny.from_error)
         return AnyType(TypeOfAny.special_form)
Ejemplo n.º 35
0
    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
Ejemplo n.º 36
0
 def visit_Tuple(self, n: ast35.Tuple) -> Type:
     return TupleType(self.visit_list(n.elts), None, implicit=True, line=self.line)
Ejemplo n.º 37
0
def make_tuple(api: "TypeChecker", fields: List[MypyType]) -> TupleType:
    # fallback for tuples is any builtins.tuple instance
    fallback = api.named_generic_type("builtins.tuple",
                                      [AnyType(TypeOfAny.special_form)])
    return TupleType(fields, fallback=fallback)
Ejemplo n.º 38
0
 def visit_tuple_type(self, t: TupleType) -> Type:
     return t.copy_modified(items=self.expand_types(t.items))