Skip to content

Update islice to align behavior closer to CP #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions adafruit_itertools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,17 +342,34 @@ def islice(p, start, stop=(), step=1):
if stop == ():
stop = start
start = 0
if stop is not None and stop < 0:
raise ValueError("stop must be None or >= 0")
if start < 0:
raise ValueError("start must be >= 0")
if step <= 0:
raise ValueError("step must be > 0")

# TODO: optimizing or breaking semantics?
if stop is not None and start >= stop:
return
it = iter(p)
for _ in range(start):
next(it)
try:
next(it)
except StopIteration:
return

while True:
yield next(it)
try:
val = next(it)
except StopIteration:
return
yield val
for _ in range(step - 1):
next(it)
try:
next(it)
except StopIteration:
return
start += step
if stop is not None and start >= stop:
return
Expand Down
24 changes: 24 additions & 0 deletions tests/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
..
SPDX-FileCopyrightText: KB Sriram
SPDX-License-Identifier: MIT
..

Itertools Tests
===============

These tests run under CPython, and are intended to verify that the
Adafruit library functions return the same outputs compared to ones in
the standard `itertools` module.

These tests run automatically from the standard `circuitpython github
workflow <wf_>`_. To run them manually, first install these packages
if necessary::

$ pip3 install pytest

Then ensure you're in the *root* directory of the repository and run
the following command::

$ python -m pytest

.. _wf: https://github.com/adafruit/workflows-circuitpython-libs/blob/6e1562eaabced4db1bd91173b698b1cc1dfd35ab/build/action.yml#L78-L84
75 changes: 75 additions & 0 deletions tests/test_itertools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# SPDX-FileCopyrightText: KB Sriram
# SPDX-License-Identifier: MIT

from typing import Iterator, Optional, Sequence, TypeVar
import itertools as it
import pytest
import adafruit_itertools as ait

_T = TypeVar("_T")


@pytest.mark.parametrize(
"seq, start",
[
("", 0),
("", 2),
("ABCDEFG", 0),
("ABCDEFG", 2),
("ABCDEFG", 20),
],
)
def test_islice_start(seq: Sequence[_T], start: int) -> None:
x: Iterator[_T] = ait.islice(seq, start)
y: Iterator[_T] = it.islice(seq, start)
assert list(x) == list(y)


@pytest.mark.parametrize(
"seq, start, stop",
[
("", 0, 5),
("", 2, 5),
("", 0, 0),
("ABCDEFG", 2, 2),
("ABCDEFG", 2, 6),
("ABCDEFG", 2, None),
("ABCDEFG", 2, 17),
("ABCDEFG", 20, 30),
],
)
def test_islice_start_stop(seq: Sequence[_T], start: int, stop: Optional[int]) -> None:
x: Iterator[_T] = ait.islice(seq, start, stop)
y: Iterator[_T] = it.islice(seq, start, stop)
assert list(x) == list(y)


@pytest.mark.parametrize(
"seq, start, stop, step",
[
("", 0, 5, 3),
("", 2, 5, 2),
("", 0, 0, 1),
("ABCDEFG", 2, 2, 2),
("ABCDEFG", 2, 6, 3),
("ABCDEFG", 2, 17, 2),
("ABCDEFG", 0, None, 2),
("ABCDEFG", 20, 30, 3),
("ABCDEFG", 0, None, 3),
],
)
def test_islice_start_stop_step(
seq: Sequence[_T], start: int, stop: Optional[int], step: int
) -> None:
x: Iterator[_T] = ait.islice(seq, start, stop, step)
y: Iterator[_T] = it.islice(seq, start, stop, step)
assert list(x) == list(y)


def test_islice_error() -> None:
with pytest.raises(ValueError):
list(ait.islice("abc", -1))
with pytest.raises(ValueError):
list(ait.islice("abc", 0, -1))
with pytest.raises(ValueError):
list(ait.islice("abc", 0, 0, 0))