1class MarkupTable:
2    """
3    Container for holding table data and render the data in creole markup.
4    Format every cell width to the same col width.
5    """
6
7    def __init__(self, head_prefix="= ", auto_width=True, debug_msg=None):
8        self.head_prefix = head_prefix
9        self.auto_width = auto_width
10
11        if debug_msg is None:
12            self.debug_msg = self._non_debug
13        else:
14            self.debug_msg = debug_msg
15
16        self.rows = []
17        self.row_index = None
18        self.has_header = False
19
20    def _non_debug(self, *args):
21        pass
22
23    def add_tr(self):
24        self.debug_msg("Table.add_tr", "")
25        self.rows.append([])
26        self.row_index = len(self.rows) - 1
27
28    def add_th(self, text):
29        self.has_header = True
30        self.add_td(self.head_prefix + text)
31
32    def add_td(self, text):
33        if self.row_index is None:
34            self.add_tr()
35
36        self.debug_msg("Table.add_td", text)
37        self.rows[self.row_index].append(text)
38
39    def _get_preformat_info(self):
40        cells = []
41        for row in self.rows:
42            line_cells = []
43            for cell in row:
44                cell = cell.strip()
45                if cell != "":
46                    if self.head_prefix and cell.startswith(self.head_prefix):
47                        cell += " "  # Headline
48                    else:
49                        cell = f" {cell} "  # normal cell
50                line_cells.append(cell)
51            cells.append(line_cells)
52
53        # Build a list of max len for every column
54        widths = [max(map(len, col)) for col in zip(*cells)]
55
56        return cells, widths
57
58    def get_table_markup(self):
59        """ return the table data in creole/textile markup. """
60        if not self.auto_width:
61            lines = []
62            for row in self.rows:
63                lines.append("|" + "|".join([cell for cell in row]) + "|")
64        else:
65            # preformat every table cell
66            cells, widths = self._get_preformat_info()
67
68            # Join every line with ljust
69            lines = []
70            for row in cells:
71                cells = [cell.ljust(width) for cell, width in zip(row, widths)]
72                lines.append("|" + "|".join(cells) + "|")
73
74        result = "\n".join(lines)
75
76        self.debug_msg("Table.get_table_markup", result)
77        return result
78
79    def get_rest_table(self):
80        """ return the table data in ReSt markup. """
81        # preformat every table cell
82        cells, widths = self._get_preformat_info()
83
84        separator_line = f"+{'+'.join([('-' * width) for width in widths])}+"
85        headline_separator = f"+{'+'.join([('=' * width) for width in widths])}+"
86
87        lines = []
88        for no, row in enumerate(cells):
89            if no == 1 and self.has_header:
90                lines.append(headline_separator)
91            else:
92                lines.append(separator_line)
93
94            # Join every line with ljust
95            cells = [cell.ljust(width) for cell, width in zip(row, widths)]
96            lines.append("|" + "|".join(cells) + "|")
97
98        lines.append(separator_line)
99
100        return "\n".join(lines)
101
102
103if __name__ == '__main__':
104    import doctest
105    print(doctest.testmod())
106