Coverage for C:\Repos\ekr-pylint\pylint\reporters\ureports\nodes.py: 40%

75 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-24 10:21 -0500

1# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html 

2# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE 

3# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt 

4 

5"""Micro reports objects. 

6 

7A micro report is a tree of layout and content objects. 

8""" 

9 

10from __future__ import annotations 

11 

12from collections.abc import Iterable, Iterator 

13from typing import Any, Callable, TypeVar 

14 

15from pylint.reporters.ureports.base_writer import BaseWriter 

16 

17_T = TypeVar("_T") 

18_VNodeT = TypeVar("_VNodeT", bound="VNode") 

19VisitLeaveFunction = Callable[[_T, Any, Any], None] 

20 

21 

22class VNode: 

23 def __init__(self) -> None: 

24 self.parent: BaseLayout | None = None 

25 self.children: list[VNode] = [] 

26 self.visitor_name: str = self.__class__.__name__.lower() 

27 

28 def __iter__(self) -> Iterator[VNode]: 

29 return iter(self.children) 

30 

31 def accept(self: _VNodeT, visitor: BaseWriter, *args: Any, **kwargs: Any) -> None: 

32 func: VisitLeaveFunction[_VNodeT] = getattr( 

33 visitor, f"visit_{self.visitor_name}" 

34 ) 

35 return func(self, *args, **kwargs) 

36 

37 def leave(self: _VNodeT, visitor: BaseWriter, *args: Any, **kwargs: Any) -> None: 

38 func: VisitLeaveFunction[_VNodeT] = getattr( 

39 visitor, f"leave_{self.visitor_name}" 

40 ) 

41 return func(self, *args, **kwargs) 

42 

43 

44class BaseLayout(VNode): 

45 """Base container node. 

46 

47 attributes 

48 * children : components in this table (i.e. the table's cells) 

49 """ 

50 

51 def __init__(self, children: Iterable[Text | str] = ()) -> None: 

52 super().__init__() 

53 for child in children: 

54 if isinstance(child, VNode): 

55 self.append(child) 

56 else: 

57 self.add_text(child) 

58 

59 def append(self, child: VNode) -> None: 

60 """Add a node to children.""" 

61 assert child not in self.parents() 

62 self.children.append(child) 

63 child.parent = self 

64 

65 def insert(self, index: int, child: VNode) -> None: 

66 """Insert a child node.""" 

67 self.children.insert(index, child) 

68 child.parent = self 

69 

70 def parents(self) -> list[BaseLayout]: 

71 """Return the ancestor nodes.""" 

72 assert self.parent is not self 

73 if self.parent is None: 

74 return [] 

75 return [self.parent] + self.parent.parents() 

76 

77 def add_text(self, text: str) -> None: 

78 """Shortcut to add text data.""" 

79 self.children.append(Text(text)) 

80 

81 

82# non container nodes ######################################################### 

83 

84 

85class Text(VNode): 

86 """A text portion. 

87 

88 attributes : 

89 * data : the text value as an encoded or unicode string 

90 """ 

91 

92 def __init__(self, data: str, escaped: bool = True) -> None: 

93 super().__init__() 

94 self.escaped = escaped 

95 self.data = data 

96 

97 

98class VerbatimText(Text): 

99 """A verbatim text, display the raw data. 

100 

101 attributes : 

102 * data : the text value as an encoded or unicode string 

103 """ 

104 

105 

106# container nodes ############################################################# 

107 

108 

109class Section(BaseLayout): 

110 """A section. 

111 

112 attributes : 

113 * BaseLayout attributes 

114 

115 a title may also be given to the constructor, it'll be added 

116 as a first element 

117 a description may also be given to the constructor, it'll be added 

118 as a first paragraph 

119 """ 

120 

121 def __init__( 

122 self, 

123 title: str | None = None, 

124 description: str | None = None, 

125 children: Iterable[Text | str] = (), 

126 ) -> None: 

127 super().__init__(children=children) 

128 if description: 

129 self.insert(0, Paragraph([Text(description)])) 

130 if title: 

131 self.insert(0, Title(children=(title,))) 

132 self.report_id: str = "" # Used in ReportHandlerMixin.make_reports 

133 

134 

135class EvaluationSection(Section): 

136 def __init__(self, message: str, children: Iterable[Text | str] = ()) -> None: 

137 super().__init__(children=children) 

138 title = Paragraph() 

139 title.append(Text("-" * len(message))) 

140 self.append(title) 

141 message_body = Paragraph() 

142 message_body.append(Text(message)) 

143 self.append(message_body) 

144 

145 

146class Title(BaseLayout): 

147 """A title. 

148 

149 attributes : 

150 * BaseLayout attributes 

151 

152 A title must not contain a section nor a paragraph! 

153 """ 

154 

155 

156class Paragraph(BaseLayout): 

157 """A simple text paragraph. 

158 

159 attributes : 

160 * BaseLayout attributes 

161 

162 A paragraph must not contains a section ! 

163 """ 

164 

165 

166class Table(BaseLayout): 

167 """Some tabular data. 

168 

169 attributes : 

170 * BaseLayout attributes 

171 * cols : the number of columns of the table (REQUIRED) 

172 * rheaders : the first row's elements are table's header 

173 * cheaders : the first col's elements are table's header 

174 * title : the table's optional title 

175 """ 

176 

177 def __init__( 

178 self, 

179 cols: int, 

180 title: str | None = None, 

181 rheaders: int = 0, 

182 cheaders: int = 0, 

183 children: Iterable[Text | str] = (), 

184 ) -> None: 

185 super().__init__(children=children) 

186 assert isinstance(cols, int) 

187 self.cols = cols 

188 self.title = title 

189 self.rheaders = rheaders 

190 self.cheaders = cheaders