comparison venv/lib/python2.7/site-packages/github/GithubObject.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 Vincent Jacques <vincent@vincent-jacques.net> #
9 # #
10 # This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ #
11 # #
12 # PyGithub is free software: you can redistribute it and/or modify it under #
13 # the terms of the GNU Lesser General Public License as published by the Free #
14 # Software Foundation, either version 3 of the License, or (at your option) #
15 # any later version. #
16 # #
17 # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY #
18 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
19 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
20 # details. #
21 # #
22 # You should have received a copy of the GNU Lesser General Public License #
23 # along with PyGithub. If not, see <http://www.gnu.org/licenses/>. #
24 # #
25 # ##############################################################################
26
27 import datetime
28
29 import GithubException
30 import Consts
31
32
33 class _NotSetType:
34 def __repr__(self):
35 return "NotSet"
36
37 value = None
38 NotSet = _NotSetType()
39
40
41 class _ValuedAttribute:
42 def __init__(self, value):
43 self.value = value
44
45
46 class _BadAttribute:
47 def __init__(self, value, expectedType, exception=None):
48 self.__value = value
49 self.__expectedType = expectedType
50 self.__exception = exception
51
52 @property
53 def value(self):
54 raise GithubException.BadAttributeException(self.__value, self.__expectedType, self.__exception)
55
56
57 class GithubObject(object):
58 """
59 Base class for all classes representing objects returned by the API.
60 """
61
62 '''
63 A global debug flag to enable header validation by requester for all objects
64 '''
65 CHECK_AFTER_INIT_FLAG = False
66
67 @classmethod
68 def setCheckAfterInitFlag(cls, flag):
69 cls.CHECK_AFTER_INIT_FLAG = flag
70
71 def __init__(self, requester, headers, attributes, completed):
72 self._requester = requester
73 self._initAttributes()
74 self._storeAndUseAttributes(headers, attributes)
75
76 # Ask requester to do some checking, for debug and test purpose
77 # Since it's most handy to access and kinda all-knowing
78 if self.CHECK_AFTER_INIT_FLAG: # pragma no branch (Flag always set in tests)
79 requester.check_me(self)
80
81 def _storeAndUseAttributes(self, headers, attributes):
82 # Make sure headers are assigned before calling _useAttributes
83 # (Some derived classes will use headers in _useAttributes)
84 self._headers = headers
85 self._rawData = attributes
86 self._useAttributes(attributes)
87
88 @property
89 def raw_data(self):
90 """
91 :type: dict
92 """
93 self._completeIfNeeded()
94 return self._rawData
95
96 @property
97 def raw_headers(self):
98 """
99 :type: dict
100 """
101 self._completeIfNeeded()
102 return self._headers
103
104 @staticmethod
105 def _parentUrl(url):
106 return "/".join(url.split("/")[: -1])
107
108 @staticmethod
109 def __makeSimpleAttribute(value, type):
110 if value is None or isinstance(value, type):
111 return _ValuedAttribute(value)
112 else:
113 return _BadAttribute(value, type)
114
115 @staticmethod
116 def __makeSimpleListAttribute(value, type):
117 if isinstance(value, list) and all(isinstance(element, type) for element in value):
118 return _ValuedAttribute(value)
119 else:
120 return _BadAttribute(value, [type])
121
122 @staticmethod
123 def __makeTransformedAttribute(value, type, transform):
124 if value is None:
125 return _ValuedAttribute(None)
126 elif isinstance(value, type):
127 try:
128 return _ValuedAttribute(transform(value))
129 except Exception, e:
130 return _BadAttribute(value, type, e)
131 else:
132 return _BadAttribute(value, type)
133
134 @staticmethod
135 def _makeStringAttribute(value):
136 return GithubObject.__makeSimpleAttribute(value, (str, unicode))
137
138 @staticmethod
139 def _makeIntAttribute(value):
140 return GithubObject.__makeSimpleAttribute(value, (int, long))
141
142 @staticmethod
143 def _makeBoolAttribute(value):
144 return GithubObject.__makeSimpleAttribute(value, bool)
145
146 @staticmethod
147 def _makeDictAttribute(value):
148 return GithubObject.__makeSimpleAttribute(value, dict)
149
150 @staticmethod
151 def _makeTimestampAttribute(value):
152 return GithubObject.__makeTransformedAttribute(value, (int, long), datetime.datetime.utcfromtimestamp)
153
154 @staticmethod
155 def _makeDatetimeAttribute(value):
156 def parseDatetime(s):
157 if len(s) == 24: # pragma no branch (This branch was used only when creating a download)
158 # The Downloads API has been removed. I'm keeping this branch because I have no mean
159 # to check if it's really useless now.
160 return datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%S.000Z") # pragma no cover (This branch was used only when creating a download)
161 elif len(s) == 25:
162 return datetime.datetime.strptime(s[:19], "%Y-%m-%dT%H:%M:%S") + (1 if s[19] == '-' else -1) * datetime.timedelta(hours=int(s[20:22]), minutes=int(s[23:25]))
163 else:
164 return datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ")
165
166 return GithubObject.__makeTransformedAttribute(value, (str, unicode), parseDatetime)
167
168 def _makeClassAttribute(self, klass, value):
169 return GithubObject.__makeTransformedAttribute(value, dict, lambda value: klass(self._requester, self._headers, value, completed=False))
170
171 @staticmethod
172 def _makeListOfStringsAttribute(value):
173 return GithubObject.__makeSimpleListAttribute(value, (str, unicode))
174
175 @staticmethod
176 def _makeListOfIntsAttribute(value):
177 return GithubObject.__makeSimpleListAttribute(value, int)
178
179 @staticmethod
180 def _makeListOfListOfStringsAttribute(value):
181 return GithubObject.__makeSimpleListAttribute(value, list)
182
183 def _makeListOfClassesAttribute(self, klass, value):
184 if isinstance(value, list) and all(isinstance(element, dict) for element in value):
185 return _ValuedAttribute([klass(self._requester, self._headers, element, completed=False) for element in value])
186 else:
187 return _BadAttribute(value, [dict])
188
189 def _makeDictOfStringsToClassesAttribute(self, klass, value):
190 if isinstance(value, dict) and all(isinstance(key, (str, unicode)) and isinstance(element, dict) for key, element in value.iteritems()):
191 return _ValuedAttribute(dict((key, klass(self._requester, self._headers, element, completed=False)) for key, element in value.iteritems()))
192 else:
193 return _BadAttribute(value, {(str, unicode): dict})
194
195 @property
196 def etag(self):
197 '''
198 :type: str
199 '''
200 return self._headers.get(Consts.RES_ETAG)
201
202 @property
203 def last_modified(self):
204 '''
205 :type: str
206 '''
207 return self._headers.get(Consts.RES_LAST_MODIFED)
208
209
210 class NonCompletableGithubObject(GithubObject):
211 def _completeIfNeeded(self):
212 pass
213
214
215 class CompletableGithubObject(GithubObject):
216 def __init__(self, requester, headers, attributes, completed):
217 GithubObject.__init__(self, requester, headers, attributes, completed)
218 self.__completed = completed
219
220 def __eq__(self, other):
221 return other.__class__ is self.__class__ and other._url.value == self._url.value
222
223 def __ne__(self, other):
224 return not self == other
225
226 def _completeIfNotSet(self, value):
227 if value is NotSet:
228 self._completeIfNeeded()
229
230 def _completeIfNeeded(self):
231 if not self.__completed:
232 self.__complete()
233
234 def __complete(self):
235 headers, data = self._requester.requestJsonAndCheck(
236 "GET",
237 self._url.value
238 )
239 self._storeAndUseAttributes(headers, data)
240 self.__completed = True
241
242 def update(self):
243 '''
244 Check and update the object with conditional request
245 :rtype: Boolean value indicating whether the object is changed
246 '''
247 conditionalRequestHeader = dict()
248 if self.etag is not None:
249 conditionalRequestHeader[Consts.REQ_IF_NONE_MATCH] = self.etag
250 if self.last_modified is not None:
251 conditionalRequestHeader[Consts.REQ_IF_MODIFIED_SINCE] = self.last_modified
252
253 status, responseHeaders, output = self._requester.requestJson(
254 "GET",
255 self._url.value,
256 headers=conditionalRequestHeader
257 )
258 if status == 304:
259 return False
260 else:
261 headers, data = self._requester._Requester__check(status, responseHeaders, output)
262 self._storeAndUseAttributes(headers, data)
263 self.__completed = True
264 return True