예제 #1
0
    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=[TypeVarType('X', 'X', -1, [], self.fx.o)])
        assert_equal(str(c), 'def [X] (X?, Y?) -> Y?')

        v = [TypeVarType('Y', 'Y', -1, [], self.fx.o),
             TypeVarType('X', 'X', -2, [], self.fx.o)]
        c2 = CallableType([], [], [], NoneType(), self.function, name=None, variables=v)
        assert_equal(str(c2), 'def [Y, X] ()')
예제 #2
0
파일: plugin.py 프로젝트: rmoorman/mypy
def typed_dict_get_signature_callback(
        object_type: Type, args: List[List[Expression]],
        signature: CallableType,
        named_generic_type: Callable[[str, List[Type]], Type]) -> CallableType:
    """Try to infer a better signature type for TypedDict.get.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    if (isinstance(object_type, TypedDictType) and len(args) == 2
            and len(args[0]) == 1 and isinstance(args[0][0], StrExpr)
            and len(signature.arg_types) == 2
            and len(signature.variables) == 1):
        key = args[0][0].value
        value_type = object_type.items.get(key)
        if value_type:
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            tv = TypeVarType(signature.variables[0])
            return signature.copy_modified(arg_types=[
                signature.arg_types[0],
                UnionType.make_simplified_union([value_type, tv])
            ])
    return signature
예제 #3
0
def fill_typevars(typ: TypeInfo) -> Union[Instance, TupleType]:
    """For a non-generic type, return instance type representing the type.

    For a generic G type with parameters T1, .., Tn, return G[T1, ..., Tn].
    """
    tvs: List[Type] = []
    # TODO: why do we need to keep both typ.type_vars and typ.defn.type_vars?
    for i in range(len(typ.defn.type_vars)):
        tv = typ.defn.type_vars[i]
        # Change the line number
        tv = TypeVarType(
            tv.name,
            tv.fullname,
            tv.id,
            tv.values,
            tv.upper_bound,
            tv.variance,
            line=-1,
            column=-1,
        )
        tvs.append(tv)
    inst = Instance(typ, tvs)
    if typ.tuple_type is None:
        return inst
    return typ.tuple_type.copy_modified(fallback=inst)
예제 #4
0
파일: default.py 프로젝트: zdszt/mypy
def typed_dict_get_signature_callback(ctx: MethodSigContext) -> CallableType:
    """Try to infer a better signature type for TypedDict.get.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    signature = ctx.default_signature
    if (isinstance(ctx.type, TypedDictType) and len(ctx.args) == 2
            and len(ctx.args[0]) == 1 and isinstance(ctx.args[0][0], StrExpr)
            and len(signature.arg_types) == 2 and len(signature.variables) == 1
            and len(ctx.args[1]) == 1):
        key = ctx.args[0][0].value
        value_type = ctx.type.items.get(key)
        ret_type = signature.ret_type
        if value_type:
            default_arg = ctx.args[1][0]
            if (isinstance(value_type, TypedDictType)
                    and isinstance(default_arg, DictExpr)
                    and len(default_arg.items) == 0):
                # Caller has empty dict {} as default for typed dict.
                value_type = value_type.copy_modified(required_keys=set())
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            tv = TypeVarType(signature.variables[0])
            return signature.copy_modified(arg_types=[
                signature.arg_types[0],
                UnionType.make_simplified_union([value_type, tv])
            ],
                                           ret_type=ret_type)
    return signature
예제 #5
0
def _add_cmp(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None:
    """Generate all the cmp methods for this class."""
    # For __ne__ and __eq__ the type is:
    #     def __ne__(self, other: object) -> bool
    bool_type = ctx.api.named_type('__builtins__.bool')
    object_type = ctx.api.named_type('__builtins__.object')
    args = [Argument(Var('other', object_type), object_type, None, ARG_POS)]
    for method in ['__ne__', '__eq__']:
        adder.add_method(method, args, bool_type)
    # For the rest we use:
    #    AT = TypeVar('AT')
    #    def __lt__(self: AT, other: AT) -> bool
    # This way comparisons with subclasses will work correctly.
    tvd = TypeVarDef(SELF_TVAR_NAME,
                     ctx.cls.info.fullname() + '.' + SELF_TVAR_NAME, -1, [],
                     object_type)
    tvd_type = TypeVarType(tvd)
    self_tvar_expr = TypeVarExpr(
        SELF_TVAR_NAME,
        ctx.cls.info.fullname() + '.' + SELF_TVAR_NAME, [], object_type)
    ctx.cls.info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr)

    args = [Argument(Var('other', tvd_type), tvd_type, None, ARG_POS)]
    for method in ['__lt__', '__le__', '__gt__', '__ge__']:
        adder.add_method(method, args, bool_type, self_type=tvd_type, tvd=tvd)
