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

Commit

Permalink
Define generic for pretty-printing objects inside a table. (#12)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
LTLA authored Oct 31, 2023
1 parent fd6e743 commit 63b174c
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/biocgenerics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
from .combine_cols import combine_cols
from .combine_rows import combine_rows
from .rownames import rownames, set_rownames
from .show_as_cell import show_as_cell, format_table
113 changes: 113 additions & 0 deletions src/biocgenerics/show_as_cell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from functools import singledispatch
from typing import Any, List, Optional, Sequence

__author__ = "Aaron Lun"
__copyright__ = "LTLA"
__license__ = "MIT"


@singledispatch
def show_as_cell(x: Any, indices: Sequence[int]) -> List[str]:
"""Show the contents of ``x`` as a cell of a table, typically for use in the ``__str__`` method of a class that
contains ``x``.
Args:
x:
Any object. By default, we assume that it can be treated as
a sequence, with a valid ``__getitem__`` method for an index.
indices:
List of indices to be extracted.
Returns:
List of strings of length equal to ``indices``, containing a
string summary of each of the specified elements of ``x``.
"""
output = []
for i in indices:
output.append(str(x[i]))
return output


def _get_max_width(col: List[str]):
width = 0
for y in col:
if len(y) > width:
width = len(y)
return width


def format_table(
columns: List[Sequence[str]],
floating_names: Optional[Sequence[str]] = None,
sep: str = " ",
window: Optional[int] = None,
) -> str:
"""Pretty-print a table with wrapping columns.
Args:
columns: List of list of strings, where each inner list is the same length.
Strings are typically generated by :py:meth:`~show_as_cell`.
floating_names: List of strings to be added to the left of the table. This is
printed repeatedly for each set of wrapped columns.
sep: Separator between columns.
window: Size of the terminal window, in characters. We attempt to determine
this automatically, otherwise it is set to 150.
Returns:
str: String containing the pretty-printed table.
"""
if window is None:
import os

try:
window = os.get_terminal_size().columns
except Exception as _:
window = 150

if len(columns) == 0:
raise ValueError("At least one column should be supplied in 'columns'.")
n = len(columns[0])

floatwidth = 0
if floating_names is not None:
floatwidth = _get_max_width(floating_names)
new_floating_names = []
for y in floating_names:
new_floating_names.append(y.rjust(floatwidth))
floating_names = new_floating_names

output = ""

def reinitialize():
if floating_names is None:
return [""] * n
else:
return floating_names[:]

contents = reinitialize()
init = True
used = floatwidth

for col in columns:
width = _get_max_width(col)

if not init and used + width + len(sep) > window:
for line in contents:
output += line + "\n"
contents = reinitialize()
init = True
used = floatwidth

for i, y in enumerate(col):
if used > 0:
contents[i] += sep
contents[i] += y.rjust(width)
used += width + len(sep)
init = False

output += "\n".join(contents)
return output
22 changes: 22 additions & 0 deletions tests/test_show_as_cell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from biocgenerics import show_as_cell, format_table


def test_show_as_cell():
assert show_as_cell([1, 2, 3, 4], range(4)) == ["1", "2", "3", "4"]
assert show_as_cell([1, 2, 3, 4], [1, 3]) == ["2", "4"]


def test_format_table():
contents = [
["asdasd", "1", "2", "3", "4"],
[""] + ["|"] * 4,
["asyudgausydga", "A", "B", "C", "D"],
]
print(format_table(contents))
print(format_table(contents, floating_names=["", "aarg", "boo", "ffoo", "stuff"]))
print(format_table(contents, window=10))
print(
format_table(
contents, window=10, floating_names=["", "AAAR", "BBBB", "XXX", "STUFF"]
)
)

0 comments on commit 63b174c

Please sign in to comment.