From 72aa5732d42efefffd75b79f297ca7e0f5156825 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Thu, 15 Jun 2023 14:24:12 -0500 Subject: [PATCH] feat: use `to_pyarrow` instead of `to_pandas` in the interactive repr --- ibis/backends/duckdb/__init__.py | 1 + ibis/expr/types/core.py | 2 +- ibis/expr/types/generic.py | 12 ++--- ibis/expr/types/groupby.py | 22 ++++---- ibis/expr/types/pretty.py | 32 ++++++++++-- ibis/expr/types/relations.py | 80 ++++++++++++++--------------- ibis/selectors.py | 2 +- ibis/tests/expr/mocks.py | 19 ++++--- ibis/tests/expr/test_pretty_repr.py | 11 +++- 9 files changed, 107 insertions(+), 74 deletions(-) diff --git a/ibis/backends/duckdb/__init__.py b/ibis/backends/duckdb/__init__.py index 4c6a593f0b93..fb12d58fa930 100644 --- a/ibis/backends/duckdb/__init__.py +++ b/ibis/backends/duckdb/__init__.py @@ -236,6 +236,7 @@ def configure_connection(dbapi_connection, connection_record): with contextlib.suppress(duckdb.InvalidInputException): duckdb.execute("SELECT ?", (1,)) + engine.dialect._backslash_escapes = False super().do_connect(engine) @staticmethod diff --git a/ibis/expr/types/core.py b/ibis/expr/types/core.py index 56e80d387628..71633ab1b1f0 100644 --- a/ibis/expr/types/core.py +++ b/ibis/expr/types/core.py @@ -88,7 +88,7 @@ def __repr__(self) -> str: self._repr(), ] return "\n".join(lines) - return capture.get() + return capture.get().rstrip() def __reduce__(self): return (self.__class__, (self._arg,)) diff --git a/ibis/expr/types/generic.py b/ibis/expr/types/generic.py index 7fd09c6e2fea..88f0dd5f2441 100644 --- a/ibis/expr/types/generic.py +++ b/ibis/expr/types/generic.py @@ -120,7 +120,7 @@ def cast(self, target_type: Any) -> Value: │ 18.7 │ │ 17.4 │ │ 18.0 │ - │ nan │ + │ NULL │ │ 19.3 │ │ 20.6 │ │ 17.8 │ @@ -335,7 +335,7 @@ def typeof(self) -> ir.StringValue: │ 39.1 │ │ 39.5 │ │ 40.3 │ - │ nan │ + │ NULL │ │ 36.7 │ └────────────────┘ >>> vals.typeof() @@ -610,7 +610,7 @@ def notin(self, values: Value | Sequence[Value]) -> ir.BooleanValue: │ 18.7 │ │ 17.4 │ │ 18.0 │ - │ nan │ + │ NULL │ │ 19.3 │ └───────────────┘ >>> t.bill_depth_mm.notin([18.7, 18.1]) @@ -770,7 +770,7 @@ def isnull(self) -> ir.BooleanValue: │ 18.7 │ │ 17.4 │ │ 18.0 │ - │ nan │ + │ NULL │ │ 19.3 │ └───────────────┘ >>> t.bill_depth_mm.isnull() @@ -805,7 +805,7 @@ def notnull(self) -> ir.BooleanValue: │ 18.7 │ │ 17.4 │ │ 18.0 │ - │ nan │ + │ NULL │ │ 19.3 │ └───────────────┘ >>> t.bill_depth_mm.notnull() @@ -1100,7 +1100,7 @@ def group_concat( │ 39.1 │ 18.7 │ │ 39.5 │ 17.4 │ │ 40.3 │ 18.0 │ - │ nan │ nan │ + │ NULL │ NULL │ │ 36.7 │ 19.3 │ └────────────────┴───────────────┘ >>> t.bill_length_mm.group_concat() diff --git a/ibis/expr/types/groupby.py b/ibis/expr/types/groupby.py index b27135bd0e7c..8505fbf8bc04 100644 --- a/ibis/expr/types/groupby.py +++ b/ibis/expr/types/groupby.py @@ -174,6 +174,7 @@ def mutate( Examples -------- >>> import ibis + >>> import ibis.selectors as s >>> ibis.options.interactive = True >>> t = ibis.examples.penguins.fetch() >>> t @@ -185,7 +186,7 @@ def mutate( │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -201,22 +202,23 @@ def mutate( ... centered_bill_len=ibis._.bill_length_mm ... - ibis._.bill_length_mm.mean() ... ) + ... .order_by(s.all()) ... ) ┏━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ ┃ species ┃ bill_length_mm ┃ centered_bill_len ┃ ┡━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ │ string │ float64 │ float64 │ ├─────────┼────────────────┼───────────────────┤ - │ Adelie │ 40.9 │ 2.108609 │ - │ Adelie │ 42.7 │ 3.908609 │ - │ Adelie │ 39.8 │ 1.008609 │ - │ Adelie │ 36.5 │ -2.291391 │ - │ Adelie │ 36.7 │ -2.091391 │ - │ Adelie │ 39.3 │ 0.508609 │ - │ Adelie │ 38.9 │ 0.108609 │ - │ Adelie │ 39.2 │ 0.408609 │ + │ Adelie │ 32.1 │ -6.691391 │ + │ Adelie │ 33.1 │ -5.691391 │ + │ Adelie │ 33.5 │ -5.291391 │ + │ Adelie │ 34.0 │ -4.791391 │ │ Adelie │ 34.1 │ -4.691391 │ - │ Adelie │ 42.0 │ 3.208609 │ + │ Adelie │ 34.4 │ -4.391391 │ + │ Adelie │ 34.5 │ -4.291391 │ + │ Adelie │ 34.6 │ -4.191391 │ + │ Adelie │ 34.6 │ -4.191391 │ + │ Adelie │ 35.0 │ -3.791391 │ │ … │ … │ … │ └─────────┴────────────────┴───────────────────┘ diff --git a/ibis/expr/types/pretty.py b/ibis/expr/types/pretty.py index 2c31773125c8..78a47a4ebcc7 100644 --- a/ibis/expr/types/pretty.py +++ b/ibis/expr/types/pretty.py @@ -1,6 +1,7 @@ from __future__ import annotations import datetime +import json from functools import singledispatch from math import isfinite from urllib.parse import urlparse @@ -8,7 +9,6 @@ import rich from rich.align import Align from rich.console import Console -from rich.style import Style from rich.text import Text import ibis @@ -18,8 +18,7 @@ simple_console = Console(force_terminal=False) -@singledispatch -def format_values(dtype, values): +def _format_nested(values): interactive = ibis.options.repr.interactive return [ rich.pretty.Pretty( @@ -32,6 +31,29 @@ def format_values(dtype, values): ] +@singledispatch +def format_values(dtype, values): + return _format_nested(values) + + +@format_values.register(dt.Map) +def _(dtype, values): + return _format_nested([None if v is None else dict(v) for v in values]) + + +@format_values.register(dt.JSON) +def _(dtype, values): + def try_json(v): + if v is None: + return None + try: + return json.loads(v) + except Exception: + return v + + return _format_nested([try_json(v) for v in values]) + + @format_values.register(dt.Boolean) @format_values.register(dt.UUID) def _(dtype, values): @@ -233,7 +255,7 @@ def to_rich_table(table, console_width=None): # Compute the data and return a pandas dataframe nrows = ibis.options.repr.interactive.max_rows - result = table.limit(nrows + 1).execute() + result = table.limit(nrows + 1).to_pyarrow() # Now format the columns in order, stopping if the console width would # be exceeded. @@ -243,7 +265,7 @@ def to_rich_table(table, console_width=None): remaining = console_width - 1 # 1 char for left boundary for name, dtype in table.schema().items(): formatted, min_width, max_width = format_column( - dtype, result[name].iloc[:nrows].to_list() + dtype, result[name].to_pylist()[:nrows] ) dtype_str = format_dtype(dtype) if ibis.options.repr.interactive.show_types and not isinstance( diff --git a/ibis/expr/types/relations.py b/ibis/expr/types/relations.py index f98d42d80b1c..efd0d6480c55 100644 --- a/ibis/expr/types/relations.py +++ b/ibis/expr/types/relations.py @@ -254,7 +254,7 @@ def cast(self, schema: SupportsSchema) -> Table: │ 3750 │ 39.1 │ │ 3800 │ 39.5 │ │ 3250 │ 40.3 │ - │ NULL │ nan │ + │ NULL │ NULL │ │ 3450 │ 36.7 │ └─────────────┴────────────────┘ @@ -272,7 +272,7 @@ def cast(self, schema: SupportsSchema) -> Table: │ 3750.0 │ 39 │ │ 3800.0 │ 40 │ │ 3250.0 │ 40 │ - │ nan │ NULL │ + │ NULL │ NULL │ │ 3450.0 │ 37 │ └─────────────┴────────────────┘ @@ -314,7 +314,7 @@ def try_cast(self, schema: SupportsSchema) -> Table: ├───────┼─────────┤ │ 1 │ 2.2 │ │ 2 │ 3.3 │ - │ 3 │ nan │ + │ 3 │ NULL │ └───────┴─────────┘ """ return self._cast(schema, cast_method="try_cast") @@ -389,7 +389,7 @@ def __getitem__(self, what): │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -463,7 +463,7 @@ def __getitem__(self, what): │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ └─────────┴───────────┴────────────────┴───────────────┴───────────────────┴───┘ >>> t[2:5] @@ -473,7 +473,7 @@ def __getitem__(self, what): │ string │ string │ float64 │ float64 │ int64 │ … │ ├─────────┼───────────┼────────────────┼───────────────┼───────────────────┼───┤ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ └─────────┴───────────┴────────────────┴───────────────┴───────────────────┴───┘ @@ -507,7 +507,7 @@ def __getitem__(self, what): │ string │ string │ float64 │ float64 │ int64 │ … │ ├─────────┼───────────┼────────────────┼───────────────┼───────────────────┼───┤ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -530,7 +530,7 @@ def __getitem__(self, what): │ Torgersen │ 39.1 │ │ Torgersen │ 39.5 │ │ Torgersen │ 40.3 │ - │ Torgersen │ nan │ + │ Torgersen │ NULL │ │ Torgersen │ 36.7 │ └───────────┴────────────────┘ >>> t["island", "bill_length_mm"].head() @@ -542,7 +542,7 @@ def __getitem__(self, what): │ Torgersen │ 39.1 │ │ Torgersen │ 39.5 │ │ Torgersen │ 40.3 │ - │ Torgersen │ nan │ + │ Torgersen │ NULL │ │ Torgersen │ 36.7 │ └───────────┴────────────────┘ >>> t[_.island, _.bill_length_mm].head() @@ -554,7 +554,7 @@ def __getitem__(self, what): │ Torgersen │ 39.1 │ │ Torgersen │ 39.5 │ │ Torgersen │ 40.3 │ - │ Torgersen │ nan │ + │ Torgersen │ NULL │ │ Torgersen │ 36.7 │ └───────────┴────────────────┘ @@ -584,7 +584,7 @@ def __getitem__(self, what): │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ └─────────┴───────────┴────────────────┴───────────────┴───────────────────┴───┘ >>> t[s.r["bill_length_mm":"body_mass_g"]].head() @@ -596,7 +596,7 @@ def __getitem__(self, what): │ 39.1 │ 18.7 │ 181 │ 3750 │ │ 39.5 │ 17.4 │ 186 │ 3800 │ │ 40.3 │ 18.0 │ 195 │ 3250 │ - │ nan │ nan │ NULL │ NULL │ + │ NULL │ NULL │ NULL │ NULL │ │ 36.7 │ 19.3 │ 193 │ 3450 │ └────────────────┴───────────────┴───────────────────┴─────────────┘ """ @@ -1062,7 +1062,7 @@ def distinct( │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -1074,47 +1074,47 @@ def distinct( Compute the distinct rows of a subset of columns - >>> t[["species", "island"]].distinct() + >>> t[["species", "island"]].distinct().order_by(s.all()) ┏━━━━━━━━━━━┳━━━━━━━━━━━┓ ┃ species ┃ island ┃ ┡━━━━━━━━━━━╇━━━━━━━━━━━┩ │ string │ string │ ├───────────┼───────────┤ - │ Adelie │ Torgersen │ │ Adelie │ Biscoe │ │ Adelie │ Dream │ - │ Gentoo │ Biscoe │ + │ Adelie │ Torgersen │ │ Chinstrap │ Dream │ + │ Gentoo │ Biscoe │ └───────────┴───────────┘ Drop all duplicate rows except the first - >>> t.distinct(on=["species", "island"], keep="first") + >>> t.distinct(on=["species", "island"], keep="first").order_by(s.all()) ┏━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━┓ ┃ species ┃ island ┃ bill_length_mm ┃ bill_depth_… ┃ flipper_length_mm ┃ ┃ ┡━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━┩ │ string │ string │ float64 │ float64 │ int64 │ │ ├───────────┼───────────┼────────────────┼──────────────┼───────────────────┼──┤ - │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ │ │ Adelie │ Biscoe │ 37.8 │ 18.3 │ 174 │ │ │ Adelie │ Dream │ 39.5 │ 16.7 │ 178 │ │ - │ Gentoo │ Biscoe │ 46.1 │ 13.2 │ 211 │ │ + │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ │ │ Chinstrap │ Dream │ 46.5 │ 17.9 │ 192 │ │ + │ Gentoo │ Biscoe │ 46.1 │ 13.2 │ 211 │ │ └───────────┴───────────┴────────────────┴──────────────┴───────────────────┴──┘ Drop all duplicate rows except the last - >>> t.distinct(on=["species", "island"], keep="last") + >>> t.distinct(on=["species", "island"], keep="last").order_by(s.all()) ┏━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━┓ ┃ species ┃ island ┃ bill_length_mm ┃ bill_depth_… ┃ flipper_length_mm ┃ ┃ ┡━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━┩ │ string │ string │ float64 │ float64 │ int64 │ │ ├───────────┼───────────┼────────────────┼──────────────┼───────────────────┼──┤ - │ Adelie │ Torgersen │ 43.1 │ 19.2 │ 197 │ │ │ Adelie │ Biscoe │ 42.7 │ 18.3 │ 196 │ │ │ Adelie │ Dream │ 41.5 │ 18.5 │ 201 │ │ - │ Gentoo │ Biscoe │ 49.9 │ 16.1 │ 213 │ │ + │ Adelie │ Torgersen │ 43.1 │ 19.2 │ 197 │ │ │ Chinstrap │ Dream │ 50.2 │ 18.7 │ 198 │ │ + │ Gentoo │ Biscoe │ 49.9 │ 16.1 │ 213 │ │ └───────────┴───────────┴────────────────┴──────────────┴───────────────────┴──┘ Drop all duplicated rows @@ -1137,7 +1137,7 @@ def distinct( ├─────────┼───────────┼────────────────┼───────────────┼───────────────────┼───┤ │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Biscoe │ 37.8 │ 18.3 │ 174 │ … │ │ Adelie │ Biscoe │ 37.7 │ 18.7 │ 180 │ … │ │ Adelie │ Dream │ 39.5 │ 16.7 │ 178 │ … │ @@ -1639,7 +1639,7 @@ def mutate( │ Adelie │ 2007 │ 39.1 │ │ Adelie │ 2007 │ 39.5 │ │ Adelie │ 2007 │ 40.3 │ - │ Adelie │ 2007 │ nan │ + │ Adelie │ 2007 │ NULL │ │ Adelie │ 2007 │ 36.7 │ │ Adelie │ 2007 │ 39.3 │ │ Adelie │ 2007 │ 38.9 │ @@ -1660,7 +1660,7 @@ def mutate( │ Adelie │ 2007 │ 39.1 │ 2008 │ │ Adelie │ 2007 │ 39.5 │ 2008 │ │ Adelie │ 2007 │ 40.3 │ 2008 │ - │ Adelie │ 2007 │ nan │ 2008 │ + │ Adelie │ 2007 │ NULL │ 2008 │ │ Adelie │ 2007 │ 36.7 │ 2008 │ └─────────┴───────┴────────────────┴───────────┘ @@ -1677,7 +1677,7 @@ def mutate( │ Adelie │ -4.82193 │ │ Adelie │ -4.42193 │ │ Adelie │ -3.62193 │ - │ Adelie │ nan │ + │ Adelie │ NULL │ │ Adelie │ -7.22193 │ └─────────┴─────────────┘ @@ -1692,7 +1692,7 @@ def mutate( │ Adelie │ 2007 │ -4.82193 │ │ Adelie │ 2007 │ -4.42193 │ │ Adelie │ 2007 │ -3.62193 │ - │ Adelie │ 2007 │ nan │ + │ Adelie │ 2007 │ NULL │ │ Adelie │ 2007 │ -7.22193 │ └─────────┴───────┴────────────────┘ """ @@ -1755,7 +1755,7 @@ def select( │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -1776,7 +1776,7 @@ def select( │ Torgersen │ 39.1 │ │ Torgersen │ 39.5 │ │ Torgersen │ 40.3 │ - │ Torgersen │ nan │ + │ Torgersen │ NULL │ │ Torgersen │ 36.7 │ └───────────┴────────────────┘ @@ -1791,7 +1791,7 @@ def select( │ Torgersen │ 39.1 │ │ Torgersen │ 39.5 │ │ Torgersen │ 40.3 │ - │ Torgersen │ nan │ + │ Torgersen │ NULL │ │ Torgersen │ 36.7 │ └───────────┴────────────────┘ @@ -1869,7 +1869,7 @@ def select( │ 39.1 │ 18.7 │ 181 │ 3750 │ │ 39.5 │ 17.4 │ 186 │ 3800 │ │ 40.3 │ 18.0 │ 195 │ 3250 │ - │ nan │ nan │ NULL │ NULL │ + │ NULL │ NULL │ NULL │ NULL │ │ 36.7 │ 19.3 │ 193 │ 3450 │ └────────────────┴───────────────┴───────────────────┴─────────────┘ @@ -2156,7 +2156,7 @@ def drop(self, *fields: str | Selector) -> Table: │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -2177,7 +2177,7 @@ def drop(self, *fields: str | Selector) -> Table: │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Torgersen │ nan │ nan │ NULL │ … │ + │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ └───────────┴────────────────┴───────────────┴───────────────────┴───┘ >>> t.drop("species", "bill_length_mm").head() @@ -2189,7 +2189,7 @@ def drop(self, *fields: str | Selector) -> Table: │ Torgersen │ 18.7 │ 181 │ 3750 │ male │ … │ │ Torgersen │ 17.4 │ 186 │ 3800 │ female │ … │ │ Torgersen │ 18.0 │ 195 │ 3250 │ female │ … │ - │ Torgersen │ nan │ NULL │ NULL │ NULL │ … │ + │ Torgersen │ NULL │ NULL │ NULL │ NULL │ … │ │ Torgersen │ 19.3 │ 193 │ 3450 │ female │ … │ └───────────┴───────────────┴───────────────────┴─────────────┴────────┴───┘ @@ -2257,7 +2257,7 @@ def filter( │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -2393,7 +2393,7 @@ def dropna( │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -2868,7 +2868,7 @@ def cross_join( │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -2950,7 +2950,7 @@ def alias(self, alias: str) -> ir.Table: │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ └─────────┴───────────┴────────────────┴───────────────┴───────────────────┴───┘ """ @@ -3103,7 +3103,7 @@ def cache(self) -> Table: │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ @@ -3126,7 +3126,7 @@ def cache(self) -> Table: │ Adelie │ Torgersen │ 39.1 │ 18.7 │ 181 │ … │ │ Adelie │ Torgersen │ 39.5 │ 17.4 │ 186 │ … │ │ Adelie │ Torgersen │ 40.3 │ 18.0 │ 195 │ … │ - │ Adelie │ Torgersen │ nan │ nan │ NULL │ … │ + │ Adelie │ Torgersen │ NULL │ NULL │ NULL │ … │ │ Adelie │ Torgersen │ 36.7 │ 19.3 │ 193 │ … │ │ Adelie │ Torgersen │ 39.3 │ 20.6 │ 190 │ … │ │ Adelie │ Torgersen │ 38.9 │ 17.8 │ 181 │ … │ diff --git a/ibis/selectors.py b/ibis/selectors.py index 0bbd5bf99293..8cdda077e01e 100644 --- a/ibis/selectors.py +++ b/ibis/selectors.py @@ -485,7 +485,7 @@ def across( │ 39.1 │ 18.7 │ -4.82193 │ … │ │ 39.5 │ 17.4 │ -4.42193 │ … │ │ 40.3 │ 18.0 │ -3.62193 │ … │ - │ nan │ nan │ nan │ … │ + │ NULL │ NULL │ NULL │ … │ │ 36.7 │ 19.3 │ -7.22193 │ … │ │ 39.3 │ 20.6 │ -4.62193 │ … │ │ 38.9 │ 17.8 │ -5.02193 │ … │ diff --git a/ibis/tests/expr/mocks.py b/ibis/tests/expr/mocks.py index e1010ccd3864..77cf82d1e797 100644 --- a/ibis/tests/expr/mocks.py +++ b/ibis/tests/expr/mocks.py @@ -54,23 +54,22 @@ def get_schema(self, name): name = name.replace("`", "") return Schema.from_tuples(MOCK_TABLES[name]) - def execute(self, expr, limit=None, params=None, **kwargs): - import pandas as pd - + def to_pyarrow(self, expr, limit=None, params=None, **kwargs): ast = self.compiler.to_ast_ensure_limit(expr, limit, params=params) for query in ast.queries: self.executed_queries.append(query.compile()) - try: - schema = expr.schema() - except AttributeError: - schema = expr.as_table().schema() - df = pd.DataFrame([], columns=schema.names) if isinstance(expr, ir.Scalar): return None elif isinstance(expr, ir.Column): - return df.iloc[:, 0] - return df + schema = expr.as_table().schema() + return schema.to_pyarrow().empty_table()[0] + else: + return expr.schema().to_pyarrow().empty_table() + + def execute(self, expr, limit=None, params=None, **kwargs): + out = self.to_pyarrow(expr, limit=limit, params=params, **kwargs) + return None if out is None else out.to_pandas() def compile( self, diff --git a/ibis/tests/expr/test_pretty_repr.py b/ibis/tests/expr/test_pretty_repr.py index 2b905a5bbaf9..547c0d537fa4 100644 --- a/ibis/tests/expr/test_pretty_repr.py +++ b/ibis/tests/expr/test_pretty_repr.py @@ -146,7 +146,7 @@ def test_format_short_string_column(): assert max_len == 4 -def test_format_nested_column(): +def test_format_struct_column(): dtype = dt.Struct({"x": "int", "y": "float"}) values = [{"x": 1, "y": 2.5}, None] fmts, min_len, max_len = format_column(dtype, values) @@ -155,6 +155,15 @@ def test_format_nested_column(): assert max_len is None +def test_format_map_column(): + dtype = dt.Map(dt.String(), dt.Int32()) + values = [[("x", 1), ("y", 2.5)], None] + fmts, min_len, max_len = format_column(dtype, values) + assert str(fmts[1]) == null + assert min_len == 20 + assert max_len is None + + def test_format_fully_null_column(): values = [None, None, None] fmts, *_ = format_column(dt.int64, values)