srne-mqtt/misc/table_drawing.py

117 lines
2.7 KiB
Python

# -*- coding: utf-8 -*-
from typing import Collection, Optional, Union
C_UL = ""
C_UR = ""
C_LL = ""
C_LR = ""
C_V = ""
C_VL = ""
C_VR = ""
C_H = ""
C_HD = ""
C_HU = ""
C_X = ""
def row(
fields: Collection[str],
sep: str = C_V,
start: str = C_V,
end: str = C_V,
) -> str:
res = []
for i, field in enumerate(fields):
if not i:
res.append(start)
else:
res.append(sep)
res.append(field)
res.append(end)
return "".join(res)
def table(
data: Collection[Collection[str]],
headers: Optional[Collection] = None,
header_interval: Optional[int] = None,
justify: Optional[Union[str, Collection[str]]] = None,
collapse_empty: bool = False,
):
res = []
if not data:
return ""
columns = max([len(x) for x in data])
if headers:
columns = max(columns, len(headers))
if isinstance(justify, str):
justify = [justify] * columns
elif not justify:
justify = []
justify = list(justify) + ["^"] * (columns - len(justify))
colwidths = [0] * columns
if headers:
for i, col in enumerate(headers):
colwidths[i] = max(colwidths[i], len(col))
for data_row in data:
for i, col in enumerate(data_row):
colwidths[i] = max(colwidths[i], len(col))
def row_iterable():
if headers and not header_interval:
yield headers
for i, data_row in enumerate(data):
if header_interval and i % header_interval == 0:
yield headers
yield data_row
for i, data_row in enumerate(row_iterable()):
if not i:
res.append(
row([C_H * colw for colw in colwidths], start=C_UL, sep=C_HD, end=C_UR)
)
else:
res.append(
row([C_H * colw for colw in colwidths], start=C_VL, sep=C_X, end=C_VR)
)
is_empty = not any([True for x in data_row if x.strip()])
if not (is_empty and collapse_empty):
padding = [""] * (columns - len(data_row))
padded_row = [
f"{cell:{justify[j]}{colwidths[j]}s}"
for j, cell in enumerate(list(data_row) + padding)
]
res.append(row(padded_row))
res.append(row([C_H * colw for colw in colwidths], start=C_LL, sep=C_HU, end=C_LR))
return "\n".join(res)
if __name__ == "__main__":
headers = [""] + ["···{:01X}".format(x) for x in range(16)]
data = [[f"{x:03X}·"] for x in range(32)]
print(
table(
data,
headers=headers,
justify=">",
header_interval=8,
)
)