feat(api_core): provide a 'raw_page' field for page_iterator.Page (#9486)
* Provide a 'raw_page' field for page_iterator.Page
Some paginated response messages include additional fields that users
may wish to inspect.
diff --git a/google/api_core/page_iterator.py b/google/api_core/page_iterator.py
index 3ac5904..11a92d3 100644
--- a/google/api_core/page_iterator.py
+++ b/google/api_core/page_iterator.py
@@ -96,14 +96,22 @@
Callable to convert an item from the type in the raw API response
into the native object. Will be called with the iterator and a
single item.
+ raw_page Optional[google.protobuf.message.Message]:
+ The raw page response.
"""
- def __init__(self, parent, items, item_to_value):
+ def __init__(self, parent, items, item_to_value, raw_page=None):
self._parent = parent
self._num_items = len(items)
self._remaining = self._num_items
self._item_iter = iter(items)
self._item_to_value = item_to_value
+ self._raw_page = raw_page
+
+ @property
+ def raw_page(self):
+ """google.protobuf.message.Message"""
+ return self._raw_page
@property
def num_items(self):
@@ -360,7 +368,7 @@
if self._has_next_page():
response = self._get_next_page_response()
items = response.get(self._items_key, ())
- page = Page(self, items, self.item_to_value)
+ page = Page(self, items, self.item_to_value, raw_page=response)
self._page_start(self, page, response)
self.next_page_token = response.get(self._next_token)
return page
@@ -527,7 +535,7 @@
self.next_page_token = getattr(response, self._response_token_field)
items = getattr(response, self._items_field)
- page = Page(self, items, self.item_to_value)
+ page = Page(self, items, self.item_to_value, raw_page=response)
return page
diff --git a/tests/unit/test_page_iterator.py b/tests/unit/test_page_iterator.py
index 6335001..2bf7424 100644
--- a/tests/unit/test_page_iterator.py
+++ b/tests/unit/test_page_iterator.py
@@ -36,9 +36,10 @@
assert page.remaining == 3
assert page._parent is parent
assert page._item_to_value is item_to_value
+ assert page.raw_page is None
def test___iter__(self):
- page = page_iterator.Page(None, (), None)
+ page = page_iterator.Page(None, (), None, None)
assert iter(page) is page
def test_iterator_calls_parent_item_to_value(self):
@@ -69,6 +70,18 @@
item_to_value.assert_called_with(parent, 12)
assert page.remaining == 97
+ def test_raw_page(self):
+ parent = mock.sentinel.parent
+ item_to_value = mock.sentinel.item_to_value
+
+ raw_page = mock.sentinel.raw_page
+
+ page = page_iterator.Page(parent, (1, 2, 3), item_to_value, raw_page=raw_page)
+ assert page.raw_page is raw_page
+
+ with pytest.raises(AttributeError):
+ page.raw_page = None
+
class PageIteratorImpl(page_iterator.Iterator):
def _next_page(self):
@@ -116,8 +129,7 @@
def test__page_iter_increment(self):
iterator = PageIteratorImpl(None, None)
page = page_iterator.Page(
- iterator, ("item",), page_iterator._item_to_value_identity
- )
+ iterator, ("item",), page_iterator._item_to_value_identity)
iterator._next_page = mock.Mock(side_effect=[page, None])
assert iterator.num_results == 0
@@ -147,11 +159,9 @@
# Make pages from mock responses
parent = mock.sentinel.parent
page1 = page_iterator.Page(
- parent, (item1, item2), page_iterator._item_to_value_identity
- )
+ parent, (item1, item2), page_iterator._item_to_value_identity)
page2 = page_iterator.Page(
- parent, (item3,), page_iterator._item_to_value_identity
- )
+ parent, (item3,), page_iterator._item_to_value_identity)
iterator = PageIteratorImpl(None, None)
iterator._next_page = mock.Mock(side_effect=[page1, page2, None])