예제 #6
0
    def add_construct_method(self, fields: List["PydanticModelField"]) -> None:
        """
        Adds a fully typed `construct` classmethod to the class.

        Similar to the fields-aware __init__ method, but always uses the field names (not aliases),
        and does not treat settings fields as optional.
        """
        ctx = self._ctx
        set_str = ctx.api.named_type("__builtins__.set",
                                     [ctx.api.named_type("__builtins__.str")])
        optional_set_str = UnionType([set_str, NoneType()])
        fields_set_argument = Argument(Var("_fields_set", optional_set_str),
                                       optional_set_str, None, ARG_OPT)
        construct_arguments = self.get_field_arguments(
            fields, typed=True, force_all_optional=False, use_alias=False)
        construct_arguments = [fields_set_argument] + construct_arguments

        obj_type = ctx.api.named_type("__builtins__.object")
        self_tvar_name = "Model"
        tvar_fullname = ctx.cls.fullname + "." + self_tvar_name
        tvd = TypeVarDef(self_tvar_name, tvar_fullname, -1, [], obj_type)
        self_tvar_expr = TypeVarExpr(self_tvar_name, tvar_fullname, [],
                                     obj_type)
        ctx.cls.info.names[self_tvar_name] = SymbolTableNode(
            MDEF, self_tvar_expr)
        self_type = TypeVarType(tvd)
        add_method(
            ctx,
            "construct",
            construct_arguments,
            return_type=self_type,
            self_type=self_type,
            tvar_def=tvd,
            is_classmethod=True,
        )
