Skip to content
This repository was archived by the owner on Dec 1, 2023. It is now read-only.

Commit 63b174c

Browse files
authored
Define generic for pretty-printing objects inside a table. (#12)
* Define generic for pretty-printing objects inside a table. Also define a function for formatting a table, so that we don't have to rely on third-party libraries for our pretty-printing.
1 parent fd6e743 commit 63b174c

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

src/biocgenerics/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
from .combine_cols import combine_cols
2121
from .combine_rows import combine_rows
2222
from .rownames import rownames, set_rownames
23+
from .show_as_cell import show_as_cell, format_table

src/biocgenerics/show_as_cell.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from functools import singledispatch
2+
from typing import Any, List, Optional, Sequence
3+
4+
__author__ = "Aaron Lun"
5+
__copyright__ = "LTLA"
6+
__license__ = "MIT"
7+
8+
9+
@singledispatch
10+
def show_as_cell(x: Any, indices: Sequence[int]) -> List[str]:
11+
"""Show the contents of ``x`` as a cell of a table, typically for use in the ``__str__`` method of a class that
12+
contains ``x``.
13+
14+
Args:
15+
x:
16+
Any object. By default, we assume that it can be treated as
17+
a sequence, with a valid ``__getitem__`` method for an index.
18+
19+
indices:
20+
List of indices to be extracted.
21+
22+
Returns:
23+
List of strings of length equal to ``indices``, containing a
24+
string summary of each of the specified elements of ``x``.
25+
"""
26+
output = []
27+
for i in indices:
28+
output.append(str(x[i]))
29+
return output
30+
31+
32+
def _get_max_width(col: List[str]):
33+
width = 0
34+
for y in col:
35+
if len(y) > width:
36+
width = len(y)
37+
return width
38+
39+
40+
def format_table(
41+
columns: List[Sequence[str]],
42+
floating_names: Optional[Sequence[str]] = None,
43+
sep: str = " ",
44+
window: Optional[int] = None,
45+
) -> str:
46+
"""Pretty-print a table with wrapping columns.
47+
48+
Args:
49+
columns: List of list of strings, where each inner list is the same length.
50+
Strings are typically generated by :py:meth:`~show_as_cell`.
51+
52+
floating_names: List of strings to be added to the left of the table. This is
53+
printed repeatedly for each set of wrapped columns.
54+
55+
sep: Separator between columns.
56+
57+
window: Size of the terminal window, in characters. We attempt to determine
58+
this automatically, otherwise it is set to 150.
59+
60+
Returns:
61+
str: String containing the pretty-printed table.
62+
"""
63+
if window is None:
64+
import os
65+
66+
try:
67+
window = os.get_terminal_size().columns
68+
except Exception as _:
69+
window = 150
70+
71+
if len(columns) == 0:
72+
raise ValueError("At least one column should be supplied in 'columns'.")
73+
n = len(columns[0])
74+
75+
floatwidth = 0
76+
if floating_names is not None:
77+
floatwidth = _get_max_width(floating_names)
78+
new_floating_names = []
79+
for y in floating_names:
80+
new_floating_names.append(y.rjust(floatwidth))
81+
floating_names = new_floating_names
82+
83+
output = ""
84+
85+
def reinitialize():
86+
if floating_names is None:
87+
return [""] * n
88+
else:
89+
return floating_names[:]
90+
91+
contents = reinitialize()
92+
init = True
93+
used = floatwidth
94+
95+
for col in columns:
96+
width = _get_max_width(col)
97+
98+
if not init and used + width + len(sep) > window:
99+
for line in contents:
100+
output += line + "\n"
101+
contents = reinitialize()
102+
init = True
103+
used = floatwidth
104+
105+
for i, y in enumerate(col):
106+
if used > 0:
107+
contents[i] += sep
108+
contents[i] += y.rjust(width)
109+
used += width + len(sep)
110+
init = False
111+
112+
output += "\n".join(contents)
113+
return output

tests/test_show_as_cell.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from biocgenerics import show_as_cell, format_table
2+
3+
4+
def test_show_as_cell():
5+
assert show_as_cell([1, 2, 3, 4], range(4)) == ["1", "2", "3", "4"]
6+
assert show_as_cell([1, 2, 3, 4], [1, 3]) == ["2", "4"]
7+
8+
9+
def test_format_table():
10+
contents = [
11+
["asdasd", "1", "2", "3", "4"],
12+
[""] + ["|"] * 4,
13+
["asyudgausydga", "A", "B", "C", "D"],
14+
]
15+
print(format_table(contents))
16+
print(format_table(contents, floating_names=["", "aarg", "boo", "ffoo", "stuff"]))
17+
print(format_table(contents, window=10))
18+
print(
19+
format_table(
20+
contents, window=10, floating_names=["", "AAAR", "BBBB", "XXX", "STUFF"]
21+
)
22+
)

0 commit comments

Comments
 (0)