diff --git a/narwhals/_utils.py b/narwhals/_utils.py index 370091a461..a02552e90a 100644 --- a/narwhals/_utils.py +++ b/narwhals/_utils.py @@ -1314,7 +1314,11 @@ def is_slice_index(obj: Any) -> TypeIs[_SliceIndex]: return isinstance(obj, slice) and ( isinstance(obj.start, int) or isinstance(obj.stop, int) - or (isinstance(obj.step, int) and obj.start is None and obj.stop is None) + or ( + isinstance(obj.step, (int, NoneType)) + and obj.start is None + and obj.stop is None + ) ) @@ -2141,3 +2145,6 @@ def __repr__(self) -> str: # pragma: no cover # the "no_default" sentinel should typically be used when one of the valid parameter # values is None, as otherwise we cannot determine if the caller has set that value. no_default = _NoDefault.no_default + +# Can be imported from types in Python 3.10 +NoneType = type(None) diff --git a/tests/series_only/getitem_test.py b/tests/series_only/getitem_test.py index cecb8099ee..aa63ac8414 100644 --- a/tests/series_only/getitem_test.py +++ b/tests/series_only/getitem_test.py @@ -5,7 +5,7 @@ import pytest import narwhals as nw -from tests.utils import assert_equal_data +from tests.utils import assert_equal_data, assert_equal_series if TYPE_CHECKING: from tests.utils import ConstructorEager @@ -38,6 +38,9 @@ def test_by_slice(constructor_eager: ConstructorEager) -> None: result = {"b": df[[], 1]} expected = {"b": []} assert_equal_data(result, expected) + result_ser = df[:, 0][slice(None)] + expected_ser = [1, 2, 3] + assert_equal_series(result_ser, expected_ser, name="a") def test_getitem_arrow_scalar() -> None: