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 ]