Source code for trader.cli.tables
"""One shared table-construction helper for every CLI table.
Six commands (`positions`, `account`, `outcomes`, `history`, `strategies`)
used to hand-build column widths in f-strings, one format per command and
silently drifting apart — `outcomes`' own header once sat two characters out
of step with its own row data because widening one `:<N>` and not the other
is an easy, silent mistake. `build_table` is now the only place a column gets
padded: every command supplies headers and already-formatted cell text, and
`prettytable.PrettyTable` does the layout.
Cells reaching this module are strings (or values `str()` renders sanely).
Rounding a `Decimal` or formatting a percentage is the caller's job, not
this module's — a table helper that rounded money itself would be exactly
the kind of incidental rounding the project's `Decimal`/`quantize` rule
forbids.
"""
from collections.abc import Sequence
from prettytable import PrettyTable
__all__ = ["MISSING", "build_table"]
#: What an unknown, never-fabricated value renders as — a dash, not a blank
#: (which reads as "nothing was tried") and not a `0` (which reads as a
#: measured value). Days held with no round trip on record uses this; so does
#: a percentage whose inputs cannot support one.
MISSING = "-"
[docs]
def build_table(headers: Sequence[str], rows: Sequence[Sequence[object]]) -> PrettyTable:
"""A table with its first column left-aligned and the rest right-aligned.
Every CLI table here has the same shape: one label column (SYMBOL, DATE,
ID, STRATEGY) followed by several numeric or percentage columns. Right-
aligning the numeric columns is what makes a column of numbers scannable;
left-aligning only the label column keeps a table from looking staggered
when that column's values vary widely in length.
"""
table = PrettyTable()
table.field_names = list(headers)
for row in rows:
table.add_row([str(value) for value in row])
table.align = "r"
if headers:
table.align[headers[0]] = "l"
return table