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 ] |