Coverage for src / ezpl / handlers / wizard / tables.py: 76.12%

98 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-13 19:35 +0000

1# /////////////////////////////////////////////////////////////// 

2# EZPL - Wizard Tables Mixin 

3# Project: ezpl 

4# /////////////////////////////////////////////////////////////// 

5 

6""" 

7Table methods mixin for Rich Wizard. 

8 

9This module provides all table-related methods for the RichWizard class. 

10""" 

11 

12from __future__ import annotations 

13 

14# /////////////////////////////////////////////////////////////// 

15# IMPORTS 

16# /////////////////////////////////////////////////////////////// 

17# Standard library imports 

18from typing import Any 

19 

20# Third-party imports 

21from rich.console import Console 

22from rich.table import Table 

23 

24# /////////////////////////////////////////////////////////////// 

25# CLASSES 

26# /////////////////////////////////////////////////////////////// 

27 

28 

29class TableMixin: 

30 """ 

31 Mixin providing table display methods for RichWizard. 

32 

33 This mixin adds all table-related functionality including 

34 generic tables, status tables, dependency tables, and command tables. 

35 """ 

36 

37 # Type hints for attributes provided by RichWizard 

38 _console: Console 

39 

40 # /////////////////////////////////////////////////////////////// 

41 # TABLE METHODS 

42 # /////////////////////////////////////////////////////////////// 

43 

44 def table( 

45 self, 

46 data: list[dict[str, Any]], 

47 title: str | None = None, 

48 show_header: bool = True, 

49 **kwargs, 

50 ) -> None: 

51 """ 

52 Display a table from a list of dictionaries. 

53 

54 Args: 

55 data: list of dictionaries representing table rows 

56 title: Optional table title 

57 show_header: Whether to show column headers 

58 **kwargs: Additional Table arguments 

59 """ 

60 if not data: 

61 return 

62 

63 try: 

64 table = Table(title=title, show_header=show_header, **kwargs) 

65 

66 # Determine columns from first element 

67 if isinstance(data[0], dict): 67 ↛ 76line 67 didn't jump to line 76 because the condition on line 67 was always true

68 columns = list(data[0].keys()) 

69 for col in columns: 

70 table.add_column(col, style="cyan", no_wrap=False) 

71 

72 # Add rows 

73 for row in data: 

74 table.add_row(*[str(row.get(col, "")) for col in columns]) 

75 

76 self._console.print(table) 

77 except Exception as e: 

78 try: 

79 self._console.print(f"[red]Table error:[/red] {type(e).__name__}") 

80 except Exception as e: 

81 raise ValueError(f"Failed to display table: {e}") from e 

82 

83 def table_from_columns( 

84 self, 

85 title: str, 

86 columns: list[str], 

87 rows: list[list[Any]], 

88 show_header: bool = True, 

89 **kwargs, 

90 ) -> None: 

91 """ 

92 Display a table with explicit columns and rows. 

93 

94 Args: 

95 title: Table title 

96 columns: list of column names 

97 rows: list of row data (each row is a list of values) 

98 show_header: Whether to show column headers 

99 **kwargs: Additional Table arguments 

100 """ 

101 try: 

102 table = Table(title=title, show_header=show_header, **kwargs) 

103 

104 # Add columns 

105 for column in columns: 

106 table.add_column(column, style="cyan", no_wrap=True) 

107 

108 # Add rows 

109 for row in rows: 

110 table.add_row(*[str(cell) for cell in row]) 

111 

112 self._console.print(table) 

113 except Exception as e: 

114 try: 

115 self._console.print(f"[red]Table error:[/red] {type(e).__name__}") 

116 except Exception as e: 

117 raise ValueError(f"Failed to display table: {e}") from e 

118 

119 def status_table( 

120 self, 

121 title: str, 

122 data: list[dict[str, Any]], 

123 status_column: str = "Status", 

124 **kwargs, 

125 ) -> None: 

