Exemple #1
0
    def visit_Lambda(self, n: ast3.Lambda) -> LambdaExpr:
        body = ast3.Return(n.body)
        body.lineno = n.lineno
        body.col_offset = n.col_offset

        e = LambdaExpr(self.transform_args(n.args, n.lineno),
                       self.as_required_block([body], n.lineno))
        e.set_line(
            n.lineno,
            n.col_offset)  # Overrides set_line -- can't use self.set_line
        return e
Exemple #2
0
    def visit_Lambda(self, n: ast27.Lambda) -> LambdaExpr:
        args, decompose_stmts = self.transform_args(n.args, n.lineno)

        n_body = ast27.Return(n.body)
        n_body.lineno = n.lineno
        n_body.col_offset = n.col_offset
        body = self.as_required_block([n_body], n.lineno)
        if decompose_stmts:
            body.body = decompose_stmts + body.body

        e = LambdaExpr(args, body)
        e.set_line(n.lineno, n.col_offset)  # Overrides set_line -- can't use self.set_line
        return e
Exemple #3
0
    def visit_Lambda(self, n: ast27.Lambda) -> LambdaExpr:
        args, decompose_stmts = self.transform_args(n.args, n.lineno)

        n_body = ast27.Return(n.body)
        n_body.lineno = n.lineno
        n_body.col_offset = n.col_offset
        body = self.as_required_block([n_body], n.lineno)
        if decompose_stmts:
            body.body = decompose_stmts + body.body

        e = LambdaExpr(args, body)
        e.set_line(n.lineno, n.col_offset)  # Overrides set_line -- can't use self.set_line
        return e
Exemple #4
0
    def visit_Lambda(self, n: ast3.Lambda) -> LambdaExpr:
        body = ast3.Return(n.body)
        body.lineno = n.lineno
        body.col_offset = n.col_offset

        return LambdaExpr(self.transform_args(n.args, n.lineno),
                          self.as_required_block([body], n.lineno))
Exemple #5
0
 def visit_lambda_expr(self, node: LambdaExpr) -> LambdaExpr:
     new = LambdaExpr([self.copy_argument(arg) for arg in node.arguments],
                      self.block(node.body),
                      cast(Optional[FunctionLike],
                           self.optional_type(node.type)))
     self.copy_function_attributes(new, node)
     return new
Exemple #6
0
    def visit_Lambda(self, n: ast27.Lambda) -> LambdaExpr:
        args, decompose_stmts = self.transform_args(n.args, n.lineno)

        n_body = ast27.Return(n.body)
        n_body.lineno = n.lineno
        n_body.col_offset = n.col_offset
        body = self.as_required_block([n_body], n.lineno)
        if decompose_stmts:
            body.body = decompose_stmts + body.body

        return LambdaExpr(args, body)
Exemple #7
0
 def visit_lambda_expr(self, node: LambdaExpr) -> None:
     node.info = self.fixup(node.info)
     super().visit_lambda_expr(node)
def _scan_declarative_decorator_stmt(
    cls: ClassDef,
    api: SemanticAnalyzerPluginInterface,
    stmt: Decorator,
    attributes: List[util.SQLAlchemyAttribute],
) -> 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 util.name_is_dunder(stmt.name):
        # for dunder names like __table_args__, __tablename__,
        # __mapper_args__ etc., rewrite these as simple assignment
        # statements; otherwise mypy doesn't like if the decorated
        # function has an annotation like ``cls: Type[Foo]`` because
        # it isn't @classmethod
        any_ = AnyType(TypeOfAny.special_form)
        left_node = NameExpr(stmt.var.name)
        left_node.node = stmt.var
        new_stmt = AssignmentStmt([left_node], TempNode(any_))
        new_stmt.type = left_node.node.type
        cls.defs.body[dec_index] = new_stmt
        return
    elif 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(names.NAMED_TYPE_SQLA_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
    rvalue = util.expr_to_mapped_constructor(
        LambdaExpr(stmt.func.arguments, stmt.func.body))

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

    attributes.append(
        util.SQLAlchemyAttribute(
            name=left_node.name,
            line=stmt.line,
            column=stmt.column,
            typ=left_hand_explicit_type,
            info=cls.info,
        ))
    cls.defs.body[dec_index] = new_stmt
Exemple #9
0
 def visit_lambda_expr(self, node: LambdaExpr) -> None:
     node.info = self.fixup(node.info)
     super().visit_lambda_expr(node)