예제 #1
0
    def make_setter_wrapper(self, name: str, typ: Type) -> FuncDef:
        """Create a setter wrapper for a data attribute.

        The setter will be of this form:
        
        . def set$name(self: C, name: typ) -> None:
        .     self.name! = name
        """
        scope = self.make_scope()
        selft = self.self_type()
        selfv = scope.add('self', selft)
        namev = scope.add(name, typ)
        
        lvalue = MemberExpr(scope.name_expr('self'), name, direct=True)
        rvalue = scope.name_expr(name)
        ret = AssignmentStmt([lvalue], rvalue)

        wrapper_name = 'set$' + name
        sig = Callable([selft, typ],
                       [nodes.ARG_POS, nodes.ARG_POS],
                       [None, None],
                       Void(), False)
        fdef = FuncDef(wrapper_name,
                       [selfv, namev],
                       [nodes.ARG_POS, nodes.ARG_POS],
                       [None, None],
                       Block([ret]), sig)
        fdef.info = self.tf.type_context()
        return fdef
예제 #2
0
 def visit_Assign(self, n: ast35.Assign) -> AssignmentStmt:
     typ = None
     if hasattr(n,
                'annotation') and n.annotation is not None:  # type: ignore
         new_syntax = True
     else:
         new_syntax = False
     if new_syntax and self.pyversion < (3, 6):
         raise TypeCommentParseError(
             'Variable annotation syntax is only '
             'suppoted in Python 3.6, use type '
             'comment instead', n.lineno, n.col_offset)
     # typed_ast prevents having both type_comment and annotation.
     if n.type_comment is not None:
         typ = parse_type_comment(n.type_comment, n.lineno)
     elif new_syntax:
         typ = TypeConverter(line=n.lineno).visit(
             n.annotation)  # type: ignore
         typ.column = n.annotation.col_offset
     if n.value is None:  # always allow 'x: int'
         rvalue = TempNode(AnyType())  # type: Expression
     else:
         rvalue = self.visit(n.value)
     lvalues = self.translate_expr_list(n.targets)
     return AssignmentStmt(lvalues, rvalue, type=typ, new_syntax=new_syntax)
예제 #3
0
파일: treetransform.py 프로젝트: tony/mypy
    def copy_argument(self, argument: Argument) -> Argument:
        init_stmt = None  # type: AssignmentStmt

        if argument.initialization_statement:
            init_lvalue = cast(
                NameExpr,
                self.node(argument.initialization_statement.lvalues[0]),
            )
            init_lvalue.set_line(argument.line)
            init_stmt = AssignmentStmt(
                [init_lvalue],
                self.node(argument.initialization_statement.rvalue),
                self.optional_type(argument.initialization_statement.type),
            )

        arg = Argument(
            self.visit_var(argument.variable),
            argument.type_annotation,
            argument.initializer,
            argument.kind,
            init_stmt,
        )

        # Refresh lines of the inner things
        arg.set_line(argument.line)

        return arg
예제 #4
0
 def duplicate_assignment(self, node: AssignmentStmt) -> AssignmentStmt:
     new = AssignmentStmt(self.expressions(node.lvalues),
                          self.expr(node.rvalue),
                          self.optional_type(node.type))
     new.line = node.line
     new.is_final_def = node.is_final_def
     return new
예제 #5
0
파일: fastparse.py 프로젝트: ashwch/mypy
 def visit_AnnAssign(self, n: ast3.AnnAssign) -> AssignmentStmt:
     if n.value is None:  # always allow 'x: int'
         rvalue = TempNode(AnyType())  # type: Expression
     else:
         rvalue = self.visit(n.value)
     typ = TypeConverter(self.errors, line=n.lineno).visit(n.annotation)
     typ.column = n.annotation.col_offset
     return AssignmentStmt([self.visit(n.target)], rvalue, type=typ, new_syntax=True)
예제 #6
0
 def visit_Assign(self, n: ast3.Assign) -> AssignmentStmt:
     lvalues = self.translate_expr_list(n.targets)
     rvalue = self.visit(n.value)
     if n.type_comment is not None:
         typ = parse_type_comment(n.type_comment, n.lineno, self.errors)
     else:
         typ = None
     return AssignmentStmt(lvalues, rvalue, type=typ, new_syntax=False)
