Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/turbohtml/migration/stdlib.py: 94%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

32 statements  

1""" 

2An :class:`python:html.parser.HTMLParser`-shaped adapter over the streaming tokenizer. 

3 

4A drop-in base class for the many ``HTMLParser`` subclasses in the wild: subclass it, override the ``handle_*`` methods, 

5and call :meth:`~HTMLParser.feed`/:meth:`~HTMLParser.close` incrementally, exactly as with the standard library, but 

6over turbohtml's WHATWG-conformant tokenizer. Migrating is changing the import and the base class. 

7 

8It is kept apart from the core API (which exposes the token stream and the tree directly) so the drop-in surface stays 

9bounded. It differs from the standard library only where the standard library diverges from the WHATWG algorithm 

10browsers run: 

11 

12- Character references are always resolved (as ``convert_charrefs=True``), so :meth:`~HTMLParser.handle_data` receives 

13 decoded text and :meth:`~HTMLParser.handle_entityref`/:meth:`~HTMLParser.handle_charref` are never called. The 

14 ``convert_charrefs`` argument is accepted for signature compatibility but has no effect. 

15- A processing instruction reaches :meth:`~HTMLParser.handle_pi`. A CDATA section outside foreign content remains a 

16 comment, so :meth:`~HTMLParser.unknown_decl` is never called. 

17- A valueless attribute's value is the empty string rather than ``None`` (the tokenizer does not tell ``disabled`` 

18 apart from ``disabled=""``). 

19""" 

20 

21from __future__ import annotations 

22 

23from turbohtml._html import Tokenizer 

24 

25__all__ = ["HTMLParser"] 

26 

27 

28class HTMLParser: 

29 """ 

30 A subclass-and-override callback parser over the streaming tokenizer. 

31 

32 :param convert_charrefs: accepted for compatibility but ignored; references are always resolved. 

33 """ 

34 

35 convert_charrefs: bool 

36 """Accepted for compatibility; references are always resolved regardless of its value.""" 

37 

38 def __init__(self, *, convert_charrefs: bool = True) -> None: 

39 """Create a parser.""" 

40 self.convert_charrefs = convert_charrefs 

41 self._tokenizer = Tokenizer() 

42 

43 def feed(self, data: str) -> None: 

44 """ 

45 Feed a chunk of HTML, dispatching the tokens it completes to the handlers. 

46 

47 :param data: the next chunk of HTML. 

48 """ 

49 self._tokenizer.feed(data) 

50 self._tokenizer.dispatch(self) 

51 

52 def close(self) -> None: 

53 """Signal end of input, dispatching any tokens still buffered.""" 

54 self._tokenizer.close() 

55 self._tokenizer.dispatch(self) 

56 

57 def reset(self) -> None: 

58 """Discard the buffered input and position, ready to parse a new document.""" 

59 self._tokenizer.reset() 

60 

61 def getpos(self) -> tuple[int, int]: 

62 """ 

63 Report the source position of the last dispatched token. 

64 

65 :returns: the 1-based line and 0-based column of the token last dispatched. 

66 """ 

67 return self._tokenizer.position() 

68 

69 def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: 

70 """ 

71 Handle a start tag; override to act on it. 

72 

73 :param tag: the lowercased tag name. 

74 :param attrs: the (name, value) attribute pairs, a valueless attribute's value the empty string. 

75 """ 

76 

77 def handle_startendtag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: 

78 """ 

79 Handle a self-closing tag; by default fire start then end, like the standard library. 

80 

81 :param tag: the lowercased tag name. 

82 :param attrs: the (name, value) attribute pairs. 

83 """ 

84 self.handle_starttag(tag, attrs) 

85 self.handle_endtag(tag) 

86 

87 def handle_endtag(self, tag: str) -> None: 

88 """ 

89 Handle an end tag; override to act on it. 

90 

91 :param tag: the lowercased tag name. 

92 """ 

93 

94 def handle_data(self, data: str) -> None: 

95 """ 

96 Handle a run of text, with character references resolved. 

97 

98 :param data: the decoded text. 

99 """ 

100 

101 def handle_comment(self, data: str) -> None: 

102 """ 

103 Handle a comment (also CDATA outside foreign content). 

104 

105 :param data: the comment text, without the ``<!--`` ``-->`` delimiters. 

106 """ 

107 

108 def handle_decl(self, decl: str) -> None: 

109 """ 

110 Handle a ``<!DOCTYPE ...>`` declaration, with the leading ``<!`` and trailing ``>`` removed. 

111 

112 :param decl: the declaration text, such as ``DOCTYPE html``. 

113 """ 

114 

115 def handle_pi(self, data: str) -> None: 

116 """ 

117 Handle an instruction with its target and data joined by one space. 

118 

119 :param data: the target followed by data when present. 

120 """ 

121 

122 def handle_entityref(self, name: str) -> None: 

123 """ 

124 Handle a named reference; never called, since references are always resolved. 

125 

126 :param name: the entity name, without the ``&`` and ``;``. 

127 """ 

128 

129 def handle_charref(self, name: str) -> None: 

130 """ 

131 Handle a numeric reference; never called, since references are always resolved. 

132 

133 :param name: the numeric reference body, without the ``&#`` and ``;``. 

134 """ 

135 

136 def unknown_decl(self, data: str) -> None: 

137 """ 

138 Handle a CDATA section; never called, since it is a comment outside foreign content. 

139 

140 :param data: the section text. 

141 """