Skip to content

Commit f4c2bcd

Browse files
committed
Exposing the current page in iterator.
1 parent 5326c88 commit f4c2bcd

1 file changed

Lines changed: 53 additions & 23 deletions

File tree

core/google/cloud/iterator.py

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
To make an iterator work, just override the ``PAGE_CLASS`` class
2121
attribute so that given a response (containing a page of results) can
2222
be parsed into an iterable page of the actual objects you want::
23-
those results into an iterable of the actual
2423
2524
class MyPage(Page):
2625
@@ -47,6 +46,29 @@ class MyIterator(Iterator):
4746
... print(my_item.name)
4847
... if not my_item.is_valid:
4948
... break
49+
50+
When iterating, not every new item will send a request to the server.
51+
To monitor these requests, track the current page of the iterator::
52+
53+
>>> iterator = MyIterator(...)
54+
>>> iterator.page_number
55+
0
56+
>>> next(iterator)
57+
<MyItemClass at 0x7f1d3cccf690>
58+
>>> iterator.page_number
59+
1
60+
>>> iterator.page.remaining
61+
1
62+
>>> next(iterator)
63+
<MyItemClass at 0x7f1d3cccfe90>
64+
>>> iterator.page.remaining
65+
0
66+
>>> next(iterator)
67+
<MyItemClass at 0x7f1d3cccffd0>
68+
>>> iterator.page_number
69+
2
70+
>>> iterator.page.remaining
71+
19
5072
"""
5173

5274

@@ -149,52 +171,60 @@ class Iterator(object):
149171

150172
def __init__(self, client, page_token=None, max_results=None,
151173
extra_params=None, path=None):
174+
self.extra_params = extra_params or {}
175+
self._verify_params()
152176
self.client = client
153-
if path is None:
154-
path = self.PATH
155-
self.path = path
177+
self.path = path or self.PATH
156178
self.page_number = 0
157179
self.next_page_token = page_token
158180
self.max_results = max_results
159181
self.num_results = 0
160-
self.extra_params = extra_params or {}
182+
self._page = None
183+
184+
def _verify_params(self):
185+
"""Verifies the parameters don't use any reserved parameter.
186+
187+
:raises ValueError: If a reserved parameter is used.
188+
"""
161189
reserved_in_use = self.RESERVED_PARAMS.intersection(
162190
self.extra_params)
163191
if reserved_in_use:
164-
raise ValueError(('Using a reserved parameter',
165-
reserved_in_use))
166-
self._curr_items = iter(())
192+
raise ValueError('Using a reserved parameter',
193+
reserved_in_use)
194+
195+
@property
196+
def page(self):
197+
"""The current page of results that has been retrieved.
198+
199+
:rtype: :class:`Page`
200+
:returns: The page of items that has been retrieved.
201+
"""
202+
return self._page
167203

168204
def __iter__(self):
169205
"""The :class:`Iterator` is an iterator."""
170206
return self
171207

172-
def _update_items(self):
173-
"""Replace the current items iterator.
174-
175-
Intended to be used when the current items iterator is exhausted.
208+
def _update_page(self):
209+
"""Replace the current page.
176210
177-
After replacing the iterator, consumes the first value to make sure
178-
it is valid.
211+
Does nothing if the current page is non-null and has items
212+
remaining.
179213
180-
:rtype: object
181-
:returns: The first item in the next iterator.
182214
:raises: :class:`~exceptions.StopIteration` if there is no next page.
183215
"""
216+
if self.page is not None and self.page.remaining > 0:
217+
return
184218
if self.has_next_page():
185219
response = self.get_next_page_response()
186-
self._curr_items = self.PAGE_CLASS(self, response)
187-
return six.next(self._curr_items)
220+
self._page = self.PAGE_CLASS(self, response)
188221
else:
189222
raise StopIteration
190223

191224
def next(self):
192225
"""Get the next value in the iterator."""
193-
try:
194-
item = six.next(self._curr_items)
195-
except StopIteration:
196-
item = self._update_items()
197-
226+
self._update_page()
227+
item = six.next(self.page)
198228
self.num_results += 1
199229
return item
200230

0 commit comments

Comments
 (0)