예제 #7
0
파일: fastparse2.py 프로젝트: smalias/mypy
    def visit_Assign(self, n: ast27.Assign) -> AssignmentStmt:
        typ = None
        if n.type_comment:
            typ = parse_type_comment(n.type_comment, n.lineno, self.errors)

        return AssignmentStmt(self.translate_expr_list(n.targets),
                              self.visit(n.value),
                              type=typ)
예제 #8
0
파일: fastparse.py 프로젝트: tony/mypy
    def visit_Assign(self, n: ast35.Assign) -> Node:
        typ = None
        if n.type_comment:
            typ = parse_type_comment(n.type_comment, n.lineno)

        return AssignmentStmt(self.visit_list(n.targets),
                              self.visit(n.value),
                              type=typ)
예제 #9
0
파일: fastparse2.py 프로젝트: pbasista/mypy
    def visit_Assign(self, n: ast27.Assign) -> AssignmentStmt:
        typ = None
        if n.type_comment:
            typ = parse_type_comment(n.type_comment, n.lineno, self.errors,
                                     assume_str_is_unicode=self.unicode_literals)

        stmt = AssignmentStmt(self.translate_expr_list(n.targets),
                              self.visit(n.value),
                              type=typ)
        return self.set_line(stmt, n)
예제 #10
0
파일: fastparse2.py 프로젝트: smalias/mypy
 def convert_arg(index: int, arg: ast27.expr) -> Var:
     if isinstance(arg, ast27.Name):
         v = arg.id
     elif isinstance(arg, ast27.Tuple):
         v = '__tuple_arg_{}'.format(index + 1)
         rvalue = NameExpr(v)
         rvalue.set_line(line)
         assignment = AssignmentStmt([self.visit(arg)], rvalue)
         assignment.set_line(line)
         decompose_stmts.append(assignment)
     else:
         raise RuntimeError("'{}' is not a valid argument.".format(ast27.dump(arg)))
     return Var(v)
예제 #11
0
 def visit_AnnAssign(self, n: ast3.AnnAssign) -> AssignmentStmt:
     if n.value is None:  # always allow 'x: int'
         rvalue = TempNode(AnyType(TypeOfAny.special_form),
                           no_rhs=True)  # type: Expression
     else:
         rvalue = self.visit(n.value)
     typ = TypeConverter(self.errors, line=n.lineno).visit(n.annotation)
     assert typ is not None
     typ.column = n.annotation.col_offset
     s = AssignmentStmt([self.visit(n.target)],
                        rvalue,
                        type=typ,
                        new_syntax=True)
     return self.set_line(s, n)
예제 #12
0
    def make_instance_tvar_initializer(self, creat: FuncDef) -> None:
        """Add type variable member initialization code to a constructor.

        Modify the constructor body directly.
        """
        for n in range(num_slots(creat.info)):
            rvalue = self.make_tvar_init_expression(creat.info, n)
            init = AssignmentStmt([MemberExpr(self_expr(),
                                              tvar_slot_name(n),
                                              direct=True)],
                                  rvalue)
            self.tf.set_type(init.lvalues[0], AnyType())
            self.tf.set_type(init.rvalue, AnyType())
            creat.body.body.insert(n, init)
