Esempio n. 1
0
def get_related_manager_type_from_metadata(model_info: TypeInfo, related_manager_name: str,
                                           api: CheckerPluginInterface) -> Optional[Instance]:
    related_manager_metadata = get_related_managers_metadata(model_info)
    if not related_manager_metadata:
        return None

    if related_manager_name not in related_manager_metadata:
        return None

    manager_class_name = related_manager_metadata[related_manager_name]['manager']
    of = related_manager_metadata[related_manager_name]['of']
    of_types = []
    for of_type_name in of:
        if of_type_name == 'any':
            of_types.append(AnyType(TypeOfAny.implementation_artifact))
        else:
            try:
                of_type = api.named_generic_type(of_type_name, [])
            except AssertionError:
                # Internal error: attempted lookup of unknown name
                of_type = AnyType(TypeOfAny.implementation_artifact)

            of_types.append(of_type)

    return api.named_generic_type(manager_class_name, of_types)
Esempio n. 2
0
def _analyze_open_signature(
    arg_types: List[List[Type]],
    args: List[List[Expression]],
    mode_arg_index: int,
    default_return_type: Type,
    api: CheckerPluginInterface,
) -> Type:
    """A helper for analyzing any function that has approximately
    the same signature as the builtin 'open(...)' function.

    Currently, the only thing the caller can customize is the index
    of the 'mode' argument. If the mode argument is omitted or is a
    string literal, we refine the return type to either 'TextIO' or
    'BinaryIO' as appropriate.
    """
    mode = None
    if not arg_types or len(arg_types[mode_arg_index]) != 1:
        mode = 'r'
    else:
        mode_expr = args[mode_arg_index][0]
        if isinstance(mode_expr, StrExpr):
            mode = mode_expr.value
    if mode is not None:
        assert isinstance(default_return_type, Instance)  # type: ignore
        if 'b' in mode:
            return api.named_generic_type('typing.BinaryIO', [])
        else:
            return api.named_generic_type('typing.TextIO', [])
    return default_return_type
Esempio n. 3
0
def make_typeddict(api: CheckerPluginInterface,
                   fields: "OrderedDict[str, MypyType]",
                   required_keys: Set[str]) -> TypedDictType:
    object_type = api.named_generic_type("mypy_extensions._TypedDict", [])
    typed_dict_type = TypedDictType(fields,
                                    required_keys=required_keys,
                                    fallback=object_type)
    return typed_dict_type
Esempio n. 4
0
def _str_to_int(api: CheckerPluginInterface, typ: Type) -> Type:
    if isinstance(typ, Instance):
        if typ.type.fullname() == 'builtins.str':
            return api.named_generic_type('builtins.int', [])
        elif typ.args:
            return typ.copy_modified(args=[_str_to_int(api, t) for t in typ.args])

    return typ
Esempio n. 5
0
def _float_to_int(api: CheckerPluginInterface, typ: Type) -> Type:
    if isinstance(typ, Instance):
        if typ.type.fullname() == 'builtins.float':
            return api.named_generic_type('builtins.int', [])
        elif typ.args:
            return typ.copy_modified(
                args=[_float_to_int(api, t) for t in typ.args])
    return typ
Esempio n. 6
0
def _build_vals_dict(typ: Instance,
                     api: CheckerPluginInterface) -> "OrderedDict[str, Type]":
    return OrderedDict({
        name:
        (api.named_generic_type("odoo.models._RecordId", [stn.type])
         if isinstance(stn.type, Instance)
         and stn.type.type.fullname.startswith("odoo.models.") else stn.type)
        for name, stn in typ.type.names.items() if stn.type
    })
