"""Python object representations of HTML.""" from abc import ABC from dataclasses import dataclass import flask class HTMLElement(ABC): """Base class for an HTML element.""" def __init__(self, content: str, **attrs: str) -> None: """Initialize the class. Args: content (str): The content inside the HTML tag. attrs (str): The attributes of tag. """ self.content = content self.attrs = attrs def stringify_attrs(self) -> str: """Generate a string version of the tags attributes. Returns: str: A string in the form of attr1="value1" attr2="value2" """ return " ".join(f'{name}="{value}"' for name, value in self.attrs.items()) def __str__(self) -> str: """Generates an HTML representation of the tag.""" attr_text = self.stringify_attrs() return ( f"<{self.tagname}{' ' + attr_text if attr_text else ''}>{self.content}" f"{self.tagname}>" ) class Paragraph(HTMLElement): """Represents a Paragraph (p) tag.""" tagname = "p" class Link(HTMLElement): """Represents a Link (a) tag.""" tagname = "a" def __init__(self, content: str, href: str, **attrs: str) -> None: """Initialize the class. Args: content (str): The content of the link tag. href (str): The href attribute, where the link points to. attrs (str): Any additional attributes of the tag. """ super().__init__(content, **{"href": href, **attrs}) class Page(flask.Response): """Represents an HTML page.""" def __init__(self, title: str = None, head: str = "", body: str = "") -> None: """Initialize the class. Args: title (str): The title of the page. If not provided no title tag will be sent. head (str): The HTML to put in the head of the page. Defaults to nothing. body (str): The HTML to put in the body of the page. Defaults to nothing. """ self.title = title self.head = head self.body = body title_html = f"