Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/api/v3/paginator.py b/api/v3/paginator.py
new file mode 100644
index 0000000..16e66fa
--- /dev/null
+++ b/api/v3/paginator.py
@@ -0,0 +1,91 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+from framework import exceptions
+from framework import paginate
+from proto import secrets_pb2
+
+
+def CoercePageSize(page_size, max_size, default_size=None):
+ # type: (int, int, Optional[int]) -> int
+ """Validates page_size and coerces it to max_size if needed.
+
+ Args:
+ page_size: The page_size requested by the user.
+ max_size: the maximum page size allowed. Must be > 0.
+ Also used as default if default_size not provided
+ default_size: default size to use if page_size not provided. Must be > 0.
+
+ Returns:
+ The appropriate page size to use for the request, based on the parameters.
+ Specifically this means
+ - page_size if not greater than max_size
+ - max_size if page_size > max_size
+ - max_size if page_size is not provided and default_size is not provided
+ - default_size if page_size is not provided
+
+ Raises:
+ InputException: if page_size is negative.
+ """
+ # These are programming errors. They are not user input.
+ assert max_size > 0
+ assert default_size is None or default_size > 0
+
+ # Check for invalid user provided page_size.
+ if page_size and page_size < 0:
+ raise exceptions.InputException('`page_size` cannot be negative.')
+
+ if not page_size:
+ return default_size or max_size
+ if page_size > max_size:
+ return max_size
+ return page_size
+
+
+class Paginator(object):
+ """Class to manage API pagination.
+
+ Paginator handles the pagination tasks and info of a single List or
+ Search API method implementation, given the contents of the request.
+ """
+
+ def __init__(self, parent=None, page_size=None, order_by=None,
+ filter_str=None, query=None, projects=None):
+ # type: (Optional[str], Optional[int], Optional[str], Optional[str],
+ # Optional[str], Optional[Collection[str]]]) -> None
+ self.request_contents = secrets_pb2.ListRequestContents(
+ parent=parent, page_size=page_size, order_by=order_by,
+ filter=filter_str, query=query, projects=projects)
+
+ def GetStart(self, page_token):
+ # type: (Optional[str]) -> int
+ """Validates a request.page_token and returns the start index for it."""
+ if page_token:
+ # TODO(crbug.com/monorail/6758): Proto string fields are unicode types in
+ # python 2. In python 3 these unicode strings will be represented with
+ # string types. paginate.ValidateAndParsePageToken requires a string token
+ # during validation (compare_digest()). Once we move to python 3, we can
+ # remove this string casting.
+ token = str(page_token)
+ return paginate.ValidateAndParsePageToken(token, self.request_contents)
+ return 0
+
+ def GenerateNextPageToken(self, next_start):
+ # type: (Optional[int]) -> str
+ """Generates the `next_page_token` for the API response.
+
+ Args:
+ next_start: The start index of the next page, or None if no more results.
+
+ Returns:
+ A string clients can use to request the next page. Returns None if
+ next_start was None
+ """
+ if next_start is None:
+ return None
+ return paginate.GeneratePageToken(self.request_contents, next_start)