예제 #13
0
    def make_generic_wrapper_init(self, info: TypeInfo) -> FuncDef:
        """Build constructor of a generic wrapper class."""
        nslots = num_slots(info)
        
        cdefs = [] # type: List[Node]
        
        # Build superclass constructor call.
        base = info.mro[1]
        if base.fullname() != 'builtins.object' and self.tf.is_java:
            s = SuperExpr('__init__')
            cargs = [NameExpr('__o')] # type: List[Node]
            for n in range(num_slots(base)):
                cargs.append(NameExpr(tvar_arg_name(n + 1)))
            for n in range(num_slots(base)):
                cargs.append(NameExpr(tvar_arg_name(n + 1, BOUND_VAR)))
            c = CallExpr(s, cargs, [nodes.ARG_POS] * len(cargs))
            cdefs.append(ExpressionStmt(c))
        
        # Create initialization of the wrapped object.
        cdefs.append(AssignmentStmt([MemberExpr(
                                         self_expr(),
                                         self.object_member_name(info),
                                         direct=True)],
                                    NameExpr('__o')))
        
        # Build constructor arguments.
        args = [Var('self'), Var('__o')]
        init = [None, None] # type: List[Node]
        
        for alt in [False, BOUND_VAR]:
            for n in range(nslots):
                args.append(Var(tvar_arg_name(n + 1, alt)))
                init.append(None)

        nargs = nslots * 2 + 2
        fdef = FuncDef('__init__',
                       args,
                       [nodes.ARG_POS] * nargs,
                       init,
                       Block(cdefs),
                       Callable( [AnyType()] * nargs,
                                [nodes.ARG_POS] * nargs, [None] * nargs,
                                Void(),
                                is_type_obj=False))
        fdef.info = info
        
        self.make_wrapper_slot_initializer(fdef)
        
        return fdef
예제 #14
0
    def make_wrapper_slot_initializer(self, creat: FuncDef) -> None:
        """Add type variable member initializations to a wrapper constructor.

        The function must be a constructor of a generic wrapper class. Modify
        the constructor body directly.
        """
        for alt in [BOUND_VAR, False]:
            for n in range(num_slots(creat.info)):
                rvalue = TypeExpr(
                    RuntimeTypeVar(NameExpr(tvar_slot_name(n, alt))))
                init = AssignmentStmt(
                    [MemberExpr(self_expr(),
                                tvar_slot_name(n, alt), direct=True)],
                    rvalue)
                self.tf.set_type(init.lvalues[0], AnyType())
                self.tf.set_type(init.rvalue, AnyType())
                creat.body.body.insert(n, init)
예제 #15
0
    def make_dynamic_setter_wrapper(self, name: str, typ: Type) -> FuncDef:
        """Create a dynamically-typed setter wrapper for a data attribute.

        The setter will be of this form:
        
        . def set$name*(self: C, name; Any) -> None:
        .     self.name! = {typ name}
        """
        lvalue = MemberExpr(self_expr(), name, direct=True)
        name_expr = NameExpr(name)
        rvalue = coerce(name_expr, typ, AnyType(), self.tf.type_context())
        ret = AssignmentStmt([lvalue], rvalue)

        wrapper_name = 'set$' + name + self.tf.dynamic_suffix()
        selft = self_type(self.tf.type_context())            
        sig = Callable([selft, AnyType()],
                       [nodes.ARG_POS, nodes.ARG_POS],
                       [None, None],
                       Void(), False)
        return FuncDef(wrapper_name,
                       [Var('self'), Var(name)],
                       [nodes.ARG_POS, nodes.ARG_POS],
                       [None, None],
                       Block([ret]), sig)
예제 #16
0
 def visit_Assign(self, n: ast27.Assign) -> AssignmentStmt:
     typ = self.translate_type_comment(n, n.type_comment)
     stmt = AssignmentStmt(self.translate_expr_list(n.targets),
                           self.visit(n.value),
                           type=typ)
     return self.set_line(stmt, n)
예제 #17
0
 def duplicate_assignment(self, node: AssignmentStmt) -> AssignmentStmt:
     new = AssignmentStmt(self.nodes(node.lvalues), self.node(node.rvalue),
                          self.optional_type(node.type))
     new.line = node.line
     return new
