Esempio n. 1
0
 def walk_array(self, d, name):
     typ = self.walk(d["items"], name=name)
     name = go.goname(name)
     array = self.resolve_file(d).newtype(go.goname(name),
                                          type=typ.slice,
                                          comment=d.get("description"))
     if self.is_pointer(d):
         array = array.pointer
     return array
Esempio n. 2
0
def emit_enum(name, schema, m):
    typename = go.goname(name)
    m.stmt('// {} : {}'.format(typename, schema.get("description", "").split("\n", 1)[0]))
    m.stmt("type {} string".format(typename))
    m.sep()
    with m.const_group() as cm:
        for e in schema["enum"]:
            itemname = '{}{}{}'.format(
                typename, go.goname(e), "Reversed" if e.startswith("-") else ""
            )
            cm('// {} :'.format(itemname))
            cm('{} = "{}"'.format(itemname, e))
Esempio n. 3
0
def emit_enum(name, schema, m):
    typename = go.goname(name)
    m.stmt('// {} : {}'.format(typename,
                               schema.get("description", "").split("\n",
                                                                   1)[0]))
    m.stmt("type {} string".format(typename))
    m.sep()
    with m.const_group() as cm:
        for e in schema["enum"]:
            itemname = '{}{}{}'.format(typename, go.goname(e),
                                       "Reversed" if e.startswith("-") else "")
            cm('// {} :'.format(itemname))
            cm('{} = "{}"'.format(itemname, e))
Esempio n. 4
0
 def walk_object(self, d, name):
     name = go.goname(name)
     struct = self.resolve_file(d).struct(name,
                                          comment=d.get("description"))
     for name, prop in (d.get("properties") or {}).items():
         typ = self.walk(prop, name=name)
         if getattr(typ, "fullname", "") == struct.fullname:
             typ = typ.pointer
         struct.define_field(go.goname(name),
                             typ,
                             comment=prop.get("description"),
                             tag=self.resolve_tag(name))
     if self.is_pointer(d):
         struct = struct.pointer
     return struct
Esempio n. 5
0
def run() -> Module:
    r = get_resolver()
    m = Module(indent="\t")
    classes = [Person, Person2]

    for item in walk(classes):
        m.stmt(f"type {goname(item.cls.__name__)} struct {{")
        with m.scope():
            for name, typeinfo, _metadata in item.fields:
                metadata = t.cast(Metadata, _metadata)
                if metadata.get("default") == MISSING:
                    metadata.pop("default")

                try:
                    gotype = r.resolve_gotype(
                        typeinfo.normalized)  # todo: pointer
                except KeyError:
                    gotype = goname(typeinfo.normalized.__name__)

                if metadata.get("pointer", False):
                    gotype = f"*{gotype}"

                if metadata.get("inline", False):
                    m.append(gotype)
                else:
                    m.append(f"{goname(name)} {gotype}")

                if metadata:
                    m.stmt(f"  // {metadata}")
                else:
                    m.stmt("")

        m.stmt("}")
        m.sep()
    return m
Esempio n. 6
0
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
Esempio n. 7
0
 def walk_enum(self, d, typ, name):
     name = go.goname(name)
     enum = self.resolve_file(d).enum(name,
                                      typ,
                                      comment=d.get("description"))
     for x in d["enum"]:
         enum.define_member(x, x)
     return enum
Esempio n. 8
0
    def resolve_gotype(
        self, typ: t.Type[t.Any], *, _none_type: t.Type[t.Any] = type(None),
    ) -> str:
        """e.g. str -> 'string' """
        if hasattr(typ, "__origin__"):
            origin = typ.__origin__
            args = typing_get_args(typ)
            if origin == dict:
                k = self.resolve_gotype(args[0])
                v = self.resolve_gotype(args[1])
                return f"map[{k}]{v}"
            elif origin == list or origin == tuple:
                v = self.resolve_gotype(args[0])
                return f"[]{v}"
            elif origin == GoPointer or (
                origin == t.Union and len(args) == 2 and _none_type in args
            ):
                v = self.resolve_gotype(args[0])
                return f"*{v}"
            else:
                name = resolve_name_maybe(typ)
                if name is not None:
                    return name
                raise RuntimeError(f"unexpected origin {origin!r}")

        gotype = self.gotype_map.get(typ)
        if gotype is not None:
            return gotype

        pkg = get_gopackage(typ)
        prefix = ""
        if pkg is not None:
            prefix = f"{self.m.import_(pkg)}."

        py_clsname = getattr(typ, "__qualname__", typ.__name__)
        if (
            "<locals>" in py_clsname
        ):  # HACK: for the type defined in closure. (e.g. t.NewType)
            py_clsname = typ.__name__

        if "." in py_clsname:
            typename = "_".join([goname(x) for x in py_clsname.split(".")])
        else:
            typename = goname(py_clsname)
        return f"{prefix}{typename}"
