Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pager helper to work with nested fields for limit or continuation token #281

Merged
merged 5 commits into from
Sep 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Allow pager helper to work with nested fields for limit and/or contin…
…uation token
  • Loading branch information
sixolet committed Sep 19, 2019
commit a3fc983cfc76222b6184bc1a5975e5d575957b4d
34 changes: 26 additions & 8 deletions apitools/base/py/list_pager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@
'YieldFromList',
]

def _GetattrNested(message, attribute):
if isinstance(attribute, str):
return getattr(message, attribute)
elif len(attribute) == 0:
return message
else:
return _GetattrNested(getattr(message, attribute[0]), attribute[1:])

def _SetattrNested(message, attribute, value):
if isinstance(attribute, str):
return setattr(message, attribute, value)
elif len(attribute) < 1:
raise ValueError("Need an attribute to set")
elif len(attribute) == 1:
return setattr(message, attribute[0], value)
else:
return setattr(_GetattrNested(message, attribute[:-1]), attribute[-1], value)


def YieldFromList(
service, request, global_params=None, limit=None, batch_size=100,
Expand All @@ -45,12 +63,12 @@ def YieldFromList(
method: str, The name of the method used to fetch resources.
field: str, The field in the response that will be a list of items.
predicate: lambda, A function that returns true for items to be yielded.
current_token_attribute: str, The name of the attribute in a
current_token_attribute: str or tuple, The name of the attribute in a
request message holding the page token for the page being
requested.
next_token_attribute: str, The name of the attribute in a
next_token_attribute: str or tuple, The name of the attribute in a
response message holding the page token for the next page.
batch_size_attribute: str, The name of the attribute in a
batch_size_attribute: str or tuple, The name of the attribute in a
response message holding the maximum number of results to be
returned. None if caller-specified batch size is unsupported.

Expand All @@ -59,7 +77,7 @@ def YieldFromList(

"""
request = encoding.CopyProtoMessage(request)
setattr(request, current_token_attribute, None)
_SetattrNested(request, current_token_attribute, None)
while limit is None or limit:
if batch_size_attribute:
# On Py3, None is not comparable so min() below will fail.
Expand All @@ -72,10 +90,10 @@ def YieldFromList(
request_batch_size = None
else:
request_batch_size = min(batch_size, limit or batch_size)
setattr(request, batch_size_attribute, request_batch_size)
_SetattrNested(request, batch_size_attribute, request_batch_size)
response = getattr(service, method)(request,
global_params=global_params)
items = getattr(response, field)
items = _GetattrNested(response, field)
if predicate:
items = list(filter(predicate, items))
for item in items:
Expand All @@ -85,7 +103,7 @@ def YieldFromList(
limit -= 1
if not limit:
return
token = getattr(response, next_token_attribute)
token = _GetattrNested(response, next_token_attribute)
if not token:
return
setattr(request, current_token_attribute, token)
_SetattrNested(request, current_token_attribute, token)
24 changes: 24 additions & 0 deletions apitools/base/py/list_pager_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@
from samples.iam_sample.iam_v1 import iam_v1_client as iam_client
from samples.iam_sample.iam_v1 import iam_v1_messages as iam_messages

class Example(object):
def __init__(self):
self.a = 'aaa'
self.b = 'bbb'
self.c = 'ccc'

class GetterSetterTest(unittest2.TestCase):

def testGetattrNested(self):
o = Example()
self.assertEqual(list_pager._GetattrNested(o, 'a'), 'aaa')
self.assertEqual(list_pager._GetattrNested(o, ('a',)), 'aaa')
o.b = Example()
self.assertEqual(list_pager._GetattrNested(o, ('b', 'c')), 'ccc')

def testSetattrNested(self):
o = Example()
list_pager._SetattrNested(o, 'b', Example())
self.assertEqual(o.b.a, 'aaa')
list_pager._SetattrNested(o, ('b', 'a'), 'AAA')
self.assertEqual(o.b.a, 'AAA')
list_pager._SetattrNested(o, ('c',), 'CCC')
self.assertEqual(o.c, 'CCC')


class ListPagerTest(unittest2.TestCase):

Expand Down