posit-dev / py-htmltools

Tools for HTML generation and output
MIT License
19 stars 2 forks source link

Clean up types #51

Closed wch closed 1 year ago

wch commented 1 year ago

This PR cleans up types for Tag functions. This will reduce ambiguities in functions that call Tag functions, and simplifies the API a bit.

The biggest change is that, instead of a single TagChildArg type that encompasses both children and attribute dictionaries, it splits it into two types:

The Tag functions have a signature like:

def div(*args: TagChild | TagAttrs, **kwargs: TagAttrValue) -> Tag:
    ...

Note that TagAttrValue and TagAttrs are defined like this:

TagAttrValue = Union[str, float, bool, None]

TagAttrs = Dict[str, TagAttrValue]

With this change, functions which wrap Tag functions can be more specific about what they accept. For example, shiny.ui.input_text previously looked like this:

def input_text(id: str, label: TagChildArg):
    ...

Previously, when TagChildArg encompassed both children and attributes, then this allowed label to be an attribute dictionary (as in label={"class":"foo"}), which was incorrect. Now, since TagChild only encompasses children (and not attributes), the function signature accurately reflects what is really allowed.

If a wrapper function really wants to accept both children and attributes, it needs a signature that explicitly accepts both types:

def div_wrapper(*args: TagChild | TagAttrs):
    return div({"class":"wrapper"}, *args)

This PR also does the following: