Skip to content

Commit 67234c3

Browse files
committed
feat(ux): use rich to format Table.info() output
1 parent 10a659d commit 67234c3

File tree

7 files changed

+61
-34
lines changed

7 files changed

+61
-34
lines changed

ibis/backends/tests/test_generic.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import importlib
33
import io
44
import operator
5+
from contextlib import redirect_stdout
56

67
import numpy as np
78
import pandas as pd
@@ -435,16 +436,25 @@ def test_select_sort_sort(alltypes):
435436
query = query.sort_by(query.year).sort_by(query.bool_col)
436437

437438

438-
def test_table_info(alltypes):
439+
def check_table_info(buf, schema):
440+
info_str = buf.getvalue()
441+
442+
assert "Null" in info_str
443+
assert all(type.__class__.__name__ in info_str for type in schema.types)
444+
assert all(name in info_str for name in schema.names)
445+
446+
447+
def test_table_info_buf(alltypes):
439448
buf = io.StringIO()
440449
alltypes.info(buf=buf)
450+
check_table_info(buf, alltypes.schema())
441451

442-
info_str = buf.getvalue()
443-
schema = alltypes.schema()
444452

445-
assert "Nulls" in info_str
446-
assert all(str(type) in info_str for type in schema.types)
447-
assert all(name in info_str for name in schema.names)
453+
def test_table_info_no_buf(alltypes):
454+
buf = io.StringIO()
455+
with redirect_stdout(buf):
456+
alltypes.info()
457+
check_table_info(buf, alltypes.schema())
448458

449459

450460
@pytest.mark.parametrize(

ibis/common/grounds.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
from typing import Any, Hashable
66
from weakref import WeakValueDictionary
77

8+
from rich.console import Console
9+
810
from ibis.common.caching import WeakCache
911
from ibis.common.validators import ImmutableProperty, Optional, Validator
1012
from ibis.util import frozendict
1113

1214
EMPTY = inspect.Parameter.empty # marker for missing argument
1315

16+
console = Console()
17+
1418

1519
class BaseMeta(ABCMeta):
1620

ibis/expr/types/relations.py

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@
44
import functools
55
import itertools
66
import operator
7+
import sys
78
import warnings
89
from functools import cached_property
910
from typing import IO, TYPE_CHECKING, Any, Iterable, Literal, Mapping, Sequence
1011

1112
import numpy as np
12-
import tabulate
13+
import rich.pretty
14+
import rich.table
1315
from public import public
1416

1517
import ibis
1618
from ibis import util
1719
from ibis.common import exceptions as com
20+
from ibis.common.grounds import console
1821
from ibis.expr.deferred import Deferred
1922
from ibis.expr.types.core import Expr
2023

@@ -872,29 +875,37 @@ def info(self, buf: IO[str] | None = None) -> None:
872875
buf
873876
A writable buffer, defaults to stdout
874877
"""
878+
if buf is None:
879+
buf = sys.stdout
880+
875881
metrics = [self[col].count().name(col) for col in self.columns]
876882
metrics.append(self.count().name("nrows"))
877883

878884
schema = self.schema()
879885

880886
*items, (_, n) = self.aggregate(metrics).execute().squeeze().items()
881887

882-
tabulated = tabulate.tabulate(
883-
[
884-
(
885-
column,
886-
schema[column],
887-
f"{n - non_nulls} ({100 * (1.0 - non_nulls / n):>3.3g}%)",
888-
)
889-
for column, non_nulls in items
890-
],
891-
headers=["Column", "Type", "Nulls (%)"],
892-
colalign=("left", "left", "right"),
893-
)
894-
width = tabulated[tabulated.index("\n") + 1 :].index("\n")
895-
row_count = f"Rows: {n}".center(width)
896-
footer_line = "-" * width
897-
print("\n".join([tabulated, footer_line, row_count]), file=buf)
888+
op = self.op()
889+
title = getattr(op, "name", type(op).__name__)
890+
891+
table = rich.table.Table(title=f"Summary of {title}\n{n:d} rows")
892+
893+
table.add_column("Name", justify="left")
894+
table.add_column("Type", justify="left")
895+
table.add_column("# Nulls", justify="right")
896+
table.add_column("% Nulls", justify="right")
897+
898+
for column, non_nulls in items:
899+
table.add_row(
900+
column,
901+
rich.pretty.Pretty(schema[column]),
902+
str(n - non_nulls),
903+
f"{100 * (1.0 - non_nulls / n):>3.2f}",
904+
)
905+
906+
with console.capture() as capture:
907+
console.print(table)
908+
buf.write(capture.get())
898909

899910
def set_column(self, name: str, expr: ir.Value) -> Table:
900911
"""Replace an existing column with a new expression.

poetry.lock

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pandas = ">=1.2.5,<2"
3535
parsy = ">=1.3.0,<2"
3636
pydantic = ">=1.9.0,<2"
3737
regex = ">=2021.7.6"
38-
tabulate = ">=0.8.9,<1"
38+
rich = ">=12.4.4,<13"
3939
toolz = ">=0.11,<0.13"
4040
clickhouse-cityhash = { version = ">=1.0.2,<2", optional = true }
4141
clickhouse-driver = { version = ">=0.1,<0.3", optional = true, extras = [

requirements.txt

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

setup.py

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)