Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/markdown_it/utils.py: 38%

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

133 statements  

1from __future__ import annotations 

2 

3from collections.abc import Callable, Iterable, MutableMapping 

4from collections.abc import MutableMapping as MutableMappingABC 

5from pathlib import Path 

6from typing import TYPE_CHECKING, Any, TypedDict, cast 

7 

8if TYPE_CHECKING: 

9 from typing_extensions import NotRequired 

10 

11 

12EnvType = MutableMapping[str, Any] # note: could use TypeAlias in python 3.10 

13"""Type for the environment sandbox used in parsing and rendering, 

14which stores mutable variables for use by plugins and rules. 

15""" 

16 

17 

18class OptionsType(TypedDict): 

19 """Options for parsing.""" 

20 

21 maxNesting: int 

22 """Internal protection, recursion limit.""" 

23 html: bool 

24 """Enable HTML tags in source.""" 

25 linkify: bool 

26 """Enable autoconversion of URL-like texts to links.""" 

27 typographer: bool 

28 """Enable smartquotes and replacements.""" 

29 quotes: str 

30 """Quote characters.""" 

31 xhtmlOut: bool 

32 """Use '/' to close single tags (<br />).""" 

33 breaks: bool 

34 """Convert newlines in paragraphs into <br>.""" 

35 langPrefix: str 

36 """CSS language prefix for fenced blocks.""" 

37 highlight: Callable[[str, str, str], str] | None 

38 """Highlighter function: (content, lang, attrs) -> str.""" 

39 store_labels: NotRequired[bool] 

40 """Store link label in link/image token's metadata (under Token.meta['label']). 

41 

42 This is a Python only option, and is intended for the use of round-trip parsing. 

43 """ 

44 tasklists: NotRequired[bool] 

45 """Enable GFM task list checkbox detection in list items.""" 

46 alerts: NotRequired[bool] 

47 """Enable GitHub-style alert detection in blockquotes.""" 

48 tasklists_editable: NotRequired[bool] 

49 """When True, rendered task list checkboxes are interactive (no disabled attribute).""" 

50 strikethrough_single_tilde: NotRequired[bool] 

51 """Allow single tilde ``~text~`` for strikethrough in addition to double.""" 

52 

53 

54class PresetType(TypedDict): 

55 """Preset configuration for markdown-it.""" 

56 

57 options: OptionsType 

58 """Options for parsing.""" 

59 components: MutableMapping[str, MutableMapping[str, list[str]]] 

60 """Components for parsing and rendering.""" 

61 

62 

63class OptionsDict(MutableMappingABC): # type: ignore 

64 """A dictionary, with attribute access to core markdownit configuration options.""" 

65 

66 # Note: ideally we would probably just remove attribute access entirely, 

67 # but we keep it for backwards compatibility. 

68 

69 def __init__(self, options: OptionsType) -> None: 

70 self._options = cast(OptionsType, dict(options)) 

71 

72 def __getitem__(self, key: str) -> Any: 

73 return self._options[key] # type: ignore[literal-required] 

74 

75 def __setitem__(self, key: str, value: Any) -> None: 

76 self._options[key] = value # type: ignore[literal-required] 

77 

78 def __delitem__(self, key: str) -> None: 

79 del self._options[key] # type: ignore 

80 

81 def __iter__(self) -> Iterable[str]: # type: ignore 

82 return iter(self._options) 

83 

84 def __len__(self) -> int: 

85 return len(self._options) 

86 

87 def __repr__(self) -> str: 

88 return repr(self._options) 

89 

90 def __str__(self) -> str: 

91 return str(self._options) 

92 

93 @property 

94 def maxNesting(self) -> int: 

95 """Internal protection, recursion limit.""" 

96 return self._options["maxNesting"] 

97 

98 @maxNesting.setter 

99 def maxNesting(self, value: int) -> None: 

100 self._options["maxNesting"] = value 

101 

102 @property 

103 def html(self) -> bool: 

104 """Enable HTML tags in source.""" 

105 return self._options["html"] 

106 

107 @html.setter 

108 def html(self, value: bool) -> None: 

109 self._options["html"] = value 

110 

111 @property 

112 def linkify(self) -> bool: 

113 """Enable autoconversion of URL-like texts to links.""" 

114 return self._options["linkify"] 

115 

116 @linkify.setter 

117 def linkify(self, value: bool) -> None: 

118 self._options["linkify"] = value 

119 

120 @property 

121 def typographer(self) -> bool: 

122 """Enable smartquotes and replacements.""" 

123 return self._options["typographer"] 

124 

125 @typographer.setter 

126 def typographer(self, value: bool) -> None: 

127 self._options["typographer"] = value 

128 

129 @property 

130 def quotes(self) -> str: 

131 """Quote characters.""" 

132 return self._options["quotes"] 

133 

134 @quotes.setter 

135 def quotes(self, value: str) -> None: 

136 self._options["quotes"] = value 

137 

138 @property 

139 def xhtmlOut(self) -> bool: 

140 """Use '/' to close single tags (<br />).""" 

141 return self._options["xhtmlOut"] 

142 

143 @xhtmlOut.setter 

144 def xhtmlOut(self, value: bool) -> None: 

145 self._options["xhtmlOut"] = value 

146 

147 @property 

148 def breaks(self) -> bool: 

149 """Convert newlines in paragraphs into <br>.""" 

150 return self._options["breaks"] 

151 

152 @breaks.setter 

153 def breaks(self, value: bool) -> None: 

154 self._options["breaks"] = value 

155 

156 @property 

157 def langPrefix(self) -> str: 

158 """CSS language prefix for fenced blocks.""" 

159 return self._options["langPrefix"] 

160 

161 @langPrefix.setter 

162 def langPrefix(self, value: str) -> None: 

163 self._options["langPrefix"] = value 

164 

165 @property 

166 def highlight(self) -> Callable[[str, str, str], str] | None: 

167 """Highlighter function: (content, langName, langAttrs) -> escaped HTML.""" 

168 return self._options["highlight"] 

169 

170 @highlight.setter 

171 def highlight(self, value: Callable[[str, str, str], str] | None) -> None: 

172 self._options["highlight"] = value 

173 

174 

175def read_fixture_file(path: str | Path) -> list[list[Any]]: 

176 text = Path(path).read_text(encoding="utf-8") 

177 tests = [] 

178 section = 0 

179 last_pos = 0 

180 lines = text.splitlines(keepends=True) 

181 for i in range(len(lines)): 

182 if lines[i].rstrip() == ".": 

183 if section == 0: 

184 tests.append([i, lines[i - 1].strip()]) 

185 section = 1 

186 elif section == 1: 

187 tests[-1].append("".join(lines[last_pos + 1 : i])) 

188 section = 2 

189 elif section == 2: 

190 tests[-1].append("".join(lines[last_pos + 1 : i])) 

191 section = 0 

192 

193 last_pos = i 

194 return tests