From d57a162a59968d5c87a24b2094ad72f44bedb313 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Sat, 19 Aug 2023 07:41:56 -0400 Subject: [PATCH] fix(repr): ensure that column expressions are not promoted to table when repring non-interactively --- ibis/expr/types/core.py | 16 +++++++++++++--- ibis/expr/types/generic.py | 8 ++------ ibis/expr/types/relations.py | 7 +------ ibis/tests/expr/test_pretty_repr.py | 12 ++++++++++++ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/ibis/expr/types/core.py b/ibis/expr/types/core.py index d9222bfa59ac..3a12204e3810 100644 --- a/ibis/expr/types/core.py +++ b/ibis/expr/types/core.py @@ -13,7 +13,7 @@ from ibis.common.exceptions import IbisError, TranslationError from ibis.common.grounds import Immutable from ibis.common.patterns import Coercible, CoercionError -from ibis.config import _default_backend, options +from ibis.config import _default_backend, options as opts from ibis.util import experimental if TYPE_CHECKING: @@ -46,6 +46,16 @@ class Expr(Immutable, Coercible): __slots__ = ("_arg",) _arg: ops.Node + def __rich_console__(self, console, options): + if not opts.interactive: + from rich.text import Text + + return console.render(Text(self._repr()), options=options) + return self.__interactive_rich_console__(console, options) + + def __interactive_rich_console__(self, console, options): + raise NotImplementedError() + def __init__(self, arg: ops.Node) -> None: object.__setattr__(self, "_arg", arg) @@ -62,7 +72,7 @@ def __coerce__(cls, value): raise CoercionError("Unable to coerce value to an expression") def __repr__(self) -> str: - if not options.interactive: + if not opts.interactive: return self._repr() from ibis.expr.types.pretty import simple_console @@ -132,7 +142,7 @@ def get_name(self): return self._arg.name def _repr_png_(self) -> bytes | None: - if options.interactive or not options.graphviz_repr: + if opts.interactive or not opts.graphviz_repr: return None try: import ibis.expr.visualize as viz diff --git a/ibis/expr/types/generic.py b/ibis/expr/types/generic.py index d614821cbe08..6061cef01c51 100644 --- a/ibis/expr/types/generic.py +++ b/ibis/expr/types/generic.py @@ -925,11 +925,7 @@ def to_pandas(self, **kwargs) -> pd.Series: @public class Scalar(Value): - def __rich_console__(self, console, options): - from rich.text import Text - - if not ibis.options.interactive: - return console.render(Text(self._repr()), options=options) + def __interactive_rich_console__(self, console, options): return console.render(repr(self.execute()), options=options) def __pyarrow_result__(self, table: pa.Table) -> pa.Scalar: @@ -995,7 +991,7 @@ def __getitem__(self, _): def __array__(self, dtype=None): return self.execute().__array__(dtype) - def __rich_console__(self, console, options): + def __interactive_rich_console__(self, console, options): named = self.name(self.op().name) projection = named.as_table() return console.render(projection, options=options) diff --git a/ibis/expr/types/relations.py b/ibis/expr/types/relations.py index a89d8e35a656..572fef30ffb9 100644 --- a/ibis/expr/types/relations.py +++ b/ibis/expr/types/relations.py @@ -295,14 +295,9 @@ def _cast(self, schema: SupportsSchema, cast_method: str = "cast") -> Table: cols.append(new_col) return self.select(*cols) - def __rich_console__(self, console, options): - from rich.text import Text - + def __interactive_rich_console__(self, console, options): from ibis.expr.types.pretty import to_rich_table - if not ibis.options.interactive: - return console.render(Text(self._repr()), options=options) - if console.is_jupyter: # Rich infers a console width in jupyter notebooks, but since # notebooks can use horizontal scroll bars we don't want to apply a diff --git a/ibis/tests/expr/test_pretty_repr.py b/ibis/tests/expr/test_pretty_repr.py index 05606d39fa1f..e5fe88f2b0c1 100644 --- a/ibis/tests/expr/test_pretty_repr.py +++ b/ibis/tests/expr/test_pretty_repr.py @@ -5,6 +5,7 @@ import pandas as pd import pytest +from rich.console import Console import ibis import ibis.expr.datatypes as dt @@ -166,3 +167,14 @@ def test_all_empty_groups_repr(): dtype = dt.float64 fmts, *_ = format_column(dtype, values) assert list(map(str, fmts)) == ["nan", "nan"] + + +def test_non_interactive_column_repr(): + t = ibis.table(dict(names="string", values="int")) + expr = t.names + console = Console() + with console.capture() as capture: + console.print(expr) + + result = capture.get() + assert "Selection" not in result