Commit MetaInfo

Revision46484dcd29f103d1a43e19f92378ebfca98c71a4 (tree)
Time2022-06-25 22:30:56
AuthorAntoon Pardon <aej@pard...>
CommiterAntoon Pardon

Log Message

Peeker class added

Change Summary

Incremental Difference

diff -r 7d9c15e382f8 -r 46484dcd29f1 source/iterators.py
--- a/source/iterators.py Sat Jun 25 11:20:19 2022 +0200
+++ b/source/iterators.py Sat Jun 25 15:30:56 2022 +0200
@@ -37,6 +37,8 @@
3737 # http://code.activestate.com/recipes/580625-collection-pipeline-in-python/
3838 #
3939
40+_INVALID = object()
41+
4042 class PipeIterator:
4143 '''
4244 Base class for constructing iterators that work like a pipe in the
@@ -64,7 +66,7 @@
6466 This class produces a pipe iterator that will turn an iterator into a new
6567 iterator where the new items are the result of applying the function.
6668
67- double = partial(operator.__mul__, 2)
69+ double = partial(operator.__mul__, 2)
6870 [3, 5, 8] | Map(double) --> 6, 10, 16
6971 """
7072 # pylint: disable=too-few-public-methods
@@ -76,7 +78,7 @@
7678 This class produces a pipe iterator that will turn an iterable of iterables
7779 into a new iterables of iterables where the new items are the result of applying the function.
7880
79- double = partial(operator.__mul__, 2)
81+ double = partial(operator.__mul__, 2)
8082 [[3, 5, 8], [7, 4], [2]] | SubMap(double) --> [6, 10, 16], [14, 8], [4]
8183 """
8284 # pylint: disable=too-few-public-methods
@@ -122,3 +124,32 @@
122124 # pylint: disable=too-few-public-methods
123125 def __init__(self, condition: Callable[[Iterator[Any]], Any] ):
124126 super().__init__(partial(filterfalse, condition))
127+
128+
129+class Peeker:
130+ """
131+ This class allows to peek ahead in an iterator
132+ """
133+ # pylint: disable=too-few-public-methods
134+ def __init__(self, iterable: Iterable[Any]):
135+ self.iterator = iter(iterable)
136+ self.next = _INVALID
137+
138+ def __iter__(self):
139+ return self
140+
141+ def __next__(self):
142+ if self.next is _INVALID:
143+ next_item = next(self.iterator)
144+ else:
145+ next_item = self.next
146+ self.next = _INVALID
147+ return next_item
148+
149+ def peek(self):
150+ """
151+ This method looks one item ahead in the iterator
152+ """
153+ if self.next is _INVALID:
154+ self.next = next(self.iterator)
155+ return self.next
diff -r 7d9c15e382f8 -r 46484dcd29f1 source/release.cfg
--- a/source/release.cfg Sat Jun 25 11:20:19 2022 +0200
+++ b/source/release.cfg Sat Jun 25 15:30:56 2022 +0200
@@ -1,3 +1,3 @@
1-version = '0.01.02g'
2-modified = '2022-06-25 @ 11:14:01'
1+version = '0.01.03d'
2+modified = '2022-06-25 @ 13:06:19'
33 installed = '*********************'
diff -r 7d9c15e382f8 -r 46484dcd29f1 tests/iterators.py
--- a/tests/iterators.py Sat Jun 25 11:20:19 2022 +0200
+++ b/tests/iterators.py Sat Jun 25 15:30:56 2022 +0200
@@ -1,14 +1,14 @@
11
22 # pylint: disable=missing-function-docstring,invalid-name,missing-module-docstring
33
4-from unittest import TestCase, main as unitmain
4+from unittest import TestCase, main as unitmain #, skip
55 from random import shuffle
66 from itertools import product
77
88 from typing import List
99
1010 # pylint: disable=unused-import
11-from AGPlib.iterators import PipeIterator, Apply, Map, concat, SubMap, Select, Discard
11+from AGPlib.iterators import PipeIterator, Apply, Map, concat, SubMap, Select, Discard, Peeker
1212 # pylint: enable=unused-import
1313
1414 SIZE_LIMIT = 101
@@ -121,4 +121,39 @@
121121 s.assertEqual(result0, result1)
122122 s.assertEqual(result0, result2)
123123
124+class IterCase(TestCase):
125+ """
126+ TestCase for the other iterators
127+ """
128+
129+ def test_empty_peeker(s):
130+ with s.assertRaises(StopIteration):
131+ Peeker([]).peek()
132+
133+ def test_peeker_is_iterator(s):
134+ for size in range(SIZE_LIMIT):
135+ source = shuffled_range_list(size)
136+ peeker = Peeker(source)
137+ s.assertIs(peeker, iter(peeker))
138+
139+ def test_peeker_iterates_over_its_source(s):
140+ for size in range(SIZE_LIMIT):
141+ source = shuffled_range_list(size)
142+ peeker = Peeker(source)
143+ for item, peeked in zip(source, peeker):
144+ s.assertEqual(item, peeked)
145+
146+ def test_peek_ahead(s):
147+ for size in range(1, SIZE_LIMIT):
148+ source = shuffled_range_list(size)
149+ peeker = Peeker(source)
150+ peeked = peeker.peek()
151+ with s.assertRaises(StopIteration):
152+ Peeker([]).peek()
153+ index = 0
154+ for index, item in enumerate(peeker):
155+ s.assertEqual(item, peeked)
156+ peeked = peeker.peek()
157+ s.assertEqual(index + 1, size)
158+
124159 unitmain()
Show on old repository browser