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
« 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# ///////////////////////////////////////////////////////////////
6"""
7Table methods mixin for Rich Wizard.
9This module provides all table-related methods for the RichWizard class.
10"""
12from __future__ import annotations
14# ///////////////////////////////////////////////////////////////
15# IMPORTS
16# ///////////////////////////////////////////////////////////////
17# Standard library imports
18from typing import Any
20# Third-party imports
21from rich.console import Console
22from rich.table import Table
24# ///////////////////////////////////////////////////////////////
25# CLASSES
26# ///////////////////////////////////////////////////////////////
29class TableMixin:
30 """
31 Mixin providing table display methods for RichWizard.
33 This mixin adds all table-related functionality including
34 generic tables, status tables, dependency tables, and command tables.
35 """
37 # Type hints for attributes provided by RichWizard
38 _console: Console
40 # ///////////////////////////////////////////////////////////////
41 # TABLE METHODS
42 # ///////////////////////////////////////////////////////////////
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.
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
63 try:
64 table = Table(title=title, show_header=show_header, **kwargs)
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)
72 # Add rows
73 for row in data:
74 table.add_row(*[str(row.get(col, "")) for col in columns])
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
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.
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)
104 # Add columns
105 for column in columns:
106 table.add_column(column, style="cyan", no_wrap=True)
108 # Add rows
109 for row in rows:
110 table.add_row(*[str(cell) for cell in row])
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
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.
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
139 try:
140 # Get columns from first row
141 columns = list(data[0].keys())
143 table = Table(title=title, show_header=True, **kwargs)
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)
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)
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
180 def dependency_table(self, dependencies: dict[str, str]) -> None:
181 """
182 Display a table for displaying dependencies.
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)
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")
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
208 def command_table(self, commands: list[dict[str, str]]) -> None:
209 """
210 Display a table for displaying available commands.
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)
221 for cmd in commands:
222 table.add_row(
223 cmd.get("command", ""),
224 cmd.get("description", ""),
225 cmd.get("category", ""),
226 )
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