From bdb011928bcba8db5e8659ccb33fea31de908511 Mon Sep 17 00:00:00 2001 From: Pebaz Date: Sat, 20 Jun 2020 15:22:13 -0400 Subject: [PATCH] New chemical: current() The current() chemical allows you to look at the current element that has been returned from next(). Also found a bug in the trait() function that needlessly returned a closure rather than the class/function it was wrapping. Since it's only job is to add the class/function to the `it` class, it didn't need to also return the wrapper function. --- chemical/__init__.py | 2 +- chemical/iterators.py | 38 ++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- tests/test_chemical.py | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/chemical/__init__.py b/chemical/__init__.py index 63ba7f6..cf814a7 100644 --- a/chemical/__init__.py +++ b/chemical/__init__.py @@ -134,7 +134,7 @@ def wrapper(clazz): it.traits[bind.__name__.lower()] = bind inner.__doc__ = bind.__doc__ - return inner + return bind class Ordering(Enum): diff --git a/chemical/iterators.py b/chemical/iterators.py index 8d7221d..8cb0c5d 100644 --- a/chemical/iterators.py +++ b/chemical/iterators.py @@ -588,3 +588,41 @@ def _process_items(the_items): next(backward) return it(forward, backward, self.size_hint()) + + +@trait +class Current(Peekable): + """ + An iterator that lets you look at the current item in the iteration. + + Essentially holds onto the last item yielded from `next()`. Works like a + call to `peek()` but for the current element. + + Extends `Peekable` to retain `next()`, `curr()`, and `peek()` methods. + + For the first element, `curr()` behaves exactly like `peek()`. + + **Examples** + + :::python + + c = it('asdf').current() + assert c.curr() == 'a' + assert c.peek() == 'a' + assert c.next() == 'a' + assert c.curr() == 'a' + assert c.peek() == 's' + assert c.next() == 's' + """ + def __init__(self, items): + Peekable.__init__(self, items) + self.current_item = None + + def __next__(self): + self.current_item = Peekable.__next__(self) + return self.current_item + + def curr(self): + if not self._modified: + return self.peek() + return self.current_item diff --git a/setup.py b/setup.py index 59ff8bd..8098140 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='chemical', - version='1.0.0', + version='1.0.1', license="MIT", python_requires='>=3.6.0', description='Rust-style iterators for Python!', diff --git a/tests/test_chemical.py b/tests/test_chemical.py index 23a3b10..806a17b 100644 --- a/tests/test_chemical.py +++ b/tests/test_chemical.py @@ -780,3 +780,42 @@ def get(url, timeout): assert it('asdf').par_iter().size_hint() == (4, 4) assert it('asdf').par_iter().rev().size_hint() == (4, 4) + + +def test_current(): + assert it(range(4)).current().collect(str) == '0123' + assert (it(range(100)) + .skip(10) + .step_by(5) + .skip(10) + .current() + .skip_while(lambda x: x < 80) + .take(4) + .collect() + ) == [80, 85, 90, 95] + + assert it(range(10)).current().rev().collect() == [ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + ] + + with pytest.raises(ChemicalException): + a = it('asdf').current() + a.next() + a.rev() + + assert it('asdf').current().size_hint() == (4, 4) + assert it('asdf').current().rev().size_hint() == (4, 4) + + c = it('asdf').current() + assert c.curr() == 'a' + assert c.peek() == 'a' + assert c.next() == 'a' + assert c.curr() == 'a' + assert c.peek() == 's' + assert c.next() == 's' + assert c.curr() == 's' + assert c.peek() == 'd' + assert c.next() == 'd' + assert c.curr() == 'd' + assert c.peek() == 'f' + assert c.next() == 'f'