Esempio n. 7
0
def open_return_type(api: CheckerPluginInterface,
                     args: List[List[Expression]]) -> Optional[Type]:
    def return_type(word: Literal["Text", "Buffered", "Raw"]) -> Type:
        return api.named_generic_type(
            "typing.Awaitable",
            [api.named_generic_type("trio._Async{}IOBase".format(word), [])],
        )

    if len(args) < 2 or len(args[1]) == 0:
        # If mode is unspecified, the default is text
        return return_type("Text")

    if len(args[1]) == 1:
        # Mode was specified
        mode_arg = args[1][0]
        if isinstance(mode_arg, StrExpr):
            # Mode is a string constant
            if "b" not in mode_arg.value:
                # If there's no "b" in it, it's a text mode
                return return_type("Text")
            # Otherwise it's binary -- determine whether buffered or not
            if len(args) >= 3 and len(args[2]) == 1:
                # Buffering was specified
                buffering_arg = args[2][0]
                if isinstance(buffering_arg, IntExpr):
                    # Buffering is a constant -- zero means
                    # unbuffered, otherwise buffered
                    if buffering_arg.value == 0:
                        return return_type("Raw")
                    return return_type("Buffered")
                # Not a constant, so we're not sure which it is.
                options = [
                    api.named_generic_type("trio._AsyncRawIOBase", []),
                    api.named_generic_type("trio._AsyncBufferedIOBase", []),
                ]  # type: List[Type]
                return api.named_generic_type(
                    "typing.Awaitable",
                    [UnionType.make_simplified_union(options)])
            else:
                # Buffering is default if not specified
                return return_type("Buffered")

    # Mode wasn't a constant or we couldn't make sense of it
    return None
Esempio n. 8
0
def make_fake_register_class_instance(api: CheckerPluginInterface, type_args: Sequence[Type]
                                      ) -> Instance:
    defn = ClassDef(REGISTER_RETURN_CLASS, Block([]))
    defn.fullname = f'functools.{REGISTER_RETURN_CLASS}'
    info = TypeInfo(SymbolTable(), defn, "functools")
    obj_type = api.named_generic_type('builtins.object', []).type
    info.bases = [Instance(obj_type, [])]
    info.mro = [info, obj_type]
    defn.info = info

    func_arg = Argument(Var('name'), AnyType(TypeOfAny.implementation_artifact), None, ARG_POS)
    add_method_to_class(api, defn, '__call__', [func_arg], NoneType())

    return Instance(info, type_args)
Esempio n. 9
0
def make_simple_type(
    fieldtype: str,
    arg_names: List[List[Optional[str]]],
    args: List[List[Expression]],
    api: CheckerPluginInterface,
) -> Optional[Type]:
    typename = SIMPLE_FIELD_TO_TYPE.get(fieldtype)
    if not typename:
        return None
    stdtype = api.named_generic_type(typename, [])
    for nameset, argset in zip(arg_names, args):
        for name, arg in zip(nameset, argset):
            if name == "required" and is_false_literal(arg):
                nonetype = NoneTyp()
                optionaltype = UnionType([stdtype, nonetype])
                return optionaltype
    return stdtype
