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