def create_pseudo_item(self, item: Item, *, discriminator_name: str) -> Item: pseudo_item = self.pseudo_item_map.get(item.type_) if pseudo_item is not None: return pseudo_item discriminator_field = ( "$kind", typeinfo.typeinfo(t.NewType(discriminator_name, str)), metadata_.metadata(), ) pseudo_fields = [ ( sub_type.__name__, typeinfo.typeinfo(t.Optional[sub_type]), # type:ignore metadata_.metadata(required=False), ) for sub_type in item.args ] pseudo_item = Item( name=item.name, type_=item.type_, fields=[discriminator_field] + pseudo_fields, args=[], ) self.pseudo_item_map[item.type_] = pseudo_item # hack: temporary self.pseudo_item_map[_option_type(item.type_)] = dataclasses.replace( pseudo_item, name=f"*{pseudo_item.name}", type_=t.Optional[item.type_]) return pseudo_item
def resolve_typeinfo(self, typ: MemberOrRef) -> typeinfo.TypeInfo: # TODO: support _ForwardRef default = self.config.typeinfo_unexpected_handler try: if hasattr(typ, "__forward_arg__"): raise NotImplementedError("ForwardRef is not supported yet") v = t.cast(t.Type[t.Any], typ) return typeinfo.typeinfo(v, default=default) except TypeError: return typeinfo.typeinfo(typ.__class__, default=default)
def type_string(self, typ: t.Type[t.Any]) -> str: """ >>> TypeStringPrinter().type_string(str) 'str' >>> TypeStringPrinter().type_string(int) 'int' >>> import typing >>> TypeStringPrinter().type_string(typing.Optional[int]) 'int?' >>> TypeStringPrinter().type_string(typing.List) 'list[Any]' >>> TypeStringPrinter().type_string(typing.List[str]) 'list[str]' >>> TypeStringPrinter().type_string(typing.List[typing.List[str]]) 'list[list[str]]' >>> TypeStringPrinter().type_string(typing.List[typing.Optional[str]]) 'list[str?]' >>> TypeStringPrinter().type_string(typing.Optional[typing.List[str]]) 'list[str]?' >>> TypeStringPrinter().type_string(typing.Dict[str, int]) 'dict[str, int]' >>> TypeStringPrinter().type_string(typing.Dict[str, typing.Set[int]]) 'dict[str, set[int]]' >>> class A: pass; >>> TypeStringPrinter().type_string(A) 'A' >>> TypeStringPrinter().type_string(t.Optional[A]) 'A?' """ return self._type_string(typeinfo(typ))
def resolve_schema(self, typ: t.Type[t.Any]) -> t.Dict[str, t.Any]: from metashape.outputs.openapi import detect from metashape.typeinfo import typeinfo if typ is _nonetype: return {} if hasattr(typ, "asdict"): return typ.asdict() info = typeinfo(typ, default=handle_unexpected_type) schema_type = detect.schema_type(info) # TODO: support dict, oneOf,anyOf,allOf if schema_type == "array": return { "type": "array", "items": self.refs[info.user_defined_type], } elif schema_type == "object": return self.refs[typ] else: prop = {"type": schema_type} if info.is_newtype: if hasattr(info.supertypes[0], "__name__"): prop["format"] = info.supertypes[0].__name__.replace( "_", "-") return prop
def handle_unexpected_type(typ: t.Type[t.Any]) -> TypeInfo: from metashape.typeinfo import typeinfo origin = t.get_origin(typ) if hasattr(origin, "__emit__"): # for Query return typeinfo(t.get_args(typ)[0]) raise ValueError(f"unsupported type {typ}")
def _unwrap_type( typ: t.Type[t.Any], *, _unwrap_origins: t.Tuple[t.Type[t.Any], ...] = (dict, list, set, tuple), ) -> t.Type[t.Any]: if hasattr(typ, "__origin__") and typ.__origin__ in _unwrap_origins: return typeinfo(typ).user_defined_type or typ return typ
def resolve_schema(self, typ: t.Type[t.Any]) -> t.Dict[str, t.Any]: from metashape.outputs.openapi import detect from metashape.typeinfo import typeinfo info = typeinfo(typ) schema_type = detect.schema_type(info) # TODO: support dict, oneOf,anyOf,allOf if schema_type == "array": return { "type": "array", "items": self.refs[info.user_defined_type], } else: return self.refs[typ]
def resolve_pytype_str(self, typ: t.Type[t.Any], *, nonetype: t.Type[t.Any] = type(None)) -> Symbol: if typ.__module__ == "builtins": if typ.__name__ == "NoneType": return "None" else: return Symbol(typ.__name__) info = typeinfo(typ) if info.is_optional: return Symbol(f"t.Optional[{self.resolve_pytype_str(info.type_)}]") elif info.is_newtype: mod = self.resolve_module(info.raw) sym = self.m.toplevel.from_(mod).import_(info.raw.__name__) return sym raise NotImplementedError(typ)
def type_string( typ: t.Type[t.Any], to_str: t.Optional[t.Callable[TypeInfo], str] = None ) -> str: """ >>> type_string(str) 'str' >>> type_string(int) 'int' >>> import typing >>> type_string(typing.Optional[int]) 'int?' >>> type_string(typing.List) 'list[Any]' >>> type_string(typing.List[str]) 'list[str]' >>> type_string(typing.List[typing.List[str]]) 'list[list[str]]' >>> type_string(typing.List[typing.Optional[str]]) 'list[str?]' >>> type_string(typing.Optional[typing.List[str]]) 'list[str]?' >>> type_string(typing.Dict[str, int]) 'dict[str, int]' >>> type_string(typing.Dict[str, typing.Set[int]]) 'dict[str, set[int]]' >>> class A: pass; >>> type_string(A) 'A' >>> type_string(t.Optional[A]) 'A?' """ return _type_string(typeinfo(typ), to_str=to_str or _to_str_default)
def _typeinfo_on_default(raw_type: t.Type[t.Any]) -> typeinfo.TypeInfo: typ, _ = _unwrap_pointer_type(raw_type) resolved = typeinfo.typeinfo(typ) self.raw_type_map[resolved] = raw_type return resolved
def test_enum(input, want): from metashape.outputs.openapi.detect import enum as callFUT info = typeinfo.typeinfo(input) got = callFUT(info) assert got == want