Esempio n. 10
0
def resolve_model_lookup(api: CheckerPluginInterface,
                         model_type_info: TypeInfo, lookup: str) -> LookupNode:
    """Resolve a lookup on the given model."""
    if lookup == 'pk':
        # Primary keys are special-cased
        primary_key_type = helpers.extract_primary_key_type_for_get(
            model_type_info)
        if primary_key_type:
            return FieldNode(primary_key_type)
        else:
            # No PK, use the get type for AutoField as PK type.
            autofield_info = api.lookup_typeinfo(
                'django.db.models.fields.AutoField')
            pk_type = helpers.get_private_descriptor_type(
                autofield_info, '_pyi_private_get_type', is_nullable=False)
            return FieldNode(pk_type)

    field_name = get_actual_field_name_for_lookup_field(
        lookup, model_type_info)

    field_node = model_type_info.get(field_name)
    if not field_node:
        raise LookupException(
            f'When resolving lookup "{lookup}", field "{field_name}" was not found in model {model_type_info.name()}'
        )

    if field_name.endswith('_id'):
        field_name_without_id = field_name.rstrip('_id')
        foreign_key_field = model_type_info.get(field_name_without_id)
        if foreign_key_field is not None and helpers.is_foreign_key(
                foreign_key_field.type):
            # Hack: If field ends with '_id' and there is a model field without the '_id' suffix, then use that field.
            field_node = foreign_key_field
            field_name = field_name_without_id

    field_node_type = field_node.type
    if field_node_type is None or not isinstance(field_node_type, Instance):
        raise LookupException(
            f'When resolving lookup "{lookup}", could not determine type for {model_type_info.name()}.{field_name}'
        )

    if helpers.is_foreign_key(field_node_type):
        field_type = helpers.extract_field_getter_type(field_node_type)
        is_nullable = helpers.is_optional(field_type)
        if is_nullable:
            field_type = helpers.make_required(field_type)

        if isinstance(field_type, Instance):
            return RelatedModelNode(typ=field_type, is_nullable=is_nullable)
        else:
            raise LookupException(
                f"Not an instance for field {field_type} lookup {lookup}")

    field_type = helpers.extract_field_getter_type(field_node_type)

    if field_type:
        return FieldNode(typ=field_type)
    else:
        # Not a Field
        if field_name == 'id':
            # If no 'id' field was fouond, use an int
            return FieldNode(api.named_generic_type('builtins.int', []))

        related_manager_arg = None
        if field_node_type.type.has_base(
                helpers.RELATED_MANAGER_CLASS_FULLNAME):
            related_manager_arg = field_node_type.args[0]

        if related_manager_arg is not None:
            # Reverse relation
            return RelatedModelNode(typ=related_manager_arg, is_nullable=True)
        raise LookupException(
            f'When resolving lookup "{lookup}", could not determine type for {model_type_info.name()}.{field_name}'
        )
Esempio n. 11
0
def resolve_model_lookup(api: CheckerPluginInterface,
                         model_type_info: TypeInfo, lookup: str) -> LookupNode:
    """Resolve a lookup on the given model."""
    if lookup == 'pk':
        return resolve_model_pk_lookup(api, model_type_info)

    field_name = get_actual_field_name_for_lookup_field(
        lookup, model_type_info)

    field_node = model_type_info.get(field_name)
    if not field_node:
        raise LookupException(
            f'When resolving lookup "{lookup}", field "{field_name}" was not found in model {model_type_info.name()}'
        )

    if field_name.endswith('_id'):
        field_name_without_id = field_name.rstrip('_id')
        foreign_key_field = model_type_info.get(field_name_without_id)
        if foreign_key_field is not None and helpers.is_foreign_key_like(
                foreign_key_field.type):
            # Hack: If field ends with '_id' and there is a model field without the '_id' suffix, then use that field.
            field_node = foreign_key_field
            field_name = field_name_without_id

    field_node_type = field_node.type
    if field_node_type is None or not isinstance(field_node_type, Instance):
        raise LookupException(
            f'When resolving lookup "{lookup}", could not determine type for {model_type_info.name()}.{field_name}'
        )

    if field_node_type.type.fullname() == 'builtins.object':
        # could be related manager
        related_manager_type = helpers.get_related_manager_type_from_metadata(
            model_type_info, field_name, api)
        if related_manager_type:
            model_arg = related_manager_type.args[0]
            if not isinstance(model_arg, Instance):
                raise LookupException(
                    f'When resolving lookup "{lookup}", could not determine type '
                    f'for {model_type_info.name()}.{field_name}')

            return RelatedModelNode(typ=model_arg, is_nullable=False)

    if helpers.is_foreign_key_like(field_node_type):
        field_type = helpers.extract_field_getter_type(field_node_type)
        is_nullable = helpers.is_optional(field_type)
        if is_nullable:
            # type is always non-optional
            field_type = helpers.make_required(field_type)

        if isinstance(field_type, Instance):
            return RelatedModelNode(typ=field_type, is_nullable=is_nullable)
        else:
            raise LookupException(
                f"Not an instance for field {field_type} lookup {lookup}")

    field_type = helpers.extract_field_getter_type(field_node_type)
    if field_type:
        return FieldNode(typ=field_type)

    # Not a Field
    if field_name == 'id':
        # If no 'id' field was found, use an int
        return FieldNode(api.named_generic_type('builtins.int', []))

    raise LookupException(
        f'When resolving lookup {lookup!r}, could not determine type for {model_type_info.name()}.{field_name}'
    )