from typing import List, Protocol, Tuple class StrArgsToStr(Protocol): def __call__(self, *children: str) -> str: ... ClassArg = str|List[str]|Tuple[str, ...]|None def MakeAttrs(classes:ClassArg, id:str|None, attributes: dict[str, str | None]) -> str: if classes: attributes['class'] = " ".join(classes) if isinstance(classes, (list, tuple)) else classes if id: attributes['id'] = id attrList: List[str] = [""] for key, value in attributes.items(): if value: attrList.append(f'{key}="{value}"') return " ".join(attrList) def ElWrapped(name: str, classes:ClassArg = None, id:str|None = None, attrs: dict[str, str | None] = {}, children:ClassArg = ()) -> StrArgsToStr: def Wrapped(*children:str): return f'<{name}{MakeAttrs(classes, id, attrs)}>{" ".join(children)}' return Wrapped def ElInline(name: str, classes:ClassArg = None, id:str|None = None, attrs: dict[str, str | None] = {}) -> str: return f'<{name} {MakeAttrs(classes, id, attrs)}/>' def SimpleWrapped(name:str): def proxy(classes:ClassArg = None, id:str|None = None): return ElWrapped(name, classes, id) return proxy def SimpleInline(name:str): def proxy(classes:ClassArg = None, id:str|None = None): return ElInline(name, classes, id) return proxy def A(classes:ClassArg = None, id:str|None = None, href:str|None = None, target:str|None = None) -> StrArgsToStr: return ElWrapped("a", classes, id, {"href":href, "target":id}) def IMG(classes:ClassArg = None, id:str|None = None, src:str|None = None): return ElInline("img", classes, id, {"src":src}) DIV = SimpleWrapped("div") P = SimpleWrapped("P") BR = SimpleInline("br") HR = SimpleInline("hr") SPAN = SimpleWrapped("span") print( DIV(classes="outer") ( A(classes="CTA Orange", href="www.link")("click") ) )