Esempio n. 9
0
 def emit_object(self, d, name):
     m = self.m.submodule()
     structname = go.goname(name)
     m.comment("{} : {}".format(structname, d.get("description", "")))
     with m.type_(structname, "struct"):
         for name, prop in d["properties"].items():
             if "description" in prop:
                 m.comment("{} : {}".format(go.goname(name), prop.get("description", "")))
             if "$ref" in prop:
                 typename = self.emit_ref(prop["$ref"])
                 if self.nullable[prop["$ref"]]:
                     typename = "*{}".format(typename)
             else:
                 typename = self.resolve_type(prop)
                 if prop.get("x-nullable", False):
                     typename = "*{}".format(typename)
             m.stmt('{} {}{}`'.format(go.goname(name), typename, self.resolve_tag(name)))
     return structname
Esempio n. 10
0
 def emit_object(self, d, name):
     m = self.m.submodule()
     structname = go.goname(name)
     m.comment("{} :{}".format(structname, d.get("description", "")))
     with m.type_(structname, "struct"):
         for name, prop in d["properties"].items():
             if "description" in prop:
                 m.comment("{} :{}".format(go.goname(name),
                                           prop.get("description", "")))
             if "$ref" in prop:
                 typename = self.emit_ref(prop["$ref"])
                 if self.nullable[prop["$ref"]]:
                     typename = "*{}".format(typename)
             else:
                 typename = self.resolve_type(prop)
                 if prop.get("x-nullable", False):
                     typename = "*{}".format(typename)
             m.stmt('{} {}{}`'.format(go.goname(name), typename,
                                      self.resolve_tag(name)))
     return structname
Esempio n. 11
0
 def emit_array(self, d, name):
     m = self.m.submodule()
     arrname = go.goname(name)
     item = d["items"]
     if "$ref" in item:
         typename = self.emit_ref(item["$ref"])
     else:
         typename = self.resolve_type(item)
     m.comment("{} :{}".format(arrname, d.get("description", "")))
     m.stmt("type {} []{}".format(arrname, typename))
     m.sep()
     return arrname
Esempio n. 12
0
 def emit_array(self, d, name):
     m = self.m.submodule()
     arrname = go.goname(name)
     item = d["items"]
     if "$ref" in item:
         typename = self.emit_ref(item["$ref"])
     else:
         typename = self.resolve_type(item)
     m.comment("{} :{}".format(arrname, d.get("description", "")))
     m.stmt("type {} []{}".format(arrname, typename))
     m.sep()
     return arrname
