Coverage for silkaj/tui.py: 98%
53 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-22 12:04 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-22 12:04 +0000
1# Copyright 2016-2025 Maël Azimi <m.a@moul.re>
2#
3# Silkaj is free software: you can redistribute it and/or modify
4# it under the terms of the GNU Affero General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# Silkaj is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU Affero General Public License for more details.
12#
13# You should have received a copy of the GNU Affero General Public License
14# along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
16import shutil
17import sys
18from typing import Optional
20import rich_click as click
21from texttable import Texttable
23from silkaj import constants
25VERT_TABLE_CHARS = ["─", "│", "│", "═"]
28def send_doc_confirmation(document_name: str) -> None:
29 if not click.confirm(f"Do you confirm sending this {document_name}?"):
30 sys.exit(constants.SUCCESS_EXIT_STATUS)
33class Table(Texttable):
34 def __init__(
35 self,
36 style="default",
37 ):
38 super().__init__(max_width=shutil.get_terminal_size().columns)
40 if style == "columns":
41 self.set_deco(self.HEADER | self.VLINES | self.BORDER)
42 self.set_chars(VERT_TABLE_CHARS)
44 def fill_rows(self, rows: list[list], header: Optional[list] = None) -> None:
45 """
46 Fills a table from header and rows list.
47 `rows` is a list of lists representing each row content.
48 each element of `rows` and header must be of same length.
49 """
50 if header:
51 if len(rows) == 0:
52 rows.append([""] * len(header))
53 assert len(header) == len(rows[0])
54 self.header(header)
55 for line in rows:
56 assert len(line) == len(rows[0])
57 self.add_row(line)
59 def fill_from_dict(self, _dict: dict) -> None:
60 """
61 Given a dict where each value represents a column,
62 fill a table where labels are dict keys and columns are dict values
63 This function stops on the first line with only empty cells
64 """
65 keys = list(_dict.keys())
66 rows = []
68 n = 0
69 while True:
70 row = []
71 empty_cells_number = 0
73 for key in keys:
74 try:
75 row.append(_dict[key][n])
76 except IndexError:
77 row.append("")
78 empty_cells_number += 1
79 # break on first empty row
80 if empty_cells_number == len(keys):
81 break
82 rows.append(row)
83 n += 1
85 return self.fill_rows(rows, keys)
87 def fill_from_dict_list(self, dict_list: list[dict]) -> None:
88 """
89 Given a list of dict with same keys,
90 fills the table with keys as header
91 """
92 header = list(dict_list[0].keys())
93 content = []
94 for _dict in dict_list:
95 assert list(_dict.keys()) == header
96 line = []
97 for head in header:
98 line.append(_dict[head])
99 content.append(line)
100 return self.fill_rows(content, header)