Mercurial > repos > bcclaywell > argo_navis
diff venv/lib/python2.7/site-packages/github/PaginatedList.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/venv/lib/python2.7/site-packages/github/PaginatedList.py Mon Oct 12 17:43:33 2015 -0400 @@ -0,0 +1,213 @@ +# -*- coding: utf-8 -*- + +# ########################## Copyrights and license ############################ +# # +# Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net> # +# Copyright 2012 Zearin <zearin@gonk.net> # +# Copyright 2013 AKFish <akfish@gmail.com> # +# Copyright 2013 Bill Mill <bill.mill@gmail.com> # +# Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> # +# Copyright 2013 davidbrai <davidbrai@gmail.com> # +# # +# This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ # +# # +# PyGithub is free software: you can redistribute it and/or modify it under # +# the terms of the GNU Lesser General Public License as published by the Free # +# Software Foundation, either version 3 of the License, or (at your option) # +# any later version. # +# # +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # +# details. # +# # +# You should have received a copy of the GNU Lesser General Public License # +# along with PyGithub. If not, see <http://www.gnu.org/licenses/>. # +# # +# ############################################################################## + +import github.GithubObject + + +class PaginatedListBase: + def __init__(self): + self.__elements = list() + + def __getitem__(self, index): + assert isinstance(index, (int, slice)) + if isinstance(index, (int, long)): + self.__fetchToIndex(index) + return self.__elements[index] + else: + return self._Slice(self, index) + + def __iter__(self): + for element in self.__elements: + yield element + while self._couldGrow(): + newElements = self._grow() + for element in newElements: + yield element + + def _isBiggerThan(self, index): + return len(self.__elements) > index or self._couldGrow() + + def __fetchToIndex(self, index): + while len(self.__elements) <= index and self._couldGrow(): + self._grow() + + def _grow(self): + newElements = self._fetchNextPage() + self.__elements += newElements + return newElements + + class _Slice: + def __init__(self, theList, theSlice): + self.__list = theList + self.__start = theSlice.start or 0 + self.__stop = theSlice.stop + self.__step = theSlice.step or 1 + + def __iter__(self): + index = self.__start + while not self.__finished(index): + if self.__list._isBiggerThan(index): + yield self.__list[index] + index += self.__step + else: + return + + def __finished(self, index): + return self.__stop is not None and index >= self.__stop + + +class PaginatedList(PaginatedListBase): + """ + This class abstracts the `pagination of the API <http://developer.github.com/v3/#pagination>`_. + + You can simply enumerate through instances of this class:: + + for repo in user.get_repos(): + print repo.name + + You can also index them or take slices:: + + second_repo = user.get_repos()[1] + first_repos = user.get_repos()[:10] + + If you want to iterate in reversed order, just do:: + + for repo in user.get_repos().reversed: + print repo.name + + And if you really need it, you can explicitely access a specific page:: + + some_repos = user.get_repos().get_page(0) + some_other_repos = user.get_repos().get_page(3) + """ + + def __init__(self, contentClass, requester, firstUrl, firstParams): + PaginatedListBase.__init__(self) + self.__requester = requester + self.__contentClass = contentClass + self.__firstUrl = firstUrl + self.__firstParams = firstParams or () + self.__nextUrl = firstUrl + self.__nextParams = firstParams or {} + if self.__requester.per_page != 30: + self.__nextParams["per_page"] = self.__requester.per_page + self._reversed = False + self.__totalCount = None + + @property + def totalCount(self): + if not self.__totalCount: + self._grow() + + return self.__totalCount + + def _getLastPageUrl(self): + headers, data = self.__requester.requestJsonAndCheck( + "GET", + self.__firstUrl, + parameters=self.__nextParams + ) + links = self.__parseLinkHeader(headers) + lastUrl = links.get("last") + return lastUrl + + @property + def reversed(self): + r = PaginatedList(self.__contentClass, self.__requester, self.__firstUrl, self.__firstParams) + r.__reverse() + return r + + def __reverse(self): + self._reversed = True + lastUrl = self._getLastPageUrl() + if lastUrl: + self.__nextUrl = lastUrl + + def _couldGrow(self): + return self.__nextUrl is not None + + def _fetchNextPage(self): + headers, data = self.__requester.requestJsonAndCheck( + "GET", + self.__nextUrl, + parameters=self.__nextParams + ) + + self.__nextUrl = None + if len(data) > 0: + links = self.__parseLinkHeader(headers) + if self._reversed: + if "prev" in links: + self.__nextUrl = links["prev"] + elif "next" in links: + self.__nextUrl = links["next"] + self.__nextParams = None + + if 'items' in data: + self.__totalCount = data['total_count'] + data = data["items"] + + content = [ + self.__contentClass(self.__requester, headers, element, completed=False) + for element in data if element is not None + ] + if self._reversed: + return content[::-1] + return content + + def __parseLinkHeader(self, headers): + links = {} + if "link" in headers: + linkHeaders = headers["link"].split(", ") + for linkHeader in linkHeaders: + (url, rel) = linkHeader.split("; ") + url = url[1:-1] + rel = rel[5:-1] + links[rel] = url + return links + + def get_page(self, page): + params = dict(self.__firstParams) + if page != 0: + params["page"] = page + 1 + if self.__requester.per_page != 30: + params["per_page"] = self.__requester.per_page + headers, data = self.__requester.requestJsonAndCheck( + "GET", + self.__firstUrl, + parameters=params + ) + + if 'items' in data: + self.__totalCount = data['total_count'] + data = data["items"] + + return [ + self.__contentClass(self.__requester, headers, element, completed=False) + for element in data + ]