Esempio n. 13
0
def emit_union(w: walker.Walker, item: walker.Item) -> runtime.Definition:
    m = w.m
    ctx = w.ctx
    resolver = w.resolver

    typename = goname(item.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
    pseudo_item = ctx.create_pseudo_item(item,
                                         discriminator_name=kind_typename)
    unmarshalJSON_definition = emit_unmarshalJSON(w, pseudo_item)
    m.sep()

    # one-of validation
    assert unmarshalJSON_definition.code_module is not None
    this = m.symbol(f"{item.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(w, item.type_, name=kind_typename)

    return runtime.Definition(name=typename, code_module=None)
Esempio n. 14
0
def emit_simple_type_definition(ctx: Context, cls: t.Type[t.Any], *, m=None) -> None:
    """
    e.g.
// Team ...
type Team struct {
      Name string `json:"name"`
      Members [][]Person `json:"members"`
}
    """
    m = m or ctx.m
    typename = goname(cls.__name__)
    m.stmt(f"// {typename} ...")
    m.stmt(f"type {typename} struct {{")
    with m.scope():
        for name, info, metata in ctx.w.for_type(cls).walk():
            m.stmt(f"""{goname(name)} {detect_gotype(info)} `json:"{name}"`""")
    m.stmt("}")
Esempio n. 15
0
def detect_gotype(info: typeinfo.TypeInfo) -> str:
    if isinstance(info, typeinfo.Container):
        if info.container in ("list", "tuple", "set"):
            assert len(info.args) == 1
            return f"[]{detect_gotype(info.args[0])}"
        elif info.container == "dict":
            assert len(info.args) == 2
            return f"map[{detect_gotype(info.args[0])}]{detect_gotype(info.args[1])}"
    else:  # Atom
        typ = info.underlying
        if issubclass(typ, str):
            return "string"
        elif issubclass(typ, bool):
            return "bool"
        elif issubclass(typ, int):
            return "int"  # todo: int64 or ... something
        elif issubclass(typ, float):
            return "float"
    return goname(info.normalized.__name__)
Esempio n. 16
0
    def write_parse_method(self, enum, file, m):
        fmt = m.import_("fmt")

        @file.func(goname("Parse" + titleize(enum.name)),
                   args=enum.type(enum.shortname),
                   returns=enum,
                   comment="parse",
                   nostore=True)
        def parse(m):
            s = enum.shortname
            with m.switch(s) as sw:
                for name, _, value, _ in enum.members.values():
                    with sw.case(tostring(value)):
                        sw.return_(enum.varname(name))
                with sw.default():
                    sw.stmt('panic({})'.format(
                        fmt.Sprintf(
                            "unexpected {} %v, in parse()".format(enum.name),
                            _noencoded(s))))
            return m

        self.writer.write_function(parse, file, m)
Esempio n. 17
0
def emit(classes: t.List[t.Type[t.Any]]) -> Module:
    m = gofile("main")
    r = get_resolver(m)

    for item in walk(classes):
        this = m.symbol(f"{item.type_.__name__[0].lower()}")
        this_type = f"{r.resolve_gotype(item.type_)}"
        this_type_pointer = f"*{this_type}"

        # func (ob *Ob) UnmarshalJSON(b []byte) error {
        b = m.symbol("b")
        m.stmt(
            f"func ({this} {this_type_pointer}) UnmarshalJSON({b} []byte) error {{"
        )
        with m.scope():

            # var err *maperr.Error
            err = m.symbol("err")
            maperr_pkg = m.import_("github.com/podhmo/maperr")
            m.stmt(f"var {err} *{maperr_pkg}.Error")
            m.sep()

            # var inner struct {
            #   ...
            # }
            m.stmt("// loading internal data")
            inner = m.symbol("inner")
            m.stmt(f"var {inner} struct {{")
            with m.scope():
                for name, typeinfo, metadata in item.fields:
                    if name.startswith("_"):
                        continue  # xxx:

                    gotype: str = r.resolve_gotype(typeinfo.raw)
                    m.append(f'{goname(name)} *{gotype} `json:"{name}"`')
                    m.stmt("// required" if metadata["required"] else "")
            m.stmt("}")

            # if rawErr := json.Unmarshal(b, &inner); rawErr != nil {
            # ...
            # }
            json_pkg = m.import_("encoding/json")
            raw_err = m.symbol("rawErr")
            with m.if_(
                    f"{raw_err} := {json_pkg}.Unmarshal(b, &{inner}); {raw_err} != nil"
            ):
                m.return_(err.addSummary(raw_err.Error()))
            m.sep()

            # if <field> != nil {
            #     ob.<field> = *<field>
            # } else {
            #     m.add(<field>, "required")
            # }
            m.stmt("// binding field value and required check")
            for name, typeinfo, metadata in item.fields:
                field = m.symbol(goname(name))
                with m.if_(f"{inner}.{field} != nil"):
                    m.stmt(f"{this}.{field} = *{inner}.{field}")
                if metadata["required"]:
                    with m.else_():
                        m.stmt(f'{err} = err.Add("{name}", "required")')
            m.sep()

            # return err.Untyped()
            m.return_(err.Untyped())
        m.stmt("}")
    return m
Esempio n. 18
0
 def enum(self, name, type, comment=None):
     name = goname(name)
     enum = Enum(name, file=self, type=type, comment=comment)
     self.enums[name] = enum
     return enum
Esempio n. 19
0
 def newtype(self, name, type, comment=None):
     name = goname(name)
     newtype = Newtype(name, file=self, type=type, comment=comment)
     self.newtypes[name] = newtype
     return newtype
Esempio n. 20
0
 def varname(self, name):
     return goname("{}{}".format(self.name, titleize(name)))
Esempio n. 21
0
def emit_unmarshalJSON(w: walker.Walker,
                       item: walker.Item) -> runtime.Definition:
    m = w.m
    ctx = w.ctx
    resolver = w.resolver

    this = m.symbol(f"{item.name[0].lower()}")
    this_type = f"{resolver.resolve_gotype(item.type_)}"
    this_type_pointer = f"*{this_type}"

    # func (ob *Ob) UnmarshalJSON(b []byte) error {
    b = m.symbol("b")
    m.stmt(
        f"func ({this} {this_type_pointer}) UnmarshalJSON({b} []byte) error {{"
    )
    with m.scope():

        # var err *maperr.Error
        err = m.symbol("err")
        maperr_pkg = m.import_("github.com/podhmo/maperr")
        m.stmt(f"var {err} *{maperr_pkg}.Error")
        m.sep()

        # var inner struct {
        #   ...
        # }
        m.stmt("// loading internal data")
        inner = m.symbol("inner")
        m.stmt(f"var {inner} struct {{")
        with m.scope():
            for name, info, metadata in item.fields:
                if name.startswith("_"):
                    continue  # xxx:

                raw_type = ctx.raw_type_map.get(info) or info.raw
                if has_reference(info):
                    json_pkg = m.import_("encoding/json")
                    gotype = str(json_pkg.RawMessage)
                else:
                    gotype = resolver.resolve_gotype(raw_type)

                m.append(f'{goname(name)} *{gotype} `json:"{name}"`')
                m.stmt("// required" if metadata["required"] else "")
        m.stmt("}")

        # if rawErr := json.Unmarshal(b, &inner); rawErr != nil {
        # ...
        # }
        json_pkg = m.import_("encoding/json")
        raw_err = m.symbol("rawErr")
        with m.if_(
                f"{raw_err} := {json_pkg}.Unmarshal(b, &{inner}); {raw_err} != nil"
        ):
            m.return_(err.AddSummary(raw_err.Error()))
        m.sep()

        # if <field> != nil {
        #     ob.<field> = *<field>
        # } else {
        #     m.add(<field>, "required")
        # }
        rawerr = m.symbol("rawerr")
        m.stmt("// binding field value and required check")
        with m.block():
            for name, info, metadata in item.fields:
                field = m.symbol(goname(name))
                with m.if_(f"{inner}.{field} != nil"):
                    if has_reference(info):
                        if info.is_optional or info in ctx.raw_type_map:  # pointer
                            raw_type = ctx.raw_type_map.get(info) or info.raw
                            level = max(1, _unwrap_pointer_type(raw_type)[1])
                            gotype = resolver.resolve_gotype(info.type_)

                            # NOTE: tricky code
                            #
                            # when *X   (1 level), generated code:
                            #     ob.<attr> = &X{}
                            # when **X  (2 level), generated code:
                            #     v0 := &X{}
                            #     ob.<attr> = &v0
                            # when ***X (3 level), generated code:
                            #     v0 := &X{}
                            #     v1 := &v0
                            #     ob.<attr> = &v1
                            syms = [(":=", f"{gotype}{{}}")]
                            for i in range(level - 1):
                                syms.append((":=", f"v{i}"))
                            syms.append(("=", f"{this}.{goname(name)}"))
                            for i in range(1, len(syms)):
                                _, rhs = syms[i - 1]
                                op, lhs = syms[i]
                                m.stmt(f"{lhs} {op} &{rhs}")

                            ref = f"{this}.{field}"
                        elif (info.is_container and info.args
                              and info.container_type != "union"):
                            gotype = resolver.resolve_gotype(info.type_)
                            m.stmt(f"{this}.{goname(name)} = {gotype}{{}}")
                            ref = f"&{this}.{field}"
                        else:
                            ref = f"&{this}.{field}"

                        with m.if_(
                                f"{rawerr} := json.Unmarshal(*{inner}.{field}, {ref}); {rawerr} != nil"
                        ):
                            m.stmt(
                                f'{err} = {err}.Add("{name}", {maperr_pkg}.Message{{Error: {rawerr}}})'
                            )
                    else:
                        m.stmt(f"{this}.{field} = *{inner}.{field}")
                if metadata["required"]:
                    with m.else_():
                        m.stmt(
                            f'{err} = err.Add("{name}", {maperr_pkg}.Message{{Text: "required"}})'
                        )
        m.sep()

        # NOTE: for injecting code from extrnal area
        code_module = m.submodule("", newline=False)

        # return err.Untyped()
        m.return_(err.Untyped())

    m.stmt("}")
    return runtime.Definition(name="UnmarshalJSON", code_module=code_module)
Esempio n. 22
0
def emit_unmarshalJSON(m: Module, item: Item, *,
                       resolver: Resolver) -> Definition:
    this = m.symbol(f"{item.type_.__name__[0].lower()}")
    this_type = f"{resolver.resolve_gotype(item.type_)}"
    this_type_pointer = f"*{this_type}"

    # func (ob *Ob) UnmarshalJSON(b []byte) error {
    b = m.symbol("b")
    m.stmt(
        f"func ({this} {this_type_pointer}) UnmarshalJSON({b} []byte) error {{"
    )
    with m.scope():

        # var err *maperr.Error
        err = m.symbol("err")
        maperr_pkg = m.import_("github.com/podhmo/maperr")
        m.stmt(f"var {err} *{maperr_pkg}.Error")
        m.sep()

        # var inner struct {
        #   ...
        # }
        m.stmt("// loading internal data")
        inner = m.symbol("inner")
        m.stmt(f"var {inner} struct {{")
        with m.scope():
            for name, info, metadata in item.fields:
                if name.startswith("_"):
                    continue  # xxx:

                if "_override_type" in metadata:
                    gotype: str = metadata["_override_type"]
                elif has_class_object(info):
                    json_pkg = m.import_("encoding/json")
                    gotype: str = str(json_pkg.RawMessage)
                else:
                    gotype: str = resolver.resolve_gotype(info.raw)

                m.append(f'{goname(name)} *{gotype} `json:"{name}"`')
                m.stmt("// required" if metadata["required"] else "")
        m.stmt("}")

        # if rawErr := json.Unmarshal(b, &inner); rawErr != nil {
        # ...
        # }
        json_pkg = m.import_("encoding/json")
        raw_err = m.symbol("rawErr")
        with m.if_(
                f"{raw_err} := {json_pkg}.Unmarshal(b, &{inner}); {raw_err} != nil"
        ):
            m.return_(err.AddSummary(raw_err.Error()))
        m.sep()

        # if <field> != nil {
        #     ob.<field> = *<field>
        # } else {
        #     m.add(<field>, "required")
        # }
        rawerr = m.symbol("rawerr")
        m.stmt("// binding field value and required check")
        with m.block():
            for name, info, metadata in item.fields:
                field = m.symbol(goname(name))
                with m.if_(f"{inner}.{field} != nil"):
                    if has_class_object(info):
                        # pointer
                        if info.is_optional:
                            gotype: str = resolver.resolve_gotype(
                                info.normalized)
                            m.stmt(f"{this}.{goname(name)} = &{gotype}{{}}")
                            ref = f"{this}.{field}"
                        elif hasattr(info, "args"):  # xxx
                            gotype: str = resolver.resolve_gotype(
                                info.normalized)
                            m.stmt(f"{this}.{goname(name)} = {gotype}{{}}")
                            ref = f"&{this}.{field}"
                        else:
                            ref = f"&{this}.{field}"

                        with m.if_(
                                f"{rawerr} := json.Unmarshal(*{inner}.{field}, {ref}); {rawerr} != nil"
                        ):
                            m.stmt(
                                f'{err} = {err}.Add("{name}", {maperr_pkg}.Message{{Error: {rawerr}}})'
                            )
                    else:
                        m.stmt(f"{this}.{field} = *{inner}.{field}")
                if metadata["required"]:
                    with m.else_():
                        m.stmt(
                            f'{err} = err.Add("{name}", {maperr_pkg}.Message{{Text: "required"}})'
                        )
        m.sep()

        # NOTE: for injecting code from extrnal area
        code_module = m.submodule("", newline=False)

        # return err.Untyped()
        m.return_(err.Untyped())

    m.stmt("}")
    return Definition(name="UnmarshalJSON", code_module=code_module)
Esempio n. 23
0
        # if rawErr := json.Unmarshal(b, &inner); rawErr != nil {
        # ...
        # }
        json_pkg = m.import_("encoding/json")
        raw_err = m.symbol("rawErr")
        with m.if_(
                f"{raw_err} := {json_pkg}.Unmarshal(b, &{inner}); {raw_err} != nil"
        ):
            m.return_(err.addSummary(raw_err.Error()))
        m.sep()

        # if <field> != nil {
        #     ob.<field> = *<field>
        # } else {
        #     m.add(<field>, "required")
        # }
        m.stmt("// binding field value and required check")
        for name, typeinfo, metadata in item.fields:
            field = m.symbol(goname(name))
            with m.if_(f"{field} != nil"):
                m.stmt(f"{this}.{field} = *{field}")
            with m.else_():
                m.stmt(f'{err} = err.Add("{name}", "required")')
        m.sep()

        # return err.Untyped()
        m.return_(err.Untyped())
    m.stmt("}")
print(m)