1+ import typing as t
12from dataclasses import dataclass , field
3+ from types import MappingProxyType
24
35from markupsafe import escape
46
3133# FUTURE: make nodes frozen (and have the parser work with mutable builders)
3234
3335
34- @dataclass (slots = True )
36+ @dataclass (slots = True , frozen = True )
3537class Node :
3638 def __html__ (self ) -> str :
3739 """Return the HTML representation of the node."""
3840 # By default, just return the string representation
3941 return str (self )
4042
4143
42- @dataclass (slots = False )
44+ @dataclass (slots = True , frozen = True )
4345class Text (Node ):
4446 text : str
4547
@@ -48,35 +50,37 @@ def __str__(self) -> str:
4850 return escape (self .text )
4951
5052
51- @dataclass (slots = True )
53+ @dataclass (slots = True , frozen = True )
5254class Fragment (Node ):
53- children : list [Node ] = field (default_factory = list )
55+ children : t . Sequence [Node ] = field (default_factory = tuple )
5456
5557 def __str__ (self ) -> str :
5658 return "" .join (str (child ) for child in self .children )
5759
5860
59- @dataclass (slots = True )
61+ @dataclass (slots = True , frozen = True )
6062class Comment (Node ):
6163 text : str
6264
6365 def __str__ (self ) -> str :
6466 return f"<!--{ self .text } -->"
6567
6668
67- @dataclass (slots = True )
69+ @dataclass (slots = True , frozen = True )
6870class DocumentType (Node ):
6971 text : str = "html"
7072
7173 def __str__ (self ) -> str :
7274 return f"<!DOCTYPE { self .text } >"
7375
7476
75- @dataclass (slots = True )
77+ @dataclass (slots = True , frozen = True )
7678class Element (Node ):
7779 tag : str
78- attrs : dict [str , str | None ] = field (default_factory = dict )
79- children : list [Node ] = field (default_factory = list )
80+ attrs : t .Mapping [str , str | None ] = field (
81+ default_factory = lambda : MappingProxyType ({})
82+ )
83+ children : t .Sequence [Node ] = field (default_factory = tuple )
8084
8185 def __post_init__ (self ):
8286 """Ensure all preconditions are met."""
0 commit comments