Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3487d68

Browse files
authored
feat: add iterator capability to paged iterators (#200)
* feat: add iterator capability to *Iterator classes The *Iterator classes are only _iterables_, and this commit also makes them _iterators_, i.e. calling next(iterator) on them now works. * Make AsyncIterator an actual async iterator
1 parent 641fbbf commit 3487d68

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

google/api_core/page_iterator.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ def __init__(
170170
max_results=None,
171171
):
172172
self._started = False
173+
self.__active_iterator = None
174+
173175
self.client = client
174176
"""Optional[Any]: The client that created this iterator."""
175177
self.item_to_value = item_to_value
@@ -228,6 +230,14 @@ def __iter__(self):
228230
self._started = True
229231
return self._items_iter()
230232

233+
def __next__(self):
234+
if self.__active_iterator is None:
235+
self.__active_iterator = iter(self)
236+
return next(self.__active_iterator)
237+
238+
# Preserve Python 2 compatibility.
239+
next = __next__
240+
231241
def _page_iter(self, increment):
232242
"""Generator of pages of API responses.
233243

google/api_core/page_iterator_async.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ def __init__(
101101
max_results=None,
102102
):
103103
self._started = False
104+
self.__active_aiterator = None
105+
104106
self.client = client
105107
"""Optional[Any]: The client that created this iterator."""
106108
self.item_to_value = item_to_value
@@ -159,6 +161,11 @@ def __aiter__(self):
159161
self._started = True
160162
return self._items_aiter()
161163

164+
async def __anext__(self):
165+
if self.__active_aiterator is None:
166+
self.__active_aiterator = self.__aiter__()
167+
return await self.__active_aiterator.__anext__()
168+
162169
async def _page_aiter(self, increment):
163170
"""Generator of pages of API responses.
164171

tests/asyncio/test_page_iterator_async.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,33 @@ def test_constructor(self):
4747
assert iterator.next_page_token == token
4848
assert iterator.num_results == 0
4949

50+
@pytest.mark.asyncio
51+
async def test_anext(self):
52+
parent = mock.sentinel.parent
53+
page_1 = page_iterator_async.Page(
54+
parent, ("item 1.1", "item 1.2"), page_iterator_async._item_to_value_identity
55+
)
56+
page_2 = page_iterator_async.Page(
57+
parent, ("item 2.1",), page_iterator_async._item_to_value_identity
58+
)
59+
60+
async_iterator = PageAsyncIteratorImpl(None, None)
61+
async_iterator._next_page = mock.AsyncMock(side_effect=[page_1, page_2, None])
62+
63+
# Consume items and check the state of the async_iterator.
64+
assert async_iterator.num_results == 0
65+
assert await async_iterator.__anext__() == "item 1.1"
66+
assert async_iterator.num_results == 1
67+
68+
assert await async_iterator.__anext__() == "item 1.2"
69+
assert async_iterator.num_results == 2
70+
71+
assert await async_iterator.__anext__() == "item 2.1"
72+
assert async_iterator.num_results == 3
73+
74+
with pytest.raises(StopAsyncIteration):
75+
await async_iterator.__anext__()
76+
5077
def test_pages_property_starts(self):
5178
iterator = PageAsyncIteratorImpl(None, None)
5279

tests/unit/test_page_iterator.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,26 @@ def test_constructor(self):
109109
assert iterator.next_page_token == token
110110
assert iterator.num_results == 0
111111

112+
def test_next(self):
113+
iterator = PageIteratorImpl(None, None)
114+
page_1 = page_iterator.Page(
115+
iterator, ("item 1.1", "item 1.2"), page_iterator._item_to_value_identity
116+
)
117+
page_2 = page_iterator.Page(
118+
iterator, ("item 2.1",), page_iterator._item_to_value_identity
119+
)
120+
iterator._next_page = mock.Mock(side_effect=[page_1, page_2, None])
121+
122+
result = next(iterator)
123+
assert result == "item 1.1"
124+
result = next(iterator)
125+
assert result == "item 1.2"
126+
result = next(iterator)
127+
assert result == "item 2.1"
128+
129+
with pytest.raises(StopIteration):
130+
next(iterator)
131+
112132
def test_pages_property_starts(self):
113133
iterator = PageIteratorImpl(None, None)
114134

0 commit comments

Comments
 (0)