126 """ 

127 Display a status table with colored status indicators. 

128 

129 Args: 

130 title: Table title 

131 data: list of dictionaries representing table rows 

132 status_column: Name of the status column 

133 **kwargs: Additional Table arguments 

134 """ 

135 if not data: 135 ↛ 136line 135 didn't jump to line 136 because the condition on line 135 was never true

136 self.table([{"No data": ""}], title=title, **kwargs) 

137 return 

138 

139 try: 

140 # Get columns from first row 

141 columns = list(data[0].keys()) 

142 

143 table = Table(title=title, show_header=True, **kwargs) 

144 

145 # Add columns 

146 for column in columns: 

147 if column == status_column: 

148 table.add_column(column, style="bold", no_wrap=True) 

149 else: 

150 table.add_column(column, style="cyan", no_wrap=True) 

151 

152 # Add rows with status styling 

153 for row_data in data: 

154 row = [] 

155 for column in columns: 

156 value = str(row_data.get(column, "")) 

157 if column == status_column: 

158 value_lower = value.lower() 

159 if "success" in value_lower or "ok" in value_lower: 

160 row.append(f"✅ {value}") 

161 elif "error" in value_lower or "fail" in value_lower: 161 ↛ 163line 161 didn't jump to line 163 because the condition on line 161 was always true

162 row.append(f"❌ {value}") 

163 elif "warning" in value_lower: 

164 row.append(f"⚠️ {value}") 

165 else: 

166 row.append(f"ℹ️ {value}") 

167 else: 

168 row.append(value) 

169 table.add_row(*row) 

170 

171 self._console.print(table) 

172 except Exception as e: 

173 try: 

174 self._console.print( 

175 f"[red]Status table error:[/red] {type(e).__name__}" 

176 ) 

177 except Exception as e: 

178 raise ValueError(f"Failed to display status table: {e}") from e 

179 

180 def dependency_table(self, dependencies: dict[str, str]) -> None: 

181 """ 

182 Display a table for displaying dependencies. 

183 

184 Args: 

185 dependencies: Dictionary mapping tool names to versions 

186 """ 

187 try: 

188 table = Table(title="Dependencies", show_header=True) 

189 table.add_column("Tool", style="cyan", no_wrap=True) 

190 table.add_column("Version", style="green", no_wrap=True) 

191 table.add_column("Status", style="bold", no_wrap=True) 

192 

193 for tool, version in dependencies.items(): 

194 if version: 

195 table.add_row(tool, version, "✅ Available") 

196 else: 

197 table.add_row(tool, "N/A", "❌ Missing") 

198 

199 self._console.print(table) 

200 except Exception as e: 

201 try: 

202 self._console.print( 

203 f"[red]Dependency table error:[/red] {type(e).__name__}" 

204 ) 

205 except Exception as e: 

206 raise ValueError(f"Failed to display dependency table: {e}") from e 

207 

208 def command_table(self, commands: list[dict[str, str]]) -> None: 

209 """ 

210 Display a table for displaying available commands. 

211 

212 Args: 

213 commands: list of command dictionaries with keys: command, description, category 

214 """ 

215 try: 

216 table = Table(title="Available Commands", show_header=True) 

217 table.add_column("Command", style="cyan", no_wrap=True) 

218 table.add_column("Description", style="green") 

219 table.add_column("Category", style="yellow", no_wrap=True) 

220 

221 for cmd in commands: 

222 table.add_row( 

223 cmd.get("command", ""), 

224 cmd.get("description", ""), 

225 cmd.get("category", ""), 

226 ) 

227 

228 self._console.print(table) 

229 except Exception as e: 

230 try: 

231 self._console.print( 

232 f"[red]Command table error:[/red] {type(e).__name__}" 

233 ) 

234 except Exception as e: 

235 raise ValueError(f"Failed to display command table: {e}") from e