From e09ce40dcaf224b21aee709d38683f75acd8dc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Fri, 2 Apr 2021 20:28:00 +0200 Subject: [PATCH] 2.15.4 --- CHANGELOG.md | 1 + docs/coding/structures.rst | 6 ++ satella/__init__.py | 2 +- satella/coding/structures/__init__.py | 2 + satella/coding/structures/push_iterable.py | 66 ++++++++++++++++++++++ tests/test_coding/test_structures.py | 20 ++++++- 6 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 satella/coding/structures/push_iterable.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 07ff7c9d..3af8fc87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,3 +3,4 @@ **bugfix release** * fixed import problem +* added diff --git a/docs/coding/structures.rst b/docs/coding/structures.rst index e7486d0e..79b679ff 100644 --- a/docs/coding/structures.rst +++ b/docs/coding/structures.rst @@ -6,6 +6,12 @@ Structures :members: +PushIterable +------------ + +.. autoclass:: satella.coding.structures.PushIterable + :members: + SyncableDroppable ----------------- diff --git a/satella/__init__.py b/satella/__init__.py index 4895c882..e824526d 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.15.3' +__version__ = '2.15.4' diff --git a/satella/coding/structures/__init__.py b/satella/coding/structures/__init__.py index c1d21f02..e0efee2b 100644 --- a/satella/coding/structures/__init__.py +++ b/satella/coding/structures/__init__.py @@ -18,8 +18,10 @@ from .typednamedtuple import typednamedtuple from .lru import LRU from .syncable_droppable import DBStorage, SyncableDroppable from .tuples import Vector +from .push_iterable import PushIterable __all__ = [ + 'PushIterable', 'Vector', 'DBStorage', 'SyncableDroppable', 'LRU', diff --git a/satella/coding/structures/push_iterable.py b/satella/coding/structures/push_iterable.py new file mode 100644 index 00000000..4daad6ef --- /dev/null +++ b/satella/coding/structures/push_iterable.py @@ -0,0 +1,66 @@ +import typing as tp +from collections import deque + +from satella.coding.typing import T + + +class PushIterable(tp.Generic[T]): + """ + An iterable that you can add elements to it's head, and they will be popped + before this iterable is consumed when a pop is called. + + Example: + + .. code-block:: python + + a = PushIterable([1, 2, 3]) + assert a.pop() == 1 + a.push(0) + assert a.pop() == 0 + assert a.pop() == 2 + a.push(0) + a.push(1) + assert a.pop() == 1 + assert a.pop() == 0 + a.push_left(0) + a.push_left(1) + assert a.pop() == 0 + assert a.pop() == 1 + assert a.pop() == 3 + assertRaises(StopIteration, a.pop) + """ + def __init__(self, iterable: tp.Iterable[T]): + self.iterable = iter(iterable) + self.collection = deque() + + def pop(self) -> T: + """ + Return next element from the stack + :return: a next element + """ + if not self.collection: + return next(self.iterable) + else: + return self.collection.pop() + + def __iter__(self): + return self + + def __next__(self) -> T: + return self.pop() + + def push(self, item: T) -> None: + """ + Push an item so that next pop will retrieve this item + + :param item: item to push + """ + self.collection.append(item) + + def push_left(self, item): + """ + Push an item so that last pop from internal buffer will retrieve this item + + :param item: item to push + """ + self.collection.appendleft(item) diff --git a/tests/test_coding/test_structures.py b/tests/test_coding/test_structures.py index 8b544849..9d7a7605 100644 --- a/tests/test_coding/test_structures.py +++ b/tests/test_coding/test_structures.py @@ -14,11 +14,29 @@ from satella.coding.structures import TimeBasedHeap, Heap, typednamedtuple, \ DirtyDict, KeyAwareDefaultDict, Proxy, ReprableMixin, TimeBasedSetHeap, ExpiringEntryDict, SelfCleaningDefaultDict, \ CacheDict, StrEqHashableMixin, ComparableIntEnum, HashableIntEnum, ComparableAndHashableBy, \ ComparableAndHashableByInt, SparseMatrix, ExclusiveWritebackCache, Subqueue, \ - CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict + CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict, PushIterable class TestMisc(unittest.TestCase): + def test_push_iterable(self): + + a = PushIterable([1, 2, 3]) + self.assertEqual(a.pop(), 1) + a.push(0) + self.assertEqual(a.pop(), 0) + self.assertEqual(a.pop(), 2) + a.push(0) + a.push(1) + self.assertEqual(a.pop(), 1) + self.assertEqual(a.pop(), 0) + a.push_left(0) + a.push_left(1) + self.assertEqual(a.pop(), 0) + self.assertEqual(a.pop(), 1) + self.assertEqual(a.pop(), 3) + self.assertRaises(StopIteration, a.pop) + def test_default_dict(self): a = DefaultDict(lambda: '') a[2] -- GitLab