Mercurial > repos > bcclaywell > argo_navis
comparison 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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:d67268158946 |
|---|---|
| 1 # -*- coding: utf-8 -*- | |
| 2 | |
| 3 # ########################## Copyrights and license ############################ | |
| 4 # # | |
| 5 # Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net> # | |
| 6 # Copyright 2012 Zearin <zearin@gonk.net> # | |
| 7 # Copyright 2013 AKFish <akfish@gmail.com> # | |
| 8 # Copyright 2013 Bill Mill <bill.mill@gmail.com> # | |
| 9 # Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> # | |
| 10 # Copyright 2013 davidbrai <davidbrai@gmail.com> # | |
| 11 # # | |
| 12 # This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ # | |
| 13 # # | |
| 14 # PyGithub is free software: you can redistribute it and/or modify it under # | |
| 15 # the terms of the GNU Lesser General Public License as published by the Free # | |
| 16 # Software Foundation, either version 3 of the License, or (at your option) # | |
| 17 # any later version. # | |
| 18 # # | |
| 19 # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # | |
| 20 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # | |
| 21 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # | |
| 22 # details. # | |
| 23 # # | |
| 24 # You should have received a copy of the GNU Lesser General Public License # | |
| 25 # along with PyGithub. If not, see <http://www.gnu.org/licenses/>. # | |
| 26 # # | |
| 27 # ############################################################################## | |
| 28 | |
| 29 import github.GithubObject | |
| 30 | |
| 31 | |
| 32 class PaginatedListBase: | |
| 33 def __init__(self): | |
| 34 self.__elements = list() | |
| 35 | |
| 36 def __getitem__(self, index): | |
| 37 assert isinstance(index, (int, slice)) | |
| 38 if isinstance(index, (int, long)): | |
| 39 self.__fetchToIndex(index) | |
| 40 return self.__elements[index] | |
| 41 else: | |
| 42 return self._Slice(self, index) | |
| 43 | |
| 44 def __iter__(self): | |
| 45 for element in self.__elements: | |
| 46 yield element | |
| 47 while self._couldGrow(): | |
| 48 newElements = self._grow() | |
| 49 for element in newElements: | |
| 50 yield element | |
| 51 | |
| 52 def _isBiggerThan(self, index): | |
| 53 return len(self.__elements) > index or self._couldGrow() | |
| 54 | |
| 55 def __fetchToIndex(self, index): | |
| 56 while len(self.__elements) <= index and self._couldGrow(): | |
| 57 self._grow() | |
| 58 | |
| 59 def _grow(self): | |
| 60 newElements = self._fetchNextPage() | |
| 61 self.__elements += newElements | |
| 62 return newElements | |
| 63 | |
| 64 class _Slice: | |
| 65 def __init__(self, theList, theSlice): | |
| 66 self.__list = theList | |
| 67 self.__start = theSlice.start or 0 | |
| 68 self.__stop = theSlice.stop | |
| 69 self.__step = theSlice.step or 1 | |
| 70 | |
| 71 def __iter__(self): | |
| 72 index = self.__start | |
| 73 while not self.__finished(index): | |
| 74 if self.__list._isBiggerThan(index): | |
| 75 yield self.__list[index] | |
| 76 index += self.__step | |
| 77 else: | |
| 78 return | |
| 79 | |
| 80 def __finished(self, index): | |
| 81 return self.__stop is not None and index >= self.__stop | |
| 82 | |
| 83 | |
| 84 class PaginatedList(PaginatedListBase): | |
| 85 """ | |
| 86 This class abstracts the `pagination of the API <http://developer.github.com/v3/#pagination>`_. | |
| 87 | |
| 88 You can simply enumerate through instances of this class:: | |
| 89 | |
| 90 for repo in user.get_repos(): | |
| 91 print repo.name | |
| 92 | |
| 93 You can also index them or take slices:: | |
| 94 | |
| 95 second_repo = user.get_repos()[1] | |
| 96 first_repos = user.get_repos()[:10] | |
| 97 | |
| 98 If you want to iterate in reversed order, just do:: | |
| 99 | |
| 100 for repo in user.get_repos().reversed: | |
| 101 print repo.name | |
| 102 | |
| 103 And if you really need it, you can explicitely access a specific page:: | |
| 104 | |
| 105 some_repos = user.get_repos().get_page(0) | |
| 106 some_other_repos = user.get_repos().get_page(3) | |
| 107 """ | |
| 108 | |
| 109 def __init__(self, contentClass, requester, firstUrl, firstParams): | |
| 110 PaginatedListBase.__init__(self) | |
| 111 self.__requester = requester | |
| 112 self.__contentClass = contentClass | |
| 113 self.__firstUrl = firstUrl | |
| 114 self.__firstParams = firstParams or () | |
| 115 self.__nextUrl = firstUrl | |
| 116 self.__nextParams = firstParams or {} | |
| 117 if self.__requester.per_page != 30: | |
| 118 self.__nextParams["per_page"] = self.__requester.per_page | |
| 119 self._reversed = False | |
| 120 self.__totalCount = None | |
| 121 | |
| 122 @property | |
| 123 def totalCount(self): | |
| 124 if not self.__totalCount: | |
| 125 self._grow() | |
| 126 | |
| 127 return self.__totalCount | |
| 128 | |
| 129 def _getLastPageUrl(self): | |
| 130 headers, data = self.__requester.requestJsonAndCheck( | |
| 131 "GET", | |
| 132 self.__firstUrl, | |
| 133 parameters=self.__nextParams | |
| 134 ) | |
| 135 links = self.__parseLinkHeader(headers) | |
| 136 lastUrl = links.get("last") | |
| 137 return lastUrl | |
| 138 | |
| 139 @property | |
| 140 def reversed(self): | |
| 141 r = PaginatedList(self.__contentClass, self.__requester, self.__firstUrl, self.__firstParams) | |
| 142 r.__reverse() | |
| 143 return r | |
| 144 | |
| 145 def __reverse(self): | |
| 146 self._reversed = True | |
| 147 lastUrl = self._getLastPageUrl() | |
| 148 if lastUrl: | |
| 149 self.__nextUrl = lastUrl | |
| 150 | |
| 151 def _couldGrow(self): | |
| 152 return self.__nextUrl is not None | |
| 153 | |
| 154 def _fetchNextPage(self): | |
| 155 headers, data = self.__requester.requestJsonAndCheck( | |
| 156 "GET", | |
| 157 self.__nextUrl, | |
| 158 parameters=self.__nextParams | |
| 159 ) | |
| 160 | |
| 161 self.__nextUrl = None | |
| 162 if len(data) > 0: | |
| 163 links = self.__parseLinkHeader(headers) | |
| 164 if self._reversed: | |
| 165 if "prev" in links: | |
| 166 self.__nextUrl = links["prev"] | |
| 167 elif "next" in links: | |
| 168 self.__nextUrl = links["next"] | |
| 169 self.__nextParams = None | |
| 170 | |
| 171 if 'items' in data: | |
| 172 self.__totalCount = data['total_count'] | |
| 173 data = data["items"] | |
| 174 | |
| 175 content = [ | |
| 176 self.__contentClass(self.__requester, headers, element, completed=False) | |
| 177 for element in data if element is not None | |
| 178 ] | |
| 179 if self._reversed: | |
| 180 return content[::-1] | |
| 181 return content | |
| 182 | |
| 183 def __parseLinkHeader(self, headers): | |
| 184 links = {} | |
| 185 if "link" in headers: | |
| 186 linkHeaders = headers["link"].split(", ") | |
| 187 for linkHeader in linkHeaders: | |
| 188 (url, rel) = linkHeader.split("; ") | |
| 189 url = url[1:-1] | |
| 190 rel = rel[5:-1] | |
| 191 links[rel] = url | |
| 192 return links | |
| 193 | |
| 194 def get_page(self, page): | |
| 195 params = dict(self.__firstParams) | |
| 196 if page != 0: | |
| 197 params["page"] = page + 1 | |
| 198 if self.__requester.per_page != 30: | |
| 199 params["per_page"] = self.__requester.per_page | |
| 200 headers, data = self.__requester.requestJsonAndCheck( | |
| 201 "GET", | |
| 202 self.__firstUrl, | |
| 203 parameters=params | |
| 204 ) | |
| 205 | |
| 206 if 'items' in data: | |
| 207 self.__totalCount = data['total_count'] | |
| 208 data = data["items"] | |
| 209 | |
| 210 return [ | |
| 211 self.__contentClass(self.__requester, headers, element, completed=False) | |
| 212 for element in data | |
| 213 ] |
