Skip to content

Commit 750de7a

Browse files
authored
Merge pull request #24 from kbsriram/add-types-2
Type annotations for `adafruit_itertools`
2 parents 397473c + b70d9bf commit 750de7a

File tree

3 files changed

+420
-17
lines changed

3 files changed

+420
-17
lines changed

adafruit_itertools/__init__.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@
5353
pass
5454

5555

56-
def accumulate(iterable, func=lambda x, y: x + y):
56+
def accumulate(
57+
iterable: Iterable[_T],
58+
func: Callable[[_T, _T], _T] = lambda x, y: x + y, # type: ignore[operator]
59+
) -> Iterator[_T]:
5760
"""Make an iterator that returns accumulated sums, or accumulated
5861
results of other binary functions (specified via the optional func
5962
argument). If func is supplied, it should be a function of two
@@ -200,7 +203,7 @@ def count(start: _N = 0, step: _N = 1) -> Iterator[_N]:
200203
start += step
201204

202205

203-
def cycle(p):
206+
def cycle(p: Iterable[_T]) -> Iterator[_T]:
204207
"""Make an iterator returning elements from the iterable and saving a copy
205208
of each. When the iterable is exhausted, return elements from the saved
206209
copy. Repeats indefinitely.
@@ -209,7 +212,7 @@ def cycle(p):
209212
210213
"""
211214
try:
212-
len(p)
215+
len(p) # type: ignore[arg-type]
213216
except TypeError:
214217
# len() is not defined for this type. Assume it is
215218
# a finite iterable so we must cache the elements.
@@ -242,7 +245,9 @@ def dropwhile(predicate: _Predicate[_T], iterable: Iterable[_T]) -> Iterator[_T]
242245
yield x
243246

244247

245-
def filterfalse(predicate: _Predicate[_T], iterable: Iterable[_T]) -> Iterator[_T]:
248+
def filterfalse(
249+
predicate: Optional[_Predicate[_T]], iterable: Iterable[_T]
250+
) -> Iterator[_T]:
246251
"""Make an iterator that filters elements from iterable returning only those
247252
for which the predicate is False. If predicate is None, return the items
248253
that are false.
@@ -288,23 +293,29 @@ class groupby:
288293
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
289294
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
290295

291-
def __init__(self, iterable, key=None):
296+
def __init__(
297+
self,
298+
iterable: Iterable[_T],
299+
key: Optional[Callable[[_T], Any]] = None,
300+
):
292301
self.keyfunc = key if key is not None else lambda x: x
293302
self.it = iter(iterable)
294-
self.tgtkey = self.currkey = self.currvalue = object()
303+
# Sentinel values, not actually returned during iteration.
304+
self.currvalue: _T = object() # type: ignore[assignment]
305+
self.tgtkey = self.currkey = self.currvalue
295306

296-
def __iter__(self):
307+
def __iter__(self) -> Iterator[Tuple[Any, Iterator[_T]]]:
297308
return self
298309

299-
def __next__(self):
310+
def __next__(self) -> Tuple[Any, Iterator[_T]]:
300311
self.id = object()
301312
while self.currkey == self.tgtkey:
302313
self.currvalue = next(self.it) # Exit on StopIteration
303314
self.currkey = self.keyfunc(self.currvalue)
304315
self.tgtkey = self.currkey
305316
return (self.currkey, self._grouper(self.tgtkey, self.id))
306317

307-
def _grouper(self, tgtkey, id):
318+
def _grouper(self, tgtkey: Any, id: object) -> Iterator[_T]:
308319
while self.id is id and self.currkey == tgtkey:
309320
yield self.currvalue
310321
try:
@@ -314,7 +325,12 @@ def _grouper(self, tgtkey, id):
314325
self.currkey = self.keyfunc(self.currvalue)
315326

316327

317-
def islice(p, start, stop=(), step=1):
328+
def islice(
329+
p: Iterable[_T],
330+
start: int,
331+
stop: Optional[int] = (), # type: ignore[assignment]
332+
step: int = 1,
333+
) -> Iterator[_T]:
318334
"""Make an iterator that returns selected elements from the
319335
iterable. If start is non-zero and stop is unspecified, then the
320336
value for start is used as end, and start is taken to be 0. Thus the
@@ -420,7 +436,8 @@ def permutations(
420436
return
421437

422438

423-
def product(*args: Iterable[_T], r: int = 1) -> Iterator[Tuple[_T, ...]]:
439+
# def product(*args: Iterable[_T], r: int = 1) -> Iterator[Tuple[_T, ...]]:
440+
def product(*args: Iterable[Any], r: int = 1) -> Iterator[Tuple[Any, ...]]:
424441
"""Cartesian product of input iterables.
425442
426443
Roughly equivalent to nested for-loops in a generator expression. For
@@ -444,7 +461,7 @@ def product(*args: Iterable[_T], r: int = 1) -> Iterator[Tuple[_T, ...]]:
444461
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
445462
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
446463
pools = [tuple(pool) for pool in args] * r
447-
result: List[List[_T]] = [[]]
464+
result: List[List[Any]] = [[]]
448465
for pool in pools:
449466
result = [x + [y] for x in result for y in pool]
450467
for prod in result:
@@ -513,8 +530,8 @@ def tee(iterable: Iterable[_T], n: int = 2) -> Sequence[Iterator[_T]]:
513530

514531

515532
def zip_longest(
516-
*args: Iterable[_T], fillvalue: _OptionalFill = None
517-
) -> Iterator[Tuple[Union[_T, _OptionalFill], ...]]:
533+
*args: Iterable[Any], fillvalue: _OptionalFill = None
534+
) -> Iterator[Tuple[Any, ...]]:
518535
"""Make an iterator that aggregates elements from each of the
519536
iterables. If the iterables are of uneven length, missing values are
520537
filled-in with fillvalue. Iteration continues until the longest
@@ -524,7 +541,7 @@ def zip_longest(
524541
:param fillvalue: value to fill in those missing from shorter iterables
525542
"""
526543
# zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
527-
iterators: List[Iterator[Union[_T, _OptionalFill]]] = [iter(it) for it in args]
544+
iterators: List[Iterator[Any]] = [iter(it) for it in args]
528545
num_active = len(iterators)
529546
if not num_active:
530547
return

tests/README.rst

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Itertools Tests
88

99
These tests run under CPython, and are intended to verify that the
1010
Adafruit library functions return the same outputs compared to ones in
11-
the standard `itertools` module.
11+
the standard `itertools` module, and also to exercise some type
12+
annotations.
1213

1314
These tests run automatically from the standard `circuitpython github
1415
workflow <wf_>`_. To run them manually, first install these packages
@@ -21,4 +22,16 @@ the following command::
2122

2223
$ python -m pytest
2324

25+
Type annotation tests don't run automatically at this point. But to
26+
verify type-related issues manually, first install these packages if
27+
necessary::
28+
29+
$ pip3 install mypy
30+
31+
Then ensure you're in the *root* directory of the repository and run
32+
the following command::
33+
34+
$ mypy --warn-unused-ignores --disallow-untyped-defs tests
35+
36+
2437
.. _wf: https://github.com/adafruit/workflows-circuitpython-libs/blob/6e1562eaabced4db1bd91173b698b1cc1dfd35ab/build/action.yml#L78-L84

0 commit comments

Comments
 (0)