From 39b486e5f470fb9376cb6a44c38dea6aaece3445 Mon Sep 17 00:00:00 2001 From: Petros Barbagiannis Date: Wed, 27 Mar 2024 23:26:54 +0200 Subject: [PATCH] fix(python): Raise properly for slices not supported by `LazyFrame` (#15331) Co-authored-by: alexander-beedie --- py-polars/polars/slice.py | 5 +++-- py-polars/tests/parametric/test_lazyframe.py | 22 ++++++++++++++----- py-polars/tests/unit/operations/test_slice.py | 18 +++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/py-polars/polars/slice.py b/py-polars/polars/slice.py index b2a9f370048e..d22bf3c3bdbf 100644 --- a/py-polars/polars/slice.py +++ b/py-polars/polars/slice.py @@ -146,7 +146,8 @@ def apply(self, s: slice) -> LazyFrame: # [i:<=i] # [i:>=i:-k] if (step > 0 and (s.stop is not None and start >= s.stop)) or ( - step < 0 and (s.stop is not None and s.stop >= s.start >= 0) + step < 0 + and (s.start is not None and s.stop is not None and s.stop >= s.start >= 0) ): return self.obj.clear() @@ -192,7 +193,7 @@ def apply(self, s: slice) -> LazyFrame: # --------------------------------------- # [-i:] => tail(abs(i)) # [-i::k] => tail(abs(i)).gather_every(k) - elif start < 0 and s.stop is None: + elif start < 0 and s.stop is None and step > 0: obj = self.obj.tail(abs(start)) return obj if (step == 1) else obj.gather_every(step) diff --git a/py-polars/tests/parametric/test_lazyframe.py b/py-polars/tests/parametric/test_lazyframe.py index 6e4b7d5dba35..d9d3ff0eb4a9 100644 --- a/py-polars/tests/parametric/test_lazyframe.py +++ b/py-polars/tests/parametric/test_lazyframe.py @@ -1,7 +1,7 @@ # ---------------------------------------------------- # Validate LazyFrame behaviour with parametric tests # ---------------------------------------------------- -from hypothesis import given +from hypothesis import example, given from hypothesis.strategies import integers import polars as pl @@ -16,25 +16,35 @@ column( "start", dtype=pl.Int8, - null_probability=0.15, - strategy=integers(min_value=-4, max_value=6), + null_probability=0.3, + strategy=integers(min_value=-3, max_value=4), ), column( "stop", dtype=pl.Int8, - null_probability=0.15, - strategy=integers(min_value=-2, max_value=8), + null_probability=0.3, + strategy=integers(min_value=-2, max_value=6), ), column( "step", dtype=pl.Int8, - null_probability=0.15, + null_probability=0.3, strategy=integers(min_value=-3, max_value=3).filter(lambda x: x != 0), ), column("misc", dtype=pl.Int32), ], ) ) +@example( + ldf=pl.LazyFrame( + { + "start": [-1, None, 1, None, 1, -1], + "stop": [None, 0, -1, -1, 2, 1], + "step": [-1, -1, 1, None, -1, 1], + "misc": [1, 2, 3, 4, 5, 6], + } + ) +) def test_lazyframe_slice(ldf: pl.LazyFrame) -> None: py_data = ldf.collect().rows() diff --git a/py-polars/tests/unit/operations/test_slice.py b/py-polars/tests/unit/operations/test_slice.py index 1e5f652c7882..8aecdd3116a4 100644 --- a/py-polars/tests/unit/operations/test_slice.py +++ b/py-polars/tests/unit/operations/test_slice.py @@ -222,3 +222,21 @@ def test_slice_pushdown_literal_projection_14349() -> None: plan = q.explain() assert plan.index("WITH_COLUMNS") < plan.index("SLICE") assert q.collect().height == 0 + + +@pytest.mark.parametrize( + "input_slice", + [ + (-1, None, -1), + (None, 0, -1), + (1, -1, 1), + (None, -1, None), + (1, 2, -1), + (-1, 1, 1), + ], +) +def test_slice_lazy_frame_raises_proper(input_slice: tuple[int | None]) -> None: + ldf = pl.LazyFrame({"a": [1, 2, 3]}) + s = slice(*input_slice) + with pytest.raises(ValueError, match="not supported"): + ldf[s].collect()