예제 #18
0
def _scan_declarative_decorator_stmt(
    cls: ClassDef,
    api: SemanticAnalyzerPluginInterface,
    stmt: Decorator,
    cls_metadata: util.DeclClassApplied,
) -> None:
    """Extract mapping information from a @declared_attr in a declarative
    class.

    E.g.::

        @reg.mapped
        class MyClass:
            # ...

            @declared_attr
            def updated_at(cls) -> Column[DateTime]:
                return Column(DateTime)

    Will resolve in mypy as::

        @reg.mapped
        class MyClass:
            # ...

            updated_at: Mapped[Optional[datetime.datetime]]

    """
    for dec in stmt.decorators:
        if (
            isinstance(dec, (NameExpr, MemberExpr, SymbolNode))
            and names._type_id_for_named_node(dec) is names.DECLARED_ATTR
        ):
            break
    else:
        return

    dec_index = cls.defs.body.index(stmt)

    left_hand_explicit_type: Optional[ProperType] = None

    if isinstance(stmt.func.type, CallableType):
        func_type = stmt.func.type.ret_type
        if isinstance(func_type, UnboundType):
            type_id = names._type_id_for_unbound_type(func_type, cls, api)
        else:
            # this does not seem to occur unless the type argument is
            # incorrect
            return

        if (
            type_id
            in {
                names.MAPPED,
                names.RELATIONSHIP,
                names.COMPOSITE_PROPERTY,
                names.MAPPER_PROPERTY,
                names.SYNONYM_PROPERTY,
                names.COLUMN_PROPERTY,
            }
            and func_type.args
        ):
            left_hand_explicit_type = get_proper_type(func_type.args[0])
        elif type_id is names.COLUMN and func_type.args:
            typeengine_arg = func_type.args[0]
            if isinstance(typeengine_arg, UnboundType):
                sym = api.lookup_qualified(typeengine_arg.name, typeengine_arg)
                if sym is not None and isinstance(sym.node, TypeInfo):
                    if names._has_base_type_id(sym.node, names.TYPEENGINE):
                        left_hand_explicit_type = UnionType(
                            [
                                infer._extract_python_type_from_typeengine(
                                    api, sym.node, []
                                ),
                                NoneType(),
                            ]
                        )
                    else:
                        util.fail(
                            api,
                            "Column type should be a TypeEngine "
                            "subclass not '{}'".format(sym.node.fullname),
                            func_type,
                        )

    if left_hand_explicit_type is None:
        # no type on the decorated function.  our option here is to
        # dig into the function body and get the return type, but they
        # should just have an annotation.
        msg = (
            "Can't infer type from @declared_attr on function '{}';  "
            "please specify a return type from this function that is "
            "one of: Mapped[<python type>], relationship[<target class>], "
            "Column[<TypeEngine>], MapperProperty[<python type>]"
        )
        util.fail(api, msg.format(stmt.var.name), stmt)

        left_hand_explicit_type = AnyType(TypeOfAny.special_form)

    left_node = NameExpr(stmt.var.name)
    left_node.node = stmt.var

    # totally feeling around in the dark here as I don't totally understand
    # the significance of UnboundType.  It seems to be something that is
    # not going to do what's expected when it is applied as the type of
    # an AssignmentStatement.  So do a feeling-around-in-the-dark version
    # of converting it to the regular Instance/TypeInfo/UnionType structures
    # we see everywhere else.
    if isinstance(left_hand_explicit_type, UnboundType):
        left_hand_explicit_type = get_proper_type(
            util._unbound_to_instance(api, left_hand_explicit_type)
        )

    left_node.node.type = api.named_type(
        "__sa_Mapped", [left_hand_explicit_type]
    )

    # this will ignore the rvalue entirely
    # rvalue = TempNode(AnyType(TypeOfAny.special_form))

    # rewrite the node as:
    # <attr> : Mapped[<typ>] =
    # _sa_Mapped._empty_constructor(lambda: <function body>)
    # the function body is maintained so it gets type checked internally
    column_descriptor = nodes.NameExpr("__sa_Mapped")
    column_descriptor.fullname = "sqlalchemy.orm.attributes.Mapped"
    mm = nodes.MemberExpr(column_descriptor, "_empty_constructor")

    arg = nodes.LambdaExpr(stmt.func.arguments, stmt.func.body)
    rvalue = CallExpr(
        mm,
        [arg],
        [nodes.ARG_POS],
        ["arg1"],
    )

    new_stmt = AssignmentStmt([left_node], rvalue)
    new_stmt.type = left_node.node.type

    cls_metadata.mapped_attr_names.append(
        (left_node.name, left_hand_explicit_type)
    )
    cls.defs.body[dec_index] = new_stmt