예제 #7
0
def typed_dict_pop_signature_callback(ctx: MethodSigContext) -> CallableType:
    """Try to infer a better signature type for TypedDict.pop.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    signature = ctx.default_signature
    str_type = ctx.api.named_generic_type('builtins.str', [])
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.args) == 2
            and len(ctx.args[0]) == 1
            and isinstance(ctx.args[0][0], StrExpr)
            and len(signature.arg_types) == 2
            and len(signature.variables) == 1
            and len(ctx.args[1]) == 1):
        key = ctx.args[0][0].value
        value_type = ctx.type.items.get(key)
        if value_type:
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            assert isinstance(signature.variables[0], TypeVarDef)
            tv = TypeVarType(signature.variables[0])
            typ = make_simplified_union([value_type, tv])
            return signature.copy_modified(
                arg_types=[str_type, typ],
                ret_type=typ)
    return signature.copy_modified(arg_types=[str_type, signature.arg_types[1]])
예제 #8
0
 def bind_new(self, name: str,
              tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
     if self.is_class_scope:
         self.class_id += 1
         i = self.class_id
     else:
         self.func_id -= 1
         i = self.func_id
     if isinstance(tvar_expr, TypeVarExpr):
         tvar_def: TypeVarLikeType = TypeVarType(
             name,
             tvar_expr.fullname,
             i,
             values=tvar_expr.values,
             upper_bound=tvar_expr.upper_bound,
             variance=tvar_expr.variance,
             line=tvar_expr.line,
             column=tvar_expr.column)
     elif isinstance(tvar_expr, ParamSpecExpr):
         tvar_def = ParamSpecType(name,
                                  tvar_expr.fullname,
                                  i,
                                  line=tvar_expr.line,
                                  column=tvar_expr.column)
     else:
         assert False
     self.scope[tvar_expr.fullname] = tvar_def
     return tvar_def
예제 #9
0
def snapshot_definition(node: Optional[SymbolNode],
                        common: Tuple[object, ...]) -> Tuple[object, ...]:
    """Create a snapshot description of a symbol table node.

    The representation is nested tuples and dicts. Only externally
    visible attributes are included.
    """
    if isinstance(node, (OverloadedFuncDef, FuncItem)):
        # TODO: info
        if node.type:
            signature = snapshot_type(node.type)
        else:
            signature = snapshot_untyped_signature(node)
        return ('Func', common, node.is_property, signature)
    elif isinstance(node, Var):
        return ('Var', common, snapshot_optional_type(node.type))
    elif isinstance(node, Decorator):
        # Note that decorated methods are represented by Decorator instances in
        # a symbol table since we need to preserve information about the
        # decorated function (whether it's a class function, for
        # example). Top-level decorated functions, however, are represented by
        # the corresponding Var node, since that happens to provide enough
        # context.
        return ('Decorator', node.is_overload,
                snapshot_optional_type(node.var.type),
                snapshot_definition(node.func, common))
    elif isinstance(node, TypeInfo):
        attrs = (
            node.is_abstract,
            node.is_enum,
            node.fallback_to_any,
            node.is_named_tuple,
            node.is_newtype,
            # We need this to e.g. trigger metaclass calculation in subclasses.
            snapshot_optional_type(node.metaclass_type),
            snapshot_optional_type(node.tuple_type),
            snapshot_optional_type(node.typeddict_type),
            [base.fullname() for base in node.mro],
            # Note that the structure of type variables is a part of the external interface,
            # since creating instances might fail, for example:
            #     T = TypeVar('T', bound=int)
            #     class C(Generic[T]):
            #         ...
            #     x: C[str] <- this is invalid, and needs to be re-checked if `T` changes.
            # An alternative would be to create both deps: <...> -> C, and <...> -> <C>,
            # but this currently seems a bit ad hoc.
            tuple(
                snapshot_type(TypeVarType(tdef))
                for tdef in node.defn.type_vars),
            [snapshot_type(base) for base in node.bases],
            snapshot_optional_type(node._promote))
        prefix = node.fullname()
        symbol_table = snapshot_symbol_table(prefix, node.names)
        # Special dependency for abstract attribute handling.
        symbol_table['(abstract)'] = ('Abstract',
                                      tuple(sorted(node.abstract_attributes)))
        return ('TypeInfo', common, attrs, symbol_table)
    else:
        # Other node types are handled elsewhere.
        assert False, type(node)
예제 #10
0
def _get_compose_type(context: FunctionContext) -> t.Optional[CallableType]:
    # TODO, why are the arguments lists of lists,
    # and do I need to worry about it?
    n_args = len([at for ats in context.arg_types for at in ats])

    arg_types = []
    arg_kinds = []
    arg_names = []
    ret_type_def = _type_var_def('R1', 'pfun.compose',
                                 context.api.named_type('builtins.object'))
    ret_type = TypeVarType(ret_type_def)
    variables = [ret_type_def]
    for n in range(n_args):
        current_arg_type_def = _type_var_def(
            f'R{n + 2}', 'pfun.compose',
            context.api.named_type('builtins.object'))
        current_arg_type = TypeVarType(current_arg_type_def)
        arg_type = CallableType(
            arg_types=[current_arg_type],
            ret_type=ret_type,
            arg_kinds=[ARG_POS],
            arg_names=[None],
            variables=[current_arg_type_def, ret_type_def],
            fallback=context.api.named_type('builtins.function'))
        arg_types.append(arg_type)
        arg_kinds.append(ARG_POS)
        arg_names.append(None)
        variables.append(current_arg_type_def)
        ret_type_def = current_arg_type_def
        ret_type = current_arg_type
    first_arg_type, *_, last_arg_type = arg_types
    ret_type = CallableType(
        arg_types=last_arg_type.arg_types,
        arg_names=last_arg_type.arg_names,
        arg_kinds=last_arg_type.arg_kinds,
        ret_type=first_arg_type.ret_type,
        variables=[first_arg_type.variables[-1], last_arg_type.variables[0]],
        fallback=context.api.named_type('builtins.function'))
    return CallableType(arg_types=arg_types,
                        arg_kinds=arg_kinds,
                        arg_names=arg_names,
                        ret_type=ret_type,
                        variables=variables,
                        fallback=context.api.named_type('builtins.function'),
                        name='compose')
예제 #11
0
파일: mypy_plugin.py 프로젝트: suned/pfun
def _set_lens_method_types(lens: Instance) -> None:
    arg_type = lens.args[0]
    t_def = _type_var_def('A',
                          'pfun.lens',
                          upper_bound=arg_type,
                          variance=COVARIANT)
    t_var = TypeVarType(t_def)
    __call__ = lens.type.names['__call__']
    _set_method_type_vars(__call__, t_var, t_def)
예제 #12
0
def analyze_class_attribute_access(itype: Instance, name: str,
                                   context: Context, is_lvalue: bool,
                                   builtin_type: Callable[[str], Instance],
                                   not_ready_callback: Callable[[str, Context],
                                                                None],
                                   msg: MessageBuilder,
                                   original_type: Type) -> Type:
    """original_type is the type of E in the expression E.var"""
    node = itype.type.get(name)
    if not node:
        if itype.type.fallback_to_any:
            return AnyType()
        return None

    is_decorated = isinstance(node.node, Decorator)
    is_method = is_decorated or isinstance(node.node, FuncDef)
    if is_lvalue:
        if is_method:
            msg.cant_assign_to_method(context)
        if isinstance(node.node, TypeInfo):
            msg.fail(messages.CANNOT_ASSIGN_TO_TYPE, context)

    if itype.type.is_enum and not (is_lvalue or is_decorated or is_method):
        return itype

    t = node.type
    if t:
        if isinstance(t, PartialType):
            return handle_partial_attribute_type(t, is_lvalue, msg, node.node)
        if not is_method and (isinstance(t, TypeVarType) or get_type_vars(t)):
            msg.fail(messages.GENERIC_INSTANCE_VAR_CLASS_ACCESS, context)
        is_classmethod = is_decorated and cast(Decorator,
                                               node.node).func.is_class
        return add_class_tvars(t, itype, is_classmethod, builtin_type,
                               original_type)
    elif isinstance(node.node, Var):
        not_ready_callback(name, context)
        return AnyType()

    if isinstance(node.node, TypeVarExpr):
        return TypeVarType(node.tvar_def, node.tvar_def.line,
                           node.tvar_def.column)

    if isinstance(node.node, TypeInfo):
        return type_object_type(node.node, builtin_type)

    if isinstance(node.node, MypyFile):
        # Reference to a module object.
        return builtin_type('builtins.module')

    if is_decorated:
        # TODO: Return type of decorated function. This is quick hack to work around #998.
        return AnyType()
    else:
        return function_type(cast(FuncBase, node.node),
                             builtin_type('builtins.function'))
예제 #13
0
 def visit_type_var(self, t: TypeVarType) -> ProperType:
     dup = TypeVarType(
         t.name,
         t.fullname,
         t.id,
         values=t.values,
         upper_bound=t.upper_bound,
         variance=t.variance,
     )
     return self.copy_common(t, dup)
예제 #14
0
def fill_typevars(typ: TypeInfo) -> Union[Instance, TupleType]:
    """For a non-generic type, return instance type representing the type.
    For a generic G type with parameters T1, .., Tn, return G[T1, ..., Tn].
    """
    tv = []  # type: List[Type]
    for i in range(len(typ.type_vars)):
        tv.append(TypeVarType(typ.defn.type_vars[i]))
    inst = Instance(typ, tv)
    if typ.tuple_type is None:
        return inst
    return typ.tuple_type.copy_modified(fallback=inst)
예제 #15
0
 def add_primitive_method(self):
     ctx = self._ctx
     self_tvar_def = self._get_tvar_def(SELF_TVAR_NAME, ctx)
     bool_type = ctx.api.named_type("__builtins__.bool")
     arg = Argument(Var("lazy", bool_type), bool_type, None, ARG_NAMED_OPT)
     add_method(
         ctx,
         "primitive",
         args=[arg],
         return_type=AnyType(TypeOfAny.unannotated),
         self_type=TypeVarType(self_tvar_def),
         tvar_def=self_tvar_def,
     )
예제 #16
0
 def add_transmute_method(self):
     ctx = self._ctx
     self_tvar_def = self._get_tvar_def(SELF_TVAR_NAME, ctx)
     arg_type = AnyType(TypeOfAny.explicit)
     arg = Argument(Var("obj", arg_type), arg_type, None, ARG_POS)
     add_method(
         ctx,
         "transmute",
         args=[arg],
         return_type=TypeVarType(self_tvar_def),
         tvar_def=self_tvar_def,
         is_staticmethod=True,
     )
예제 #17
0
def _combine_hook(context: FunctionContext):
    result_types = []
    error_types = []
    env_types = []
    try:
        for effect_type in context.arg_types[0]:
            env_type, error_type, result_type = get_proper_type(
                effect_type).args
            env_types.append(env_type)
            error_types.append(error_type)
            result_types.append(result_type)
        map_return_type_def = _type_var_def(
            'R1', 'pfun.effect', context.api.named_type('builtins.object'))
        map_return_type = TypeVarType(map_return_type_def)
        map_function_type = CallableType(
            arg_types=result_types,
            arg_kinds=[ARG_POS for _ in result_types],
            arg_names=[None for _ in result_types],
            ret_type=map_return_type,
            variables=[map_return_type_def],
            fallback=context.api.named_type('builtins.function'))
        ret_type = context.default_return_type.ret_type
        combined_error_type = UnionType.make_union(
            sorted(set(error_types), key=str))
        ret_type_args = ret_type.args
        ret_type_args[1] = combined_error_type
        ret_type_args[2] = map_return_type
        env_types = [
            env_type for env_type in env_types
            if not isinstance(env_type, AnyType)
        ]
        if len(set(env_types)) == 1:
            combined_env_type = env_types[0]
        elif env_types and all(
                hasattr(env_type, 'type') and env_type.type.is_protocol
                for env_type in env_types):
            combined_env_type = reduce(_combine_protocols, env_types)
        else:
            combined_env_type = ret_type_args[0]
        ret_type_args[0] = combined_env_type
        ret_type = ret_type.copy_modified(args=ret_type_args)
        return CallableType(
            arg_types=[map_function_type],
            arg_kinds=[ARG_POS],
            arg_names=[None],
            variables=[map_return_type_def],
            ret_type=ret_type,
            fallback=context.api.named_type('builtins.function'))
    except AttributeError:
        return context.default_return_type
예제 #18
0
 def add_translate_method(self):
     ctx = self._ctx
     self_tvar_def = self._get_tvar_def(SELF_TVAR_NAME, ctx)
     r_type = AnyType(TypeOfAny.explicit)
     arg_type = TypeType(r_type)
     arg = Argument(Var("target", arg_type), arg_type, None, ARG_POS)
     add_method(
         ctx,
         "translate",
         args=[arg],
         return_type=r_type,
         self_type=TypeVarType(self_tvar_def),
         tvar_def=self_tvar_def,
     )
예제 #19
0
 def add_iter_method(self):
     ctx = self._ctx
     self_tvar_def = self._get_tvar_def(SELF_TVAR_NAME, ctx)
     r_type = AnyType(TypeOfAny.explicit)
     bool_type = ctx.api.named_type("__builtins__.bool")
     arg = Argument(Var("values", bool_type), bool_type, None,
                    ARG_NAMED_OPT)
     add_method(
         ctx,
         "__iter__",
         args=[arg],
         return_type=r_type,
         self_type=TypeVarType(self_tvar_def),
         tvar_def=self_tvar_def,
     )
예제 #20
0
 def callable(self, vars: List[str], *a: Type) -> CallableType:
     """callable(args, a1, ..., an, r) constructs a callable with
     argument types a1, ... an and return type r and type arguments
     vars.
     """
     tv: List[TypeVarType] = []
     n = -1
     for v in vars:
         tv.append(TypeVarType(v, v, n, [], self.fx.o))
         n -= 1
     return CallableType(list(a[:-1]), [ARG_POS] * (len(a) - 1),
                         [None] * (len(a) - 1),
                         a[-1],
                         self.fx.function,
                         name=None,
                         variables=tv)
예제 #21
0
파일: attrs.py 프로젝트: alanhdu/mypy
def _add_order(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None:
    """Generate all the ordering methods for this class."""
    bool_type = ctx.api.named_type('__builtins__.bool')
    object_type = ctx.api.named_type('__builtins__.object')
    # Make the types be:
    #    AT = TypeVar('AT')
    #    def __lt__(self: AT, other: AT) -> bool
    # This way comparisons with subclasses will work correctly.
    tvd = TypeVarType(SELF_TVAR_NAME, ctx.cls.info.fullname + '.' + SELF_TVAR_NAME,
                     -1, [], object_type)
    self_tvar_expr = TypeVarExpr(SELF_TVAR_NAME, ctx.cls.info.fullname + '.' + SELF_TVAR_NAME,
                                 [], object_type)
    ctx.cls.info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr)

    args = [Argument(Var('other', tvd), tvd, None, ARG_POS)]
    for method in ['__lt__', '__le__', '__gt__', '__ge__']:
        adder.add_method(method, args, bool_type, self_type=tvd, tvd=tvd)
예제 #22
0
파일: attrs.py 프로젝트: rkday/mypy
def _add_cmp(ctx: 'mypy.plugin.ClassDefContext', adder: 'MethodAdder') -> None:
    """Generate all the cmp methods for this class."""
    # For __ne__ and __eq__ the type is:
    #     def __ne__(self, other: object) -> bool
    bool_type = ctx.api.named_type('__builtins__.bool')
    object_type = ctx.api.named_type('__builtins__.object')
    args = [Argument(Var('other', object_type), object_type, None, ARG_POS)]
    for method in ['__ne__', '__eq__']:
        adder.add_method(method, args, bool_type)
    # For the rest we use:
    #    AT = TypeVar('AT')
    #    def __lt__(self: AT, other: AT) -> bool
    # This way comparisons with subclasses will work correctly.
    tvd = TypeVarDef('AT', 'AT', 1, [], object_type)
    tvd_type = TypeVarType(tvd)
    args = [Argument(Var('other', tvd_type), tvd_type, None, ARG_POS)]
    for method in ['__lt__', '__le__', '__gt__', '__ge__']:
        adder.add_method(method, args, bool_type, self_type=tvd_type, tvd=tvd)
예제 #23
0
def freshen_function_type_vars(callee: F) -> F:
    """Substitute fresh type variables for generic function type variables."""
    if isinstance(callee, CallableType):
        if not callee.is_generic():
            return cast(F, callee)
        tvdefs = []
        tvmap = {}  # type: Dict[TypeVarId, Type]
        for v in callee.variables:
            tvdef = TypeVarDef.new_unification_variable(v)
            tvdefs.append(tvdef)
            tvmap[v.id] = TypeVarType(tvdef)
        fresh = cast(CallableType, expand_type(callee, tvmap)).copy_modified(variables=tvdefs)
        return cast(F, fresh)
    else:
        assert isinstance(callee, Overloaded)
        fresh_overload = Overloaded([freshen_function_type_vars(item)
                                     for item in callee.items()])
        return cast(F, fresh_overload)
예제 #24
0
 def add_schema_method(self):
     ctx = self._ctx
     api: SemanticAnalyzer = ctx.api
     return_type_info: SymbolTableNode = api.lookup_fully_qualified(
         "typic.SchemaReturnT")
     self_tvar_def = self._get_tvar_def(SELF_TVAR_NAME, ctx)
     arg_type = api.named_type("__builtins__.bool")
     arg = Argument(Var("primitive", arg_type), arg_type, None,
                    ARG_NAMED_OPT)
     add_method(
         ctx,
         "schema",
         args=[arg],
         return_type=return_type_info.node.target,
         self_type=TypeVarType(self_tvar_def),
         tvar_def=self_tvar_def,
         is_classmethod=True,
     )
예제 #25
0
 def add_json_method(self):
     ctx = self._ctx
     self_tvar_def = self._get_tvar_def(SELF_TVAR_NAME, ctx)
     bool_type = ctx.api.named_type("__builtins__.bool")
     int_type = ctx.api.named_type("__builtins__.int")
     str_type = ctx.api.named_type("__builtins__.str")
     indent = Argument(Var("indent", int_type), int_type, None,
                       ARG_NAMED_OPT)
     ensure = Argument(Var("ensure_ascii", bool_type), bool_type, None,
                       ARG_NAMED_OPT)
     add_method(
         ctx,
         "tojson",
         args=[indent, ensure],
         return_type=str_type,
         self_type=TypeVarType(self_tvar_def),
         tvar_def=self_tvar_def,
     )
예제 #26
0
    def make_type_info(self,
                       name: str,
                       module_name: Optional[str] = None,
                       is_abstract: bool = False,
                       mro: Optional[List[TypeInfo]] = None,
                       bases: Optional[List[Instance]] = None,
                       typevars: Optional[List[str]] = None,
                       variances: Optional[List[int]] = None) -> TypeInfo:
        """Make a TypeInfo suitable for use in unit tests."""

        class_def = ClassDef(name, Block([]), None, [])
        class_def.fullname = name

        if module_name is None:
            if '.' in name:
                module_name = name.rsplit('.', 1)[0]
            else:
                module_name = '__main__'

        if typevars:
            v: List[TypeVarLikeType] = []
            for id, n in enumerate(typevars, 1):
                if variances:
                    variance = variances[id - 1]
                else:
                    variance = COVARIANT
                v.append(TypeVarType(n, n, id, [], self.o, variance=variance))
            class_def.type_vars = v

        info = TypeInfo(SymbolTable(), class_def, module_name)
        if mro is None:
            mro = []
            if name != 'builtins.object':
                mro.append(self.oi)
        info.mro = [info] + mro
        if bases is None:
            if mro:
                # By default, assume that there is a single non-generic base.
                bases = [Instance(mro[0], [])]
            else:
                bases = []
        info.bases = bases

        return info
예제 #27
0
    def add_construct_method(self, fields: List['PydanticModelField']) -> None:
        """
        Adds a fully typed `construct` classmethod to the class.

        Similar to the fields-aware __init__ method, but always uses the field names (not aliases),
        and does not treat settings fields as optional.
        """
        ctx = self._ctx
        set_str = ctx.api.named_type(
            f'{BUILTINS_NAME}.set',
            [ctx.api.named_type(f'{BUILTINS_NAME}.str')])
        optional_set_str = UnionType([set_str, NoneType()])
        fields_set_argument = Argument(Var('_fields_set', optional_set_str),
                                       optional_set_str, None, ARG_OPT)
        construct_arguments = self.get_field_arguments(
            fields, typed=True, force_all_optional=False, use_alias=False)
        construct_arguments = [fields_set_argument] + construct_arguments

        obj_type = ctx.api.named_type(f'{BUILTINS_NAME}.object')
        self_tvar_name = '_PydanticBaseModel'  # Make sure it does not conflict with other names in the class
        tvar_fullname = ctx.cls.fullname + '.' + self_tvar_name
        tvd = TypeVarDef(self_tvar_name, tvar_fullname, -1, [], obj_type)
        self_tvar_expr = TypeVarExpr(self_tvar_name, tvar_fullname, [],
                                     obj_type)
        ctx.cls.info.names[self_tvar_name] = SymbolTableNode(
            MDEF, self_tvar_expr)

        # Backward-compatible with TypeVarDef from Mypy 0.910.
        if isinstance(tvd, TypeVarType):
            self_type = tvd
        else:
            self_type = TypeVarType(tvd)  # type: ignore[call-arg]

        add_method(
            ctx,
            'construct',
            construct_arguments,
            return_type=self_type,
            self_type=self_type,
            tvar_def=tvd,
            is_classmethod=True,
        )
예제 #28
0
 def bind_new(self, name: str,
              tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
     if self.is_class_scope:
         self.class_id += 1
         i = self.class_id
         namespace = self.namespace
     else:
         self.func_id -= 1
         i = self.func_id
         # TODO: Consider also using namespaces for functions
         namespace = ''
     if isinstance(tvar_expr, TypeVarExpr):
         tvar_def: TypeVarLikeType = TypeVarType(
             name,
             tvar_expr.fullname,
             TypeVarId(i, namespace=namespace),
             values=tvar_expr.values,
             upper_bound=tvar_expr.upper_bound,
             variance=tvar_expr.variance,
             line=tvar_expr.line,
             column=tvar_expr.column)
     elif isinstance(tvar_expr, ParamSpecExpr):
         tvar_def = ParamSpecType(name,
                                  tvar_expr.fullname,
                                  i,
                                  flavor=ParamSpecFlavor.BARE,
                                  upper_bound=tvar_expr.upper_bound,
                                  line=tvar_expr.line,
                                  column=tvar_expr.column)
     elif isinstance(tvar_expr, TypeVarTupleExpr):
         tvar_def = TypeVarTupleType(name,
                                     tvar_expr.fullname,
                                     i,
                                     upper_bound=tvar_expr.upper_bound,
                                     line=tvar_expr.line,
                                     column=tvar_expr.column)
     else:
         assert False
     self.scope[tvar_expr.fullname] = tvar_def
     return tvar_def
예제 #29
0
파일: mro.py 프로젝트: dry-python/classes
    def add_supports_metadata(self) -> None:
        """Injects ``Supports`` metadata into instance types' mro."""
        if not isinstance(self._associated_type, Instance):
            return

        for instance_type in self._instance_types:
            assert isinstance(instance_type, Instance)

            supports_spec = self._associated_type.copy_modified(args=[
                TypeVarType(var_def)
                for var_def in instance_type.type.defn.type_vars
            ])
            supports_spec = type_loader.load_supports_type(
                supports_spec,
                self._ctx,
            )

            if supports_spec not in instance_type.type.bases:
                instance_type.type.bases.append(supports_spec)
            if supports_spec.type not in instance_type.type.mro:
                instance_type.type.mro.insert(0, supports_spec.type)

            self._added_types.append(supports_spec)
