Skip to content

Commit 397473c

Browse files
authored
Merge pull request #23 from kbsriram/islice-fix
Update `islice` to align behavior closer to CP
2 parents 7a6f049 + 0d95ebc commit 397473c

File tree

3 files changed

+119
-3
lines changed

3 files changed

+119
-3
lines changed

adafruit_itertools/__init__.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -342,17 +342,34 @@ def islice(p, start, stop=(), step=1):
342342
if stop == ():
343343
stop = start
344344
start = 0
345+
if stop is not None and stop < 0:
346+
raise ValueError("stop must be None or >= 0")
347+
if start < 0:
348+
raise ValueError("start must be >= 0")
349+
if step <= 0:
350+
raise ValueError("step must be > 0")
351+
345352
# TODO: optimizing or breaking semantics?
346353
if stop is not None and start >= stop:
347354
return
348355
it = iter(p)
349356
for _ in range(start):
350-
next(it)
357+
try:
358+
next(it)
359+
except StopIteration:
360+
return
351361

352362
while True:
353-
yield next(it)
363+
try:
364+
val = next(it)
365+
except StopIteration:
366+
return
367+
yield val
354368
for _ in range(step - 1):
355-
next(it)
369+
try:
370+
next(it)
371+
except StopIteration:
372+
return
356373
start += step
357374
if stop is not None and start >= stop:
358375
return

tests/README.rst

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
..
2+
SPDX-FileCopyrightText: KB Sriram
3+
SPDX-License-Identifier: MIT
4+
..
5+
6+
Itertools Tests
7+
===============
8+
9+
These tests run under CPython, and are intended to verify that the
10+
Adafruit library functions return the same outputs compared to ones in
11+
the standard `itertools` module.
12+
13+
These tests run automatically from the standard `circuitpython github
14+
workflow <wf_>`_. To run them manually, first install these packages
15+
if necessary::
16+
17+
$ pip3 install pytest
18+
19+
Then ensure you're in the *root* directory of the repository and run
20+
the following command::
21+
22+
$ python -m pytest
23+
24+
.. _wf: https://github.com/adafruit/workflows-circuitpython-libs/blob/6e1562eaabced4db1bd91173b698b1cc1dfd35ab/build/action.yml#L78-L84

tests/test_itertools.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# SPDX-FileCopyrightText: KB Sriram
2+
# SPDX-License-Identifier: MIT
3+
4+
from typing import Iterator, Optional, Sequence, TypeVar
5+
import itertools as it
6+
import pytest
7+
import adafruit_itertools as ait
8+
9+
_T = TypeVar("_T")
10+
11+
12+
@pytest.mark.parametrize(
13+
"seq, start",
14+
[
15+
("", 0),
16+
("", 2),
17+
("ABCDEFG", 0),
18+
("ABCDEFG", 2),
19+
("ABCDEFG", 20),
20+
],
21+
)
22+
def test_islice_start(seq: Sequence[_T], start: int) -> None:
23+
x: Iterator[_T] = ait.islice(seq, start)
24+
y: Iterator[_T] = it.islice(seq, start)
25+
assert list(x) == list(y)
26+
27+
28+
@pytest.mark.parametrize(
29+
"seq, start, stop",
30+
[
31+
("", 0, 5),
32+
("", 2, 5),
33+
("", 0, 0),
34+
("ABCDEFG", 2, 2),
35+
("ABCDEFG", 2, 6),
36+
("ABCDEFG", 2, None),
37+
("ABCDEFG", 2, 17),
38+
("ABCDEFG", 20, 30),
39+
],
40+
)
41+
def test_islice_start_stop(seq: Sequence[_T], start: int, stop: Optional[int]) -> None:
42+
x: Iterator[_T] = ait.islice(seq, start, stop)
43+
y: Iterator[_T] = it.islice(seq, start, stop)
44+
assert list(x) == list(y)
45+
46+
47+
@pytest.mark.parametrize(
48+
"seq, start, stop, step",
49+
[
50+
("", 0, 5, 3),
51+
("", 2, 5, 2),
52+
("", 0, 0, 1),
53+
("ABCDEFG", 2, 2, 2),
54+
("ABCDEFG", 2, 6, 3),
55+
("ABCDEFG", 2, 17, 2),
56+
("ABCDEFG", 0, None, 2),
57+
("ABCDEFG", 20, 30, 3),
58+
("ABCDEFG", 0, None, 3),
59+
],
60+
)
61+
def test_islice_start_stop_step(
62+
seq: Sequence[_T], start: int, stop: Optional[int], step: int
63+
) -> None:
64+
x: Iterator[_T] = ait.islice(seq, start, stop, step)
65+
y: Iterator[_T] = it.islice(seq, start, stop, step)
66+
assert list(x) == list(y)
67+
68+
69+
def test_islice_error() -> None:
70+
with pytest.raises(ValueError):
71+
list(ait.islice("abc", -1))
72+
with pytest.raises(ValueError):
73+
list(ait.islice("abc", 0, -1))
74+
with pytest.raises(ValueError):
75+
list(ait.islice("abc", 0, 0, 0))

0 commit comments

Comments
 (0)