2020To make an iterator work, just override the ``PAGE_CLASS`` class
2121attribute so that given a response (containing a page of results) can
2222be 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