diff --git a/pytools/__init__.py b/pytools/__init__.py index b7dc0989835991c6c29392894b48743a942b05ee..22459de742ba7067f93ade6e2611f5ea388d3960 100644 --- a/pytools/__init__.py +++ b/pytools/__init__.py @@ -1497,30 +1497,106 @@ a_star = MovedFunctionDeprecationWrapper(a_star_moved) class Table: """An ASCII table generator. + :arg alignments: List of alignments of each column ('l', 'c', or 'r', + for left, center, and right alignment, respectively). Columns which + have no alignment specifier will use the last specified alignment. For + example, with `alignments=['l', 'r']`, the third and all following + columns will use 'r' alignment. + .. automethod:: add_row .. automethod:: __str__ .. automethod:: latex + .. automethod:: github_markdown """ - def __init__(self): + def __init__(self, alignments=None): self.rows = [] + if alignments is not None: + self.alignments = alignments + else: + self.alignments = ['l'] def add_row(self, row): self.rows.append([str(i) for i in row]) def __str__(self): + """ + Returns a string representation of the table. + + .. doctest :: + + >>> tbl = Table(alignments=['l', 'r', 'l']) + >>> tbl.add_row([1, '|']) + >>> tbl.add_row([10, '20||']) + >>> print(tbl) + 1 | | + ---+------ + 10 | 20|| + + """ + columns = len(self.rows[0]) col_widths = [max(len(row[i]) for row in self.rows) for i in range(columns)] - lines = [" | ".join([cell.ljust(col_width) - for cell, col_width in zip(row, col_widths)]) + alignments = self.alignments + # If not all alignments were specified, extend alignments with the + # last alignment specified: + alignments += self.alignments[-1] * (columns - len(self.alignments)) + + lines = [" | ".join([ + cell.center(col_width) if align == "c" + else cell.ljust(col_width) if align == "l" + else cell.rjust(col_width) + for cell, col_width, align in zip(row, col_widths, alignments)]) for row in self.rows] lines[1:1] = ["+".join("-" * (col_width + 1 + (i > 0)) for i, col_width in enumerate(col_widths))] return "\n".join(lines) + def github_markdown(self): + """Returns a string representation of the table formatted as + `GitHub-Flavored Markdown. + <https://docs.github.com/en/github/writing-on-github/organizing-information-with-tables>`__ + + .. doctest :: + + >>> tbl = Table(alignments=['l', 'r', 'l']) + >>> tbl.add_row([1, '|']) + >>> tbl.add_row([10, '20||']) + >>> print(tbl.github_markdown()) + 1 | \| + :--|-------: + 10 | 20\|\| + + """ # noqa: W605 + # Pipe symbols ('|') must be replaced + rows = [[w.replace('|', '\\|') for w in r] for r in self.rows] + + columns = len(rows[0]) + col_widths = [max(len(row[i]) for row in rows) + for i in range(columns)] + + alignments = self.alignments + # If not all alignments were specified, extend alignments with the + # last alignment specified: + alignments += self.alignments[-1] * (columns - len(self.alignments)) + + lines = [" | ".join([ + cell.center(col_width) if align == "c" + else cell.ljust(col_width) if align == "l" + else cell.rjust(col_width) + for cell, col_width, align in zip(row, col_widths, alignments)]) + for row in rows] + lines[1:1] = ["|".join( + ":" + "-" * (col_width - 1 + (i > 0)) + ":" if align == "c" + else ":" + "-" * (col_width + (i > 0)) if align == "l" + else "-" * (col_width + (i > 0)) + ":" + for i, (col_width, align) in enumerate(zip(col_widths, alignments)))] + + return "\n".join(lines) + def latex(self, skip_lines=0, hline_after=None): if hline_after is None: hline_after = []