html_compose.base_types
1import typing 2from functools import lru_cache 3from typing import Callable, Iterable, Mapping 4 5from . import util_funcs 6 7 8# Note: base_element actually does runtime checking via hasattr 9# This is for the type checker. 10@typing.runtime_checkable 11class _HasHtml(typing.Protocol): 12 def __html__(self) -> str: 13 """ 14 Return unsafe HTML string 15 """ 16 ... 17 18 19class ElementBase: 20 """ 21 Base class for all HTML elements 22 23 Defined here to avoid circular imports for Node definition 24 25 Implementers define: __init__, render, __html__ 26 27 See: BaseElement 28 """ 29 30 FLOAT_PRECISION = 3 # Used when marshalling child floats into strings 31 ATTR_CACHE_SIZE = ( 32 250 # Number of translated attributes to cache strings for 33 ) 34 35 def __init__(self): 36 raise NotImplementedError 37 38 def get_attr_join(self) -> Callable[[str, str], str]: 39 """ 40 Return join_attrs(key: str, value_trusted: str) function with lru cache 41 The returned function turns key, value into key="value" 42 """ 43 cls = self.__class__ 44 45 if hasattr(cls, "_join_lru_maxsize"): 46 live_size = cls._join_lru_maxsize # pyright: ignore[reportAttributeAccessIssue] 47 else: 48 cls._join_lru_maxsize = cls.ATTR_CACHE_SIZE # type: ignore[attr-defined] 49 live_size = None 50 51 if live_size != cls.ATTR_CACHE_SIZE: 52 cls.join_attrs = lru_cache(maxsize=cls.ATTR_CACHE_SIZE)( # type: ignore[attr-defined] 53 util_funcs.join_attrs 54 ) 55 56 return cls.join_attrs # type: ignore[attr-defined] 57 58 def render(self, parent=None) -> str: 59 return "".join(self.resolve(parent)) 60 61 def resolve(self, parent=None) -> Iterable[str]: 62 """ 63 Yield all html as a generator of strings 64 """ 65 raise NotImplementedError() 66 67 def __html__(self) -> str: 68 return self.render() 69 70 71# A node resolver is a callable that returns a Node, 72# possibly taking the calling element and parent element as arguments. 73NodeResolver = ( 74 Callable[[], "Node"] 75 | Callable[[ElementBase], "Node"] 76 | Callable[[ElementBase, ElementBase], "Node"] 77) 78 79# The Node type is a union of all possible types that can be rendered 80Node = ( 81 None # None will not be appended to the output children 82 | str # Text that needs to be escaped 83 | int # Integer that needs to be converted to str 84 | float # Float that needs to be converted to str 85 | bool # Boolean that needs to be converted to str - usually a mistake 86 | ElementBase # Base class for all HTML elements 87 | _HasHtml # Returns HTML that does not need escaping 88 | Iterable["Node"] 89 | NodeResolver 90) 91 92# These types are used for attribute values 93StrLike = str | float | int | bool 94Resolvable = ( 95 None 96 | StrLike 97 | Iterable[StrLike] 98 | Mapping[StrLike, bool] # key-value pairs which resolve if .value is True 99)
class
ElementBase:
20class ElementBase: 21 """ 22 Base class for all HTML elements 23 24 Defined here to avoid circular imports for Node definition 25 26 Implementers define: __init__, render, __html__ 27 28 See: BaseElement 29 """ 30 31 FLOAT_PRECISION = 3 # Used when marshalling child floats into strings 32 ATTR_CACHE_SIZE = ( 33 250 # Number of translated attributes to cache strings for 34 ) 35 36 def __init__(self): 37 raise NotImplementedError 38 39 def get_attr_join(self) -> Callable[[str, str], str]: 40 """ 41 Return join_attrs(key: str, value_trusted: str) function with lru cache 42 The returned function turns key, value into key="value" 43 """ 44 cls = self.__class__ 45 46 if hasattr(cls, "_join_lru_maxsize"): 47 live_size = cls._join_lru_maxsize # pyright: ignore[reportAttributeAccessIssue] 48 else: 49 cls._join_lru_maxsize = cls.ATTR_CACHE_SIZE # type: ignore[attr-defined] 50 live_size = None 51 52 if live_size != cls.ATTR_CACHE_SIZE: 53 cls.join_attrs = lru_cache(maxsize=cls.ATTR_CACHE_SIZE)( # type: ignore[attr-defined] 54 util_funcs.join_attrs 55 ) 56 57 return cls.join_attrs # type: ignore[attr-defined] 58 59 def render(self, parent=None) -> str: 60 return "".join(self.resolve(parent)) 61 62 def resolve(self, parent=None) -> Iterable[str]: 63 """ 64 Yield all html as a generator of strings 65 """ 66 raise NotImplementedError() 67 68 def __html__(self) -> str: 69 return self.render()
Base class for all HTML elements
Defined here to avoid circular imports for Node definition
Implementers define: __init__, render, __html__
See: BaseElement
def
get_attr_join(self) -> Callable[[str, str], str]:
39 def get_attr_join(self) -> Callable[[str, str], str]: 40 """ 41 Return join_attrs(key: str, value_trusted: str) function with lru cache 42 The returned function turns key, value into key="value" 43 """ 44 cls = self.__class__ 45 46 if hasattr(cls, "_join_lru_maxsize"): 47 live_size = cls._join_lru_maxsize # pyright: ignore[reportAttributeAccessIssue] 48 else: 49 cls._join_lru_maxsize = cls.ATTR_CACHE_SIZE # type: ignore[attr-defined] 50 live_size = None 51 52 if live_size != cls.ATTR_CACHE_SIZE: 53 cls.join_attrs = lru_cache(maxsize=cls.ATTR_CACHE_SIZE)( # type: ignore[attr-defined] 54 util_funcs.join_attrs 55 ) 56 57 return cls.join_attrs # type: ignore[attr-defined]
Return join_attrs(key: str, value_trusted: str) function with lru cache The returned function turns key, value into key="value"
NodeResolver =
typing.Union[typing.Callable[[], ForwardRef('Node')], typing.Callable[[ElementBase], ForwardRef('Node')], typing.Callable[[ElementBase, ElementBase], ForwardRef('Node')]]
Node =
typing.Union[NoneType, str, int, float, bool, ElementBase, html_compose.base_types._HasHtml, typing.Iterable[ForwardRef('Node')], typing.Callable[[], ForwardRef('Node')], typing.Callable[[ElementBase], ForwardRef('Node')], typing.Callable[[ElementBase, ElementBase], ForwardRef('Node')]]
StrLike =
str | float | int | bool
Resolvable =
typing.Union[NoneType, str, float, int, bool, typing.Iterable[str | float | int | bool], typing.Mapping[str | float | int | bool, bool]]