Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Side by Side Diff: appengine/chromium_build_logs/third_party/googleapiclient/model.py

Issue 1260293009: make version of ts_mon compatible with appengine (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: clean up code Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/python2.4 1 # Copyright 2014 Google Inc. All Rights Reserved.
2 # 2 #
3 # Copyright (C) 2010 Google Inc.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License. 4 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at 5 # You may obtain a copy of the License at
8 # 6 #
9 # http://www.apache.org/licenses/LICENSE-2.0 7 # http://www.apache.org/licenses/LICENSE-2.0
10 # 8 #
11 # Unless required by applicable law or agreed to in writing, software 9 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, 10 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and 12 # See the License for the specific language governing permissions and
15 # limitations under the License. 13 # limitations under the License.
16 14
17 """Model objects for requests and responses. 15 """Model objects for requests and responses.
18 16
19 Each API may support one or more serializations, such 17 Each API may support one or more serializations, such
20 as JSON, Atom, etc. The model classes are responsible 18 as JSON, Atom, etc. The model classes are responsible
21 for converting between the wire format and the Python 19 for converting between the wire format and the Python
22 object representation. 20 object representation.
23 """ 21 """
22 from __future__ import absolute_import
23 import six
24 24
25 __author__ = 'jcgregorio@google.com (Joe Gregorio)' 25 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
26 26
27 import gflags 27 import json
28 import logging 28 import logging
29 import urllib
30 29
31 from errors import HttpError 30 from six.moves.urllib.parse import urlencode
32 from oauth2client.anyjson import simplejson
33 31
34 FLAGS = gflags.FLAGS 32 from googleapiclient import __version__
33 from googleapiclient.errors import HttpError
35 34
36 gflags.DEFINE_boolean('dump_request_response', False, 35
37 'Dump all http server requests and responses. ' 36 dump_request_response = False
38 )
39 37
40 38
41 def _abstract(): 39 def _abstract():
42 raise NotImplementedError('You need to override this function') 40 raise NotImplementedError('You need to override this function')
43 41
44 42
45 class Model(object): 43 class Model(object):
46 """Model base class. 44 """Model base class.
47 45
48 All Model classes should implement this interface. 46 All Model classes should implement this interface.
(...skipping 24 matching lines...) Expand all
73 """Convert the response wire format into a Python object. 71 """Convert the response wire format into a Python object.
74 72
75 Args: 73 Args:
76 resp: httplib2.Response, the HTTP response headers and status 74 resp: httplib2.Response, the HTTP response headers and status
77 content: string, the body of the HTTP response 75 content: string, the body of the HTTP response
78 76
79 Returns: 77 Returns:
80 The body de-serialized as a Python object. 78 The body de-serialized as a Python object.
81 79
82 Raises: 80 Raises:
83 apiclient.errors.HttpError if a non 2xx response is received. 81 googleapiclient.errors.HttpError if a non 2xx response is received.
84 """ 82 """
85 _abstract() 83 _abstract()
86 84
87 85
88 class BaseModel(Model): 86 class BaseModel(Model):
89 """Base model class. 87 """Base model class.
90 88
91 Subclasses should provide implementations for the "serialize" and 89 Subclasses should provide implementations for the "serialize" and
92 "deserialize" methods, as well as values for the following class attributes. 90 "deserialize" methods, as well as values for the following class attributes.
93 91
94 Attributes: 92 Attributes:
95 accept: The value to use for the HTTP Accept header. 93 accept: The value to use for the HTTP Accept header.
96 content_type: The value to use for the HTTP Content-type header. 94 content_type: The value to use for the HTTP Content-type header.
97 no_content_response: The value to return when deserializing a 204 "No 95 no_content_response: The value to return when deserializing a 204 "No
98 Content" response. 96 Content" response.
99 alt_param: The value to supply as the "alt" query parameter for requests. 97 alt_param: The value to supply as the "alt" query parameter for requests.
100 """ 98 """
101 99
102 accept = None 100 accept = None
103 content_type = None 101 content_type = None
104 no_content_response = None 102 no_content_response = None
105 alt_param = None 103 alt_param = None
106 104
107 def _log_request(self, headers, path_params, query, body): 105 def _log_request(self, headers, path_params, query, body):
108 """Logs debugging information about the request if requested.""" 106 """Logs debugging information about the request if requested."""
109 if FLAGS.dump_request_response: 107 if dump_request_response:
110 logging.info('--request-start--') 108 logging.info('--request-start--')
111 logging.info('-headers-start-') 109 logging.info('-headers-start-')
112 for h, v in headers.iteritems(): 110 for h, v in six.iteritems(headers):
113 logging.info('%s: %s', h, v) 111 logging.info('%s: %s', h, v)
114 logging.info('-headers-end-') 112 logging.info('-headers-end-')
115 logging.info('-path-parameters-start-') 113 logging.info('-path-parameters-start-')
116 for h, v in path_params.iteritems(): 114 for h, v in six.iteritems(path_params):
117 logging.info('%s: %s', h, v) 115 logging.info('%s: %s', h, v)
118 logging.info('-path-parameters-end-') 116 logging.info('-path-parameters-end-')
119 logging.info('body: %s', body) 117 logging.info('body: %s', body)
120 logging.info('query: %s', query) 118 logging.info('query: %s', query)
121 logging.info('--request-end--') 119 logging.info('--request-end--')
122 120
123 def request(self, headers, path_params, query_params, body_value): 121 def request(self, headers, path_params, query_params, body_value):
124 """Updates outgoing requests with a serialized body. 122 """Updates outgoing requests with a serialized body.
125 123
126 Args: 124 Args:
127 headers: dict, request headers 125 headers: dict, request headers
128 path_params: dict, parameters that appear in the request path 126 path_params: dict, parameters that appear in the request path
129 query_params: dict, parameters that appear in the query 127 query_params: dict, parameters that appear in the query
130 body_value: object, the request body as a Python object, which must be 128 body_value: object, the request body as a Python object, which must be
131 serializable by simplejson. 129 serializable by json.
132 Returns: 130 Returns:
133 A tuple of (headers, path_params, query, body) 131 A tuple of (headers, path_params, query, body)
134 132
135 headers: dict, request headers 133 headers: dict, request headers
136 path_params: dict, parameters that appear in the request path 134 path_params: dict, parameters that appear in the request path
137 query: string, query part of the request URI 135 query: string, query part of the request URI
138 body: string, the body serialized as JSON 136 body: string, the body serialized as JSON
139 """ 137 """
140 query = self._build_query(query_params) 138 query = self._build_query(query_params)
141 headers['accept'] = self.accept 139 headers['accept'] = self.accept
142 headers['accept-encoding'] = 'gzip, deflate' 140 headers['accept-encoding'] = 'gzip, deflate'
143 if 'user-agent' in headers: 141 if 'user-agent' in headers:
144 headers['user-agent'] += ' ' 142 headers['user-agent'] += ' '
145 else: 143 else:
146 headers['user-agent'] = '' 144 headers['user-agent'] = ''
147 headers['user-agent'] += 'google-api-python-client/1.0' 145 headers['user-agent'] += 'google-api-python-client/%s (gzip)' % __version__
148 146
149 if body_value is not None: 147 if body_value is not None:
150 headers['content-type'] = self.content_type 148 headers['content-type'] = self.content_type
151 body_value = self.serialize(body_value) 149 body_value = self.serialize(body_value)
152 self._log_request(headers, path_params, query, body_value) 150 self._log_request(headers, path_params, query, body_value)
153 return (headers, path_params, query, body_value) 151 return (headers, path_params, query, body_value)
154 152
155 def _build_query(self, params): 153 def _build_query(self, params):
156 """Builds a query string. 154 """Builds a query string.
157 155
158 Args: 156 Args:
159 params: dict, the query parameters 157 params: dict, the query parameters
160 158
161 Returns: 159 Returns:
162 The query parameters properly encoded into an HTTP URI query string. 160 The query parameters properly encoded into an HTTP URI query string.
163 """ 161 """
164 if self.alt_param is not None: 162 if self.alt_param is not None:
165 params.update({'alt': self.alt_param}) 163 params.update({'alt': self.alt_param})
166 astuples = [] 164 astuples = []
167 for key, value in params.iteritems(): 165 for key, value in six.iteritems(params):
168 if type(value) == type([]): 166 if type(value) == type([]):
169 for x in value: 167 for x in value:
170 x = x.encode('utf-8') 168 x = x.encode('utf-8')
171 astuples.append((key, x)) 169 astuples.append((key, x))
172 else: 170 else:
173 if getattr(value, 'encode', False) and callable(value.encode): 171 if isinstance(value, six.text_type) and callable(value.encode):
174 value = value.encode('utf-8') 172 value = value.encode('utf-8')
175 astuples.append((key, value)) 173 astuples.append((key, value))
176 return '?' + urllib.urlencode(astuples) 174 return '?' + urlencode(astuples)
177 175
178 def _log_response(self, resp, content): 176 def _log_response(self, resp, content):
179 """Logs debugging information about the response if requested.""" 177 """Logs debugging information about the response if requested."""
180 if FLAGS.dump_request_response: 178 if dump_request_response:
181 logging.info('--response-start--') 179 logging.info('--response-start--')
182 for h, v in resp.iteritems(): 180 for h, v in six.iteritems(resp):
183 logging.info('%s: %s', h, v) 181 logging.info('%s: %s', h, v)
184 if content: 182 if content:
185 logging.info(content) 183 logging.info(content)
186 logging.info('--response-end--') 184 logging.info('--response-end--')
187 185
188 def response(self, resp, content): 186 def response(self, resp, content):
189 """Convert the response wire format into a Python object. 187 """Convert the response wire format into a Python object.
190 188
191 Args: 189 Args:
192 resp: httplib2.Response, the HTTP response headers and status 190 resp: httplib2.Response, the HTTP response headers and status
193 content: string, the body of the HTTP response 191 content: string, the body of the HTTP response
194 192
195 Returns: 193 Returns:
196 The body de-serialized as a Python object. 194 The body de-serialized as a Python object.
197 195
198 Raises: 196 Raises:
199 apiclient.errors.HttpError if a non 2xx response is received. 197 googleapiclient.errors.HttpError if a non 2xx response is received.
200 """ 198 """
201 self._log_response(resp, content) 199 self._log_response(resp, content)
202 # Error handling is TBD, for example, do we retry 200 # Error handling is TBD, for example, do we retry
203 # for some operation/error combinations? 201 # for some operation/error combinations?
204 if resp.status < 300: 202 if resp.status < 300:
205 if resp.status == 204: 203 if resp.status == 204:
206 # A 204: No Content response should be treated differently 204 # A 204: No Content response should be treated differently
207 # to all the other success states 205 # to all the other success states
208 return self.no_content_response 206 return self.no_content_response
209 return self.deserialize(content) 207 return self.deserialize(content)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 248
251 Args: 249 Args:
252 data_wrapper: boolean, wrap requests and responses in a data wrapper 250 data_wrapper: boolean, wrap requests and responses in a data wrapper
253 """ 251 """
254 self._data_wrapper = data_wrapper 252 self._data_wrapper = data_wrapper
255 253
256 def serialize(self, body_value): 254 def serialize(self, body_value):
257 if (isinstance(body_value, dict) and 'data' not in body_value and 255 if (isinstance(body_value, dict) and 'data' not in body_value and
258 self._data_wrapper): 256 self._data_wrapper):
259 body_value = {'data': body_value} 257 body_value = {'data': body_value}
260 return simplejson.dumps(body_value) 258 return json.dumps(body_value)
261 259
262 def deserialize(self, content): 260 def deserialize(self, content):
263 body = simplejson.loads(content) 261 try:
264 if isinstance(body, dict) and 'data' in body: 262 content = content.decode('utf-8')
263 except AttributeError:
264 pass
265 body = json.loads(content)
266 if self._data_wrapper and isinstance(body, dict) and 'data' in body:
265 body = body['data'] 267 body = body['data']
266 return body 268 return body
267 269
268 @property 270 @property
269 def no_content_response(self): 271 def no_content_response(self):
270 return {} 272 return {}
271 273
272 274
273 class RawModel(JsonModel): 275 class RawModel(JsonModel):
274 """Model class for requests that don't return JSON. 276 """Model class for requests that don't return JSON.
275 277
276 Serializes and de-serializes between JSON and the Python 278 Serializes and de-serializes between JSON and the Python
277 object representation of HTTP request, and returns the raw bytes 279 object representation of HTTP request, and returns the raw bytes
278 of the response body. 280 of the response body.
279 """ 281 """
280 accept = '*/*' 282 accept = '*/*'
281 content_type = 'application/json' 283 content_type = 'application/json'
282 alt_param = None 284 alt_param = None
283 285
284 def deserialize(self, content): 286 def deserialize(self, content):
285 return content 287 return content
286 288
287 @property 289 @property
288 def no_content_response(self): 290 def no_content_response(self):
289 return '' 291 return ''
290 292
291 293
294 class MediaModel(JsonModel):
295 """Model class for requests that return Media.
296
297 Serializes and de-serializes between JSON and the Python
298 object representation of HTTP request, and returns the raw bytes
299 of the response body.
300 """
301 accept = '*/*'
302 content_type = 'application/json'
303 alt_param = 'media'
304
305 def deserialize(self, content):
306 return content
307
308 @property
309 def no_content_response(self):
310 return ''
311
312
292 class ProtocolBufferModel(BaseModel): 313 class ProtocolBufferModel(BaseModel):
293 """Model class for protocol buffers. 314 """Model class for protocol buffers.
294 315
295 Serializes and de-serializes the binary protocol buffer sent in the HTTP 316 Serializes and de-serializes the binary protocol buffer sent in the HTTP
296 request and response bodies. 317 request and response bodies.
297 """ 318 """
298 accept = 'application/x-protobuf' 319 accept = 'application/x-protobuf'
299 content_type = 'application/x-protobuf' 320 content_type = 'application/x-protobuf'
300 alt_param = 'proto' 321 alt_param = 'proto'
301 322
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 form suitable to pass to a PATCH method. 358 form suitable to pass to a PATCH method.
338 359
339 Example usage: 360 Example usage:
340 item = service.activities().get(postid=postid, userid=userid).execute() 361 item = service.activities().get(postid=postid, userid=userid).execute()
341 original = copy.deepcopy(item) 362 original = copy.deepcopy(item)
342 item['object']['content'] = 'This is updated.' 363 item['object']['content'] = 'This is updated.'
343 service.activities.patch(postid=postid, userid=userid, 364 service.activities.patch(postid=postid, userid=userid,
344 body=makepatch(original, item)).execute() 365 body=makepatch(original, item)).execute()
345 """ 366 """
346 patch = {} 367 patch = {}
347 for key, original_value in original.iteritems(): 368 for key, original_value in six.iteritems(original):
348 modified_value = modified.get(key, None) 369 modified_value = modified.get(key, None)
349 if modified_value is None: 370 if modified_value is None:
350 # Use None to signal that the element is deleted 371 # Use None to signal that the element is deleted
351 patch[key] = None 372 patch[key] = None
352 elif original_value != modified_value: 373 elif original_value != modified_value:
353 if type(original_value) == type({}): 374 if type(original_value) == type({}):
354 # Recursively descend objects 375 # Recursively descend objects
355 patch[key] = makepatch(original_value, modified_value) 376 patch[key] = makepatch(original_value, modified_value)
356 else: 377 else:
357 # In the case of simple types or arrays we just replace 378 # In the case of simple types or arrays we just replace
358 patch[key] = modified_value 379 patch[key] = modified_value
359 else: 380 else:
360 # Don't add anything to patch if there's no change 381 # Don't add anything to patch if there's no change
361 pass 382 pass
362 for key in modified: 383 for key in modified:
363 if key not in original: 384 if key not in original:
364 patch[key] = modified[key] 385 patch[key] = modified[key]
365 386
366 return patch 387 return patch
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698