From ef3fe8d80a71662406a8dcb28d28e88dfbd66fd3 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:34:30 +0100 Subject: [PATCH] feat: raise informative error message if list or tuple is passed to `by` in *Frame.group_by --- py-polars/polars/dataframe/frame.py | 10 ++++++++++ py-polars/polars/lazyframe/frame.py | 10 ++++++++++ py-polars/tests/unit/operations/test_group_by.py | 7 +++++++ 3 files changed, 27 insertions(+) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index d0eb3b59eb9b..ae1a9260bf65 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -5741,6 +5741,16 @@ def group_by( │ c ┆ 3 ┆ 1 │ └─────┴─────┴─────┘ """ + for _key, value in named_by.items(): + if not isinstance(value, (str, pl.Expr, pl.Series)): + msg = ( + f"Expected Polars expression or object convertible to one, got {type(value)}.\n\n" + "Hint: if you tried\n" + f" group_by(by={value!r})\n" + "then you probably want to use this instead:\n" + f" group_by({value!r})" + ) + raise TypeError(msg) return GroupBy(self, *by, **named_by, maintain_order=maintain_order) @deprecate_renamed_parameter("by", "group_by", version="0.20.14") diff --git a/py-polars/polars/lazyframe/frame.py b/py-polars/polars/lazyframe/frame.py index 2935f9091057..074d269b0d2c 100644 --- a/py-polars/polars/lazyframe/frame.py +++ b/py-polars/polars/lazyframe/frame.py @@ -3357,6 +3357,16 @@ def group_by( │ c ┆ 1 ┆ 1.0 │ └─────┴─────┴─────┘ """ + for _key, value in named_by.items(): + if not isinstance(value, (str, pl.Expr, pl.Series)): + msg = ( + f"Expected Polars expression or object convertible to one, got {type(value)}.\n\n" + "Hint: if you tried\n" + f" group_by(by={value!r})\n" + "then you probably want to use this instead:\n" + f" group_by({value!r})" + ) + raise TypeError(msg) exprs = parse_into_list_of_expressions(*by, **named_by) lgb = self._ldf.group_by(exprs, maintain_order) return LazyGroupBy(lgb) diff --git a/py-polars/tests/unit/operations/test_group_by.py b/py-polars/tests/unit/operations/test_group_by.py index c2234035ffdb..a448a25c2370 100644 --- a/py-polars/tests/unit/operations/test_group_by.py +++ b/py-polars/tests/unit/operations/test_group_by.py @@ -1139,3 +1139,10 @@ def test_grouped_slice_literals() -> None: ), # slices a list of 1 element, so remains the same element x2=pl.lit(pl.Series([1, 2])).slice(-1, 1), ).to_dict(as_series=False) == {"literal": [True], "x": [[1, 2]], "x2": [2]} + + +def test_positional_by_with_list_or_tuple_17540() -> None: + with pytest.raises(TypeError, match="Hint: if you"): + pl.DataFrame({"a": [1, 2, 3]}).group_by(by=["a"]) + with pytest.raises(TypeError, match="Hint: if you"): + pl.LazyFrame({"a": [1, 2, 3]}).group_by(by=["a"])