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, )
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)
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(), )
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
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, )