예제 #30
0
    def transform(self) -> None:
        """Apply all the necessary transformations to the underlying
        dataclass so as to ensure it is fully type checked according
        to the rules in PEP 557.
        """
        ctx = self._ctx
        info = self._ctx.cls.info
        attributes = self.collect_attributes()
        if attributes is None:
            # Some definitions are not ready, defer() should be already called.
            return
        for attr in attributes:
            if attr.type is None:
                ctx.api.defer()
                return
        decorator_arguments = {
            'init': _get_decorator_bool_argument(self._ctx, 'init', True),
            'eq': _get_decorator_bool_argument(self._ctx, 'eq', True),
            'order': _get_decorator_bool_argument(self._ctx, 'order', False),
            'frozen': _get_decorator_bool_argument(self._ctx, 'frozen', False),
        }

        if info.get('replace') is None:
            obj_type = ctx.api.named_type('__builtins__.object')
            self_tvar_expr = TypeVarExpr(SELF_UVAR_NAME,
                                         info.fullname + '.' + SELF_UVAR_NAME,
                                         [], obj_type)
            info.names[SELF_UVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr)
            replace_tvar_def = TypeVarDef(SELF_UVAR_NAME,
                                          info.fullname + '.' + SELF_UVAR_NAME,
                                          -1, [], fill_typevars(info))
            replace_other_type = TypeVarType(replace_tvar_def)

            add_method(ctx,
                       'replace',
                       args=[
                           Argument(
                               Var('changes', AnyType(TypeOfAny.explicit)),
                               AnyType(TypeOfAny.explicit), None, ARG_STAR2)
                       ],
                       return_type=replace_other_type,
                       self_type=replace_other_type,
                       tvar_def=replace_tvar_def)

        # If there are no attributes, it may be that the semantic analyzer has not
        # processed them yet. In order to work around this, we can simply skip generating
        # __init__ if there are no attributes, because if the user truly did not define any,
        # then the object default __init__ with an empty signature will be present anyway.
        if (decorator_arguments['init']
                and ('__init__' not in info.names
                     or info.names['__init__'].plugin_generated)
                and attributes):
            add_method(
                ctx,
                '__init__',
                args=[
                    attr.to_argument() for attr in attributes
                    if attr.is_in_init
                ],
                return_type=NoneType(),
            )

        if (decorator_arguments['eq'] and info.get('__eq__') is None
                or decorator_arguments['order']):
            # Type variable for self types in generated methods.
            obj_type = ctx.api.named_type('__builtins__.object')
            self_tvar_expr = TypeVarExpr(SELF_TVAR_NAME,
                                         info.fullname + '.' + SELF_TVAR_NAME,
                                         [], obj_type)
            info.names[SELF_TVAR_NAME] = SymbolTableNode(MDEF, self_tvar_expr)

        # Add <, >, <=, >=, but only if the class has an eq method.
        if decorator_arguments['order']:
            if not decorator_arguments['eq']:
                ctx.api.fail('eq must be True if order is True', ctx.cls)

            for method_name in ['__lt__', '__gt__', '__le__', '__ge__']:
                # Like for __eq__ and __ne__, we want "other" to match
                # the self type.
                obj_type = ctx.api.named_type('__builtins__.object')
                order_tvar_def = TypeVarDef(
                    SELF_TVAR_NAME, info.fullname + '.' + SELF_TVAR_NAME, -1,
                    [], obj_type)
                order_other_type = TypeVarType(order_tvar_def)
                order_return_type = ctx.api.named_type('__builtins__.bool')
                order_args = [
                    Argument(Var('other', order_other_type), order_other_type,
                             None, ARG_POS)
                ]

                existing_method = info.get(method_name)
                if existing_method is not None and not existing_method.plugin_generated:
                    assert existing_method.node
                    ctx.api.fail(
                        'You may not have a custom %s method when order=True' %
                        method_name,
                        existing_method.node,
                    )

                add_method(
                    ctx,
                    method_name,
                    args=order_args,
                    return_type=order_return_type,
                    self_type=order_other_type,
                    tvar_def=order_tvar_def,
                )

        if decorator_arguments['frozen']:
            self._freeze(attributes)

        self.reset_init_only_vars(info, attributes)

        info.metadata['dataclass'] = {
            'attributes': [attr.serialize() for attr in attributes],
            'frozen': decorator_arguments['frozen'],
        }