def emit_union(m: Module, item: Item, *, resolver: Resolver) -> Definition: typename = goname(item.type_.__name__) kind_typename = typename + "Kind" # type <typename> { # Kind string `json:"$kind"` # ... # } m.stmt(f"type {typename} struct {{") with m.scope(): m.stmt(f'Kind {kind_typename} `json:"$kind"` // discriminator') for subtype in item.args: gotype: str = resolver.resolve_gotype(subtype) m.append(f"{gotype} *{gotype}") m.stmt( f' `json:"{untitleize(str(gotype)).rstrip("_")},omitempty"`') m.stmt("}") m.sep() # UnmarshalJSON discriminator_field = ("$kind", typeinfo.typeinfo(str), metadata()) discriminator_field[-1]["_override_type"] = kind_typename pseudo_fields = [(sub_type.__name__, typeinfo.typeinfo(sub_type), metadata(required=False)) for sub_type in item.args] pseudo_item = Item( type_=item.type_, fields=[discriminator_field] + pseudo_fields, args=[], ) unmarshalJSON_definition = emit_unmarshalJSON(m, pseudo_item, resolver=resolver) m.sep() # one-of validation assert unmarshalJSON_definition.code_module is not None this = m.symbol(f"{item.type_.__name__[0].lower()}") maperr_pkg = m.import_("github.com/podhmo/maperr") sm = unmarshalJSON_definition.code_module sm.stmt("// one-of?") sm.stmt("{") with sm.scope(): for go_name, info, _ in pseudo_item.fields[1:]: with sm.if_( f'{this}.Kind == "{go_name}" && {this}.{go_name} == nil'): sm.stmt( f'err = err.Add("{go_name}", {maperr_pkg}.Message{{Text: "treated as {go_name}, but no data"}})' ) sm.stmt("}") # enums emit_enums(m, item.type_, resolver=resolver, name=kind_typename) definition = Definition(name=typename, code_module=None) return definition
**metadata: t.Optional[t.Any], ) -> None: pass m = Module() m.toplevel = m.submodule(import_unique=True) m.sep() spec = fnspec(f) with m.class_("F"): for name, typ, kind in spec.parameters: if typ.__module__ != "builtins": m.toplevel.import_(typ.__module__) info = typeinfo(typ) rhs = spec.type_str_of(info.normalized) if info.is_optional: rhs = LazyFormat("typing.Optional[{}]", rhs) if kind == "var_kw": rhs = LazyFormat("typing.Dict[str, {}]", rhs) elif kind == "var_args": rhs = LazyFormat("typing.List[{}]", rhs) elif kind == "kw_defaults" or kind == "args_defaults": rhs = LazyFormat("{} = {}", rhs, spec.default_of(name)) m.stmt("{}: {}", name, rhs) print(m)