Repository: ibis-project/ibis

Issue:
depr: Remove Column.summary()
### What happened?

```python
from ibis import examples as ex
ex.Alfalfa.fetch().variety.summary()
```
results in simply `[72, 0, 3]`. Can we make this return a dict or something where each field has meaning? [The docstring](https://ibis-project.org/api/expressions/generic/?h=summary#ibis.expr.types.generic.Column.summary) could also use some love.

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:
Honestly, I'm not sure if this API is that useful.

Are you often calculating the same three aggregations that `summary` provides so that it does provide some level of convenience?

I'd rather remove this API than try to make it work better if we can.
Yeah, I would say just remove it. My favorite bugfix :)

Resolving patch:
diff --git a/ibis/expr/types/generic.py b/ibis/expr/types/generic.py
--- a/ibis/expr/types/generic.py
+++ b/ibis/expr/types/generic.py
@@ -5,6 +5,7 @@
 from public import public
 
 import ibis
+from ibis import util
 import ibis.common.exceptions as com
 import ibis.expr.datatypes as dt
 import ibis.expr.operations as ops
@@ -843,6 +844,11 @@ def topk(
             .limit(k)
         )
 
+    @util.deprecated(
+        instead="Reach out at https://github.com/ibis-project/ibis if you'd like this API to remain.",
+        as_of="5.0",
+        removed_in="6.0",
+    )
     def summary(
         self,
         exact_nunique: bool = False,
diff --git a/ibis/expr/types/groupby.py b/ibis/expr/types/groupby.py
--- a/ibis/expr/types/groupby.py
+++ b/ibis/expr/types/groupby.py
@@ -332,6 +332,11 @@ def __init__(self, arr, parent):
     approx_median = _group_agg_dispatch('approx_median')
     group_concat = _group_agg_dispatch('group_concat')
 
+    @util.deprecated(
+        instead="Reach out at https://github.com/ibis-project/ibis if you'd like this API to remain.",
+        as_of="5.0",
+        removed_in="6.0",
+    )
     def summary(self, exact_nunique=False):
         """Summarize a column.
 
diff --git a/ibis/expr/types/numeric.py b/ibis/expr/types/numeric.py
--- a/ibis/expr/types/numeric.py
+++ b/ibis/expr/types/numeric.py
@@ -7,6 +7,7 @@
 from public import public
 
 import ibis.expr.operations as ops
+from ibis import util
 from ibis.common.exceptions import IbisTypeError
 from ibis.expr.types.core import _binop
 from ibis.expr.types.generic import Column, Scalar, Value
@@ -583,6 +584,11 @@ def histogram(
 
         return ((self - base) / binwidth).floor()
 
+    @util.deprecated(
+        instead="Reach out at https://github.com/ibis-project/ibis if you'd like this API to remain.",
+        as_of="5.0",
+        removed_in="6.0",
+    )
     def summary(
         self,
         exact_nunique: bool = False,


Test patch:
diff --git a/ibis/backends/clickhouse/tests/test_aggregations.py b/ibis/backends/clickhouse/tests/test_aggregations.py
--- a/ibis/backends/clickhouse/tests/test_aggregations.py
+++ b/ibis/backends/clickhouse/tests/test_aggregations.py
@@ -168,7 +168,8 @@ def test_anonymous_aggregate(alltypes, df):
 
 
 def test_boolean_summary(alltypes):
-    bool_col_summary = alltypes.bool_col.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        bool_col_summary = alltypes.bool_col.summary()
     expr = alltypes.aggregate(bool_col_summary)
 
     result = expr.execute()
diff --git a/ibis/backends/dask/tests/execution/test_operations.py b/ibis/backends/dask/tests/execution/test_operations.py
--- a/ibis/backends/dask/tests/execution/test_operations.py
+++ b/ibis/backends/dask/tests/execution/test_operations.py
@@ -843,7 +843,8 @@ def q_fun(x, quantile, interpolation):
 
 
 def test_summary_numeric(batting, batting_df):
-    expr = batting.aggregate(batting.G.summary())
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.aggregate(batting.G.summary())
     result = expr.execute()
     assert len(result) == 1
 
@@ -861,7 +862,8 @@ def test_summary_numeric(batting, batting_df):
 
 
 def test_summary_numeric_group_by(batting, batting_df):
-    expr = batting.group_by('teamID').G.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.group_by('teamID').G.summary()
     result = expr.execute()
 
     def agg(s):
@@ -885,7 +887,8 @@ def agg(s):
 
 
 def test_summary_non_numeric(batting, batting_df):
-    expr = batting.aggregate(batting.teamID.summary())
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.aggregate(batting.teamID.summary())
     result = expr.execute()
     assert len(result) == 1
     assert len(result.columns) == 3
@@ -898,7 +901,8 @@ def test_summary_non_numeric(batting, batting_df):
 
 
 def test_summary_non_numeric_group_by(batting, batting_df):
-    expr = batting.group_by('teamID').playerID.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.group_by('teamID').playerID.summary()
     result = expr.execute()
     expected = (
         batting_df.groupby('teamID')
diff --git a/ibis/backends/impala/tests/test_exprs.py b/ibis/backends/impala/tests/test_exprs.py
--- a/ibis/backends/impala/tests/test_exprs.py
+++ b/ibis/backends/impala/tests/test_exprs.py
@@ -24,20 +24,22 @@ def test_summary_execute(alltypes):
     # also test set_column while we're at it
     table = table.set_column('double_col', table.double_col * 2)
 
-    metrics = table.double_col.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        metrics = table.double_col.summary()
     expr = table.aggregate(metrics)
     repr(expr)
 
     result = expr.execute()
     assert isinstance(result, pd.DataFrame)
 
-    expr = table.group_by('string_col').aggregate(
-        [
-            table.double_col.summary(prefix='double_'),
-            table.float_col.summary(prefix='float_'),
-            table.string_col.summary(suffix='_string'),
-        ]
-    )
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = table.group_by('string_col').aggregate(
+            [
+                table.double_col.summary(prefix='double_'),
+                table.float_col.summary(prefix='float_'),
+                table.string_col.summary(suffix='_string'),
+            ]
+        )
     result = expr.execute()
     assert isinstance(result, pd.DataFrame)
 
diff --git a/ibis/backends/pandas/tests/execution/test_operations.py b/ibis/backends/pandas/tests/execution/test_operations.py
--- a/ibis/backends/pandas/tests/execution/test_operations.py
+++ b/ibis/backends/pandas/tests/execution/test_operations.py
@@ -648,20 +648,22 @@ def q_fun(x, quantile, interpolation):
 
 
 def test_summary_execute(t):
-    expr = t.group_by('plain_strings').aggregate(
-        [
-            t.plain_int64.summary(prefix='int64_'),
-            t.plain_int64.summary(suffix='_int64'),
-            t.plain_datetimes_utc.summary(prefix='datetime_'),
-            t.plain_datetimes_utc.summary(suffix='_datetime'),
-        ]
-    )
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = t.group_by('plain_strings').aggregate(
+            [
+                t.plain_int64.summary(prefix='int64_'),
+                t.plain_int64.summary(suffix='_int64'),
+                t.plain_datetimes_utc.summary(prefix='datetime_'),
+                t.plain_datetimes_utc.summary(suffix='_datetime'),
+            ]
+        )
     result = expr.execute()
     assert isinstance(result, pd.DataFrame)
 
 
 def test_summary_numeric(batting, batting_df):
-    expr = batting.aggregate(batting.G.summary())
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.aggregate(batting.G.summary())
     result = expr.execute()
     assert len(result) == 1
 
@@ -679,7 +681,8 @@ def test_summary_numeric(batting, batting_df):
 
 
 def test_summary_numeric_group_by(batting, batting_df):
-    expr = batting.group_by('teamID').G.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.group_by('teamID').G.summary()
     result = expr.execute()
     expected = (
         batting_df.groupby('teamID')
@@ -707,7 +710,8 @@ def test_summary_numeric_group_by(batting, batting_df):
 
 
 def test_summary_non_numeric(batting, batting_df):
-    expr = batting.aggregate(batting.teamID.summary())
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.aggregate(batting.teamID.summary())
     result = expr.execute()
     assert len(result) == 1
     assert len(result.columns) == 3
@@ -720,7 +724,8 @@ def test_summary_non_numeric(batting, batting_df):
 
 
 def test_summary_non_numeric_group_by(batting, batting_df):
-    expr = batting.group_by('teamID').playerID.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        expr = batting.group_by('teamID').playerID.summary()
     result = expr.execute()
     expected = (
         batting_df.groupby('teamID')
diff --git a/ibis/backends/postgres/tests/test_functions.py b/ibis/backends/postgres/tests/test_functions.py
--- a/ibis/backends/postgres/tests/test_functions.py
+++ b/ibis/backends/postgres/tests/test_functions.py
@@ -1203,7 +1203,8 @@ def test_boolean_reduction(alltypes, opname, df):
 
 
 def test_boolean_summary(alltypes):
-    bool_col_summary = alltypes.bool_col.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        bool_col_summary = alltypes.bool_col.summary()
     expr = alltypes.aggregate(bool_col_summary)
 
     result = expr.execute()
diff --git a/ibis/backends/tests/test_aggregation.py b/ibis/backends/tests/test_aggregation.py
--- a/ibis/backends/tests/test_aggregation.py
+++ b/ibis/backends/tests/test_aggregation.py
@@ -1029,7 +1029,8 @@ def test_filter(backend, alltypes, df):
 
 @pytest.mark.notimpl(["polars", "datafusion", "pyspark", "mssql"])
 def test_column_summary(alltypes):
-    bool_col_summary = alltypes.bool_col.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        bool_col_summary = alltypes.bool_col.summary()
     expr = alltypes.aggregate(bool_col_summary)
     result = expr.execute()
     assert result.shape == (1, 7)
diff --git a/ibis/tests/expr/test_table.py b/ibis/tests/expr/test_table.py
--- a/ibis/tests/expr/test_table.py
+++ b/ibis/tests/expr/test_table.py
@@ -626,7 +626,8 @@ def test_groupby_alias(table):
 
 
 def test_summary_expand_list(table):
-    summ = table.f.summary()
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        summ = table.f.summary()
 
     metric = table.g.group_concat().name('bar')
     result = table.aggregate([metric, summ])
@@ -638,40 +639,45 @@ def test_summary_prefix_suffix(table):
     def get_names(exprs):
         return [e.get_name() for e in exprs]
 
-    assert get_names(table.g.summary(prefix="string_")) == [
-        'string_count',
-        'string_nulls',
-        'string_uniques',
-    ]
-    assert get_names(table.g.summary(suffix="_string")) == [
-        'count_string',
-        'nulls_string',
-        'uniques_string',
-    ]
-    assert get_names(table.g.summary(prefix="pre_", suffix="_post")) == [
-        'pre_count_post',
-        'pre_nulls_post',
-        'pre_uniques_post',
-    ]
-
-    assert get_names(table.f.summary(prefix="float_")) == [
-        "float_count",
-        "float_nulls",
-        "float_min",
-        "float_max",
-        "float_sum",
-        "float_mean",
-        "float_approx_nunique",
-    ]
-    assert get_names(table.f.summary(suffix="_numeric")) == [
-        "count_numeric",
-        "nulls_numeric",
-        "min_numeric",
-        "max_numeric",
-        "sum_numeric",
-        "mean_numeric",
-        "approx_nunique_numeric",
-    ]
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        assert get_names(table.g.summary(prefix="string_")) == [
+            'string_count',
+            'string_nulls',
+            'string_uniques',
+        ]
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        assert get_names(table.g.summary(suffix="_string")) == [
+            'count_string',
+            'nulls_string',
+            'uniques_string',
+        ]
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        assert get_names(table.g.summary(prefix="pre_", suffix="_post")) == [
+            'pre_count_post',
+            'pre_nulls_post',
+            'pre_uniques_post',
+        ]
+
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        assert get_names(table.f.summary(prefix="float_")) == [
+            "float_count",
+            "float_nulls",
+            "float_min",
+            "float_max",
+            "float_sum",
+            "float_mean",
+            "float_approx_nunique",
+        ]
+    with pytest.warns(FutureWarning, match="is deprecated"):
+        assert get_names(table.f.summary(suffix="_numeric")) == [
+            "count_numeric",
+            "nulls_numeric",
+            "min_numeric",
+            "max_numeric",
+            "sum_numeric",
+            "mean_numeric",
+            "approx_nunique_numeric",
+        ]
 
 
 def test_filter_aggregate_pushdown_predicate(table):