Beispiel #1
0
    def _field_from_field_def(self, stmt, lhs, call) -> Field:
        ctx = self._ctx
        type_arg = call.args[0]

        try:
            un_type = exprtotype.expr_to_unanalyzed_type(type_arg)
        except exprtotype.TypeTranslationError:
            ctx.api.fail('Cannot resolve schema field type', type_arg)
        else:
            ftype = ctx.api.anal_type(un_type)
            if ftype is None:
                raise DeferException

        is_optional = self._is_optional(call)
        if is_optional:
            ftype = types.UnionType.make_union(
                [ftype, types.NoneType()],
                line=ftype.line,
                column=ftype.column,
            )

        lhs.node.type = ftype

        return Field(
            name=lhs.name,
            is_optional=is_optional,
            line=stmt.line,
            column=stmt.column,
        )
Beispiel #2
0
    def _get_python_type_from_ovo_field_type(
        self,
        ctx: plugin.ClassDefContext,
        ovo_field_type_name: str,
        args: Dict[str, nodes.Expression],
    ) -> types.Type:

        try:
            field_symbol = ctx.api.lookup_fully_qualified_or_none(
                ovo_field_type_name)
            assert field_symbol is not None
            assert field_symbol.node is not None
            assert isinstance(field_symbol.node, nodes.TypeInfo)
            assert "MYPY_TYPE" in field_symbol.node.names
            assert field_symbol.node.names["MYPY_TYPE"] is not None
            assert isinstance(field_symbol.node.names["MYPY_TYPE"].node,
                              nodes.Var)
            assert field_symbol.node.names["MYPY_TYPE"].node.type is not None

            type = field_symbol.node.names["MYPY_TYPE"].node.type

            if "nullable" in args and ctx.api.parse_bool(args["nullable"]):
                return types.UnionType([type, types.NoneType()])

            return type
        except Exception as e:
            self.log("looking up %s got exception %s" %
                     (ovo_field_type_name, str(e)))

        # defaults to Any if the stub is incomplete
        return types.AnyType(types.TypeOfAny.implementation_artifact)
Beispiel #3
0
    def _synthesize_init(self, fields: List[Field]) -> None:
        ctx = self._ctx
        cls_info = ctx.cls.info

        # If our self type has placeholders (probably because of type
        # var bounds), defer. If we skip deferring and stick something
        # in our symbol table anyway, we'll get in trouble.  (Arguably
        # plugins.common ought to help us with this, but oh well.)
        self_type = mypy_helpers.fill_typevars(cls_info)
        if semanal.has_placeholder(self_type):
            raise DeferException

        if (
            (
                '__init__' not in cls_info.names
                or cls_info.names['__init__'].plugin_generated
            ) and fields
        ):
            mypy_helpers.add_method(
                ctx,
                '__init__',
                self_type=self_type,
                args=[field.to_argument() for field in fields],
                return_type=types.NoneType(),
            )
Beispiel #4
0
    def transform(self):
        ctx = self._ctx
        metadata = ctx.cls.info.metadata.get(METADATA_KEY)
        if not metadata:
            ctx.cls.info.metadata[METADATA_KEY] = metadata = {}

        metadata['processing'] = True

        if metadata.get('processed'):
            return

        try:
            fields = self._collect_fields()
            schema_t = self._lookup_type('edb.schema.schema.Schema')
        except DeferException:
            ctx.api.defer()
            return None

        cls_info = ctx.cls.info

        for f in fields:
            ftype = cls_info.get(f.name).type
            if ftype is None or cls_info.get(f'get_{f.name}') is not None:
                # The class is already doing something funny with the
                # field or the accessor, so ignore it.
                continue

            if f.is_optional:
                ftype = types.UnionType.make_union(
                    [ftype, types.NoneType()],
                    line=ftype.line,
                    column=ftype.column,
                )

            mypy_helpers.add_method(
                ctx,
                name=f'get_{f.name}',
                args=[
                    nodes.Argument(
                        variable=nodes.Var(
                            name='schema',
                            type=schema_t,
                        ),
                        type_annotation=schema_t,
                        initializer=None,
                        kind=nodes.ARG_POS,
                    ),
                ],
                return_type=ftype,
            )

        metadata['fields'] = {f.name: f.serialize() for f in fields}
        metadata['processed'] = True
Beispiel #5
0
    def _field_from_field_def(
        self,
        stmt: nodes.AssignmentStmt,
        name: nodes.NameExpr,
        sym: nodes.SymbolTableNode,
    ) -> Optional[Field]:
        ctx = self._ctx

        rhs = stmt.rvalue

        if isinstance(rhs, nodes.CastExpr):
            rhs = rhs.expr

        if not isinstance(rhs, nodes.CallExpr):
            return None

        fdef = rhs.callee

        ftype = None
        if (
            isinstance(fdef, nodes.IndexExpr)
            and isinstance(fdef.analyzed, nodes.TypeApplication)
        ):
            # Explicitly typed Field declaration
            ctor = fdef.analyzed.expr
            if len(fdef.analyzed.types) > 1:
                ctx.api.fail('too many type arguments to Field', fdef)
            ftype = fdef.analyzed.types[0]
        else:
            ctor = fdef
            ftype = None

        if (
            not isinstance(ctor, nodes.RefExpr)
            or ctor.fullname not in self._field_makers
        ):
            return None

        type_arg = rhs.args[0]

        deflt = self._get_default(rhs)

        if ftype is None:
            try:
                un_type = exprtotype.expr_to_unanalyzed_type(type_arg)
            except exprtotype.TypeTranslationError:
                ctx.api.fail('Cannot resolve schema field type', type_arg)
            else:
                ftype = ctx.api.anal_type(un_type)
            if ftype is None:
                raise DeferException

            is_optional = (
                isinstance(deflt, nodes.NameExpr)
                and deflt.fullname == 'builtins.None'
            )
            if is_optional:
                ftype = types.UnionType.make_union(
                    [ftype, types.NoneType()],
                    line=ftype.line,
                    column=ftype.column,
                )

        assert isinstance(name.node, nodes.Var)
        name.node.type = ftype

        return Field(
            name=name.name,
            has_explicit_accessor=self._has_explicit_field_accessor(name.name),
            has_default=deflt is not None,
            line=stmt.line,
            column=stmt.column,
            type=ftype,
        )