googlecloud 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +4 -0
  3. data/LICENSE +674 -0
  4. data/Manifest +111 -0
  5. data/README.md +4 -3
  6. data/bin/gcutil +53 -0
  7. data/googlecloud.gemspec +4 -3
  8. data/packages/gcutil-1.7.1/CHANGELOG +197 -0
  9. data/packages/gcutil-1.7.1/LICENSE +202 -0
  10. data/packages/gcutil-1.7.1/VERSION +1 -0
  11. data/packages/gcutil-1.7.1/gcutil +53 -0
  12. data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
  13. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
  14. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
  15. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
  16. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
  17. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
  18. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
  19. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
  20. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
  21. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
  22. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
  23. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
  24. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
  25. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
  26. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
  27. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
  28. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
  29. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
  30. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
  31. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
  32. data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
  33. data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
  34. data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
  35. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
  36. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
  37. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
  38. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
  39. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
  40. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
  41. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
  42. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
  43. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
  44. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
  45. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
  46. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
  47. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
  48. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
  49. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
  50. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
  51. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
  52. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
  53. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
  54. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
  55. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
  56. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
  57. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
  58. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
  59. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
  60. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
  61. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
  62. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
  63. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
  64. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
  65. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
  66. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
  67. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
  68. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
  69. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
  70. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
  71. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
  72. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
  73. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
  74. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
  75. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
  76. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
  77. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
  78. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
  79. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
  80. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
  81. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
  82. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
  83. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
  84. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
  85. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
  86. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
  87. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
  88. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
  89. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
  90. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
  91. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
  92. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
  93. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
  94. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
  95. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
  96. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
  97. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
  98. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
  99. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
  100. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
  101. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
  102. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
  103. data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
  104. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
  105. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
  106. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
  107. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
  108. data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
  109. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
  110. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
  111. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
  112. data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
  113. data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
  114. data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
  115. data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
  116. data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
  117. metadata +118 -5
  118. metadata.gz.sig +0 -0
@@ -0,0 +1,172 @@
1
+ # Copyright (C) 2007 Joe Gregorio
2
+ #
3
+ # Licensed under the MIT License
4
+
5
+ """MIME-Type Parser
6
+
7
+ This module provides basic functions for handling mime-types. It can handle
8
+ matching mime-types against a list of media-ranges. See section 14.1 of the
9
+ HTTP specification [RFC 2616] for a complete explanation.
10
+
11
+ http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
12
+
13
+ Contents:
14
+ - parse_mime_type(): Parses a mime-type into its component parts.
15
+ - parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q'
16
+ quality parameter.
17
+ - quality(): Determines the quality ('q') of a mime-type when
18
+ compared against a list of media-ranges.
19
+ - quality_parsed(): Just like quality() except the second parameter must be
20
+ pre-parsed.
21
+ - best_match(): Choose the mime-type with the highest quality ('q')
22
+ from a list of candidates.
23
+ """
24
+
25
+ __version__ = '0.1.3'
26
+
27
+ __email__ = 'joe@bitworking.org'
28
+ __license__ = 'MIT License'
29
+ __credits__ = ''
30
+
31
+
32
+ def parse_mime_type(mime_type):
33
+ """Parses a mime-type into its component parts.
34
+
35
+ Carves up a mime-type and returns a tuple of the (type, subtype, params)
36
+ where 'params' is a dictionary of all the parameters for the media range.
37
+ For example, the media range 'application/xhtml;q=0.5' would get parsed
38
+ into:
39
+
40
+ ('application', 'xhtml', {'q', '0.5'})
41
+ """
42
+ parts = mime_type.split(';')
43
+ params = dict([tuple([s.strip() for s in param.split('=', 1)])\
44
+ for param in parts[1:]
45
+ ])
46
+ full_type = parts[0].strip()
47
+ # Java URLConnection class sends an Accept header that includes a
48
+ # single '*'. Turn it into a legal wildcard.
49
+ if full_type == '*':
50
+ full_type = '*/*'
51
+ (type, subtype) = full_type.split('/')
52
+
53
+ return (type.strip(), subtype.strip(), params)
54
+
55
+
56
+ def parse_media_range(range):
57
+ """Parse a media-range into its component parts.
58
+
59
+ Carves up a media range and returns a tuple of the (type, subtype,
60
+ params) where 'params' is a dictionary of all the parameters for the media
61
+ range. For example, the media range 'application/*;q=0.5' would get parsed
62
+ into:
63
+
64
+ ('application', '*', {'q', '0.5'})
65
+
66
+ In addition this function also guarantees that there is a value for 'q'
67
+ in the params dictionary, filling it in with a proper default if
68
+ necessary.
69
+ """
70
+ (type, subtype, params) = parse_mime_type(range)
71
+ if not params.has_key('q') or not params['q'] or \
72
+ not float(params['q']) or float(params['q']) > 1\
73
+ or float(params['q']) < 0:
74
+ params['q'] = '1'
75
+
76
+ return (type, subtype, params)
77
+
78
+
79
+ def fitness_and_quality_parsed(mime_type, parsed_ranges):
80
+ """Find the best match for a mime-type amongst parsed media-ranges.
81
+
82
+ Find the best match for a given mime-type against a list of media_ranges
83
+ that have already been parsed by parse_media_range(). Returns a tuple of
84
+ the fitness value and the value of the 'q' quality parameter of the best
85
+ match, or (-1, 0) if no match was found. Just as for quality_parsed(),
86
+ 'parsed_ranges' must be a list of parsed media ranges.
87
+ """
88
+ best_fitness = -1
89
+ best_fit_q = 0
90
+ (target_type, target_subtype, target_params) =\
91
+ parse_media_range(mime_type)
92
+ for (type, subtype, params) in parsed_ranges:
93
+ type_match = (type == target_type or\
94
+ type == '*' or\
95
+ target_type == '*')
96
+ subtype_match = (subtype == target_subtype or\
97
+ subtype == '*' or\
98
+ target_subtype == '*')
99
+ if type_match and subtype_match:
100
+ param_matches = reduce(lambda x, y: x + y, [1 for (key, value) in \
101
+ target_params.iteritems() if key != 'q' and \
102
+ params.has_key(key) and value == params[key]], 0)
103
+ fitness = (type == target_type) and 100 or 0
104
+ fitness += (subtype == target_subtype) and 10 or 0
105
+ fitness += param_matches
106
+ if fitness > best_fitness:
107
+ best_fitness = fitness
108
+ best_fit_q = params['q']
109
+
110
+ return best_fitness, float(best_fit_q)
111
+
112
+
113
+ def quality_parsed(mime_type, parsed_ranges):
114
+ """Find the best match for a mime-type amongst parsed media-ranges.
115
+
116
+ Find the best match for a given mime-type against a list of media_ranges
117
+ that have already been parsed by parse_media_range(). Returns the 'q'
118
+ quality parameter of the best match, 0 if no match was found. This function
119
+ bahaves the same as quality() except that 'parsed_ranges' must be a list of
120
+ parsed media ranges.
121
+ """
122
+
123
+ return fitness_and_quality_parsed(mime_type, parsed_ranges)[1]
124
+
125
+
126
+ def quality(mime_type, ranges):
127
+ """Return the quality ('q') of a mime-type against a list of media-ranges.
128
+
129
+ Returns the quality 'q' of a mime-type when compared against the
130
+ media-ranges in ranges. For example:
131
+
132
+ >>> quality('text/html','text/*;q=0.3, text/html;q=0.7,
133
+ text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
134
+ 0.7
135
+
136
+ """
137
+ parsed_ranges = [parse_media_range(r) for r in ranges.split(',')]
138
+
139
+ return quality_parsed(mime_type, parsed_ranges)
140
+
141
+
142
+ def best_match(supported, header):
143
+ """Return mime-type with the highest quality ('q') from list of candidates.
144
+
145
+ Takes a list of supported mime-types and finds the best match for all the
146
+ media-ranges listed in header. The value of header must be a string that
147
+ conforms to the format of the HTTP Accept: header. The value of 'supported'
148
+ is a list of mime-types. The list of supported mime-types should be sorted
149
+ in order of increasing desirability, in case of a situation where there is
150
+ a tie.
151
+
152
+ >>> best_match(['application/xbel+xml', 'text/xml'],
153
+ 'text/*;q=0.5,*/*; q=0.1')
154
+ 'text/xml'
155
+ """
156
+ split_header = _filter_blank(header.split(','))
157
+ parsed_header = [parse_media_range(r) for r in split_header]
158
+ weighted_matches = []
159
+ pos = 0
160
+ for mime_type in supported:
161
+ weighted_matches.append((fitness_and_quality_parsed(mime_type,
162
+ parsed_header), pos, mime_type))
163
+ pos += 1
164
+ weighted_matches.sort()
165
+
166
+ return weighted_matches[-1][0][1] and weighted_matches[-1][2] or ''
167
+
168
+
169
+ def _filter_blank(i):
170
+ for s in i:
171
+ if s.strip():
172
+ yield s
@@ -0,0 +1,385 @@
1
+ #!/usr/bin/python2.4
2
+ #
3
+ # Copyright (C) 2010 Google Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """Model objects for requests and responses.
18
+
19
+ Each API may support one or more serializations, such
20
+ as JSON, Atom, etc. The model classes are responsible
21
+ for converting between the wire format and the Python
22
+ object representation.
23
+ """
24
+
25
+
26
+
27
+ import gflags
28
+ import logging
29
+ import urllib
30
+
31
+ from errors import HttpError
32
+ from oauth2client.anyjson import simplejson
33
+
34
+ FLAGS = gflags.FLAGS
35
+
36
+ gflags.DEFINE_boolean('dump_request_response', False,
37
+ 'Dump all http server requests and responses. '
38
+ )
39
+
40
+
41
+ def _abstract():
42
+ raise NotImplementedError('You need to override this function')
43
+
44
+
45
+ class Model(object):
46
+ """Model base class.
47
+
48
+ All Model classes should implement this interface.
49
+ The Model serializes and de-serializes between a wire
50
+ format such as JSON and a Python object representation.
51
+ """
52
+
53
+ def request(self, headers, path_params, query_params, body_value):
54
+ """Updates outgoing requests with a serialized body.
55
+
56
+ Args:
57
+ headers: dict, request headers
58
+ path_params: dict, parameters that appear in the request path
59
+ query_params: dict, parameters that appear in the query
60
+ body_value: object, the request body as a Python object, which must be
61
+ serializable.
62
+ Returns:
63
+ A tuple of (headers, path_params, query, body)
64
+
65
+ headers: dict, request headers
66
+ path_params: dict, parameters that appear in the request path
67
+ query: string, query part of the request URI
68
+ body: string, the body serialized in the desired wire format.
69
+ """
70
+ _abstract()
71
+
72
+ def response(self, resp, content):
73
+ """Convert the response wire format into a Python object.
74
+
75
+ Args:
76
+ resp: httplib2.Response, the HTTP response headers and status
77
+ content: string, the body of the HTTP response
78
+
79
+ Returns:
80
+ The body de-serialized as a Python object.
81
+
82
+ Raises:
83
+ apiclient.errors.HttpError if a non 2xx response is received.
84
+ """
85
+ _abstract()
86
+
87
+
88
+ class BaseModel(Model):
89
+ """Base model class.
90
+
91
+ Subclasses should provide implementations for the "serialize" and
92
+ "deserialize" methods, as well as values for the following class attributes.
93
+
94
+ Attributes:
95
+ accept: The value to use for the HTTP Accept header.
96
+ 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
98
+ Content" response.
99
+ alt_param: The value to supply as the "alt" query parameter for requests.
100
+ """
101
+
102
+ accept = None
103
+ content_type = None
104
+ no_content_response = None
105
+ alt_param = None
106
+
107
+ def _log_request(self, headers, path_params, query, body):
108
+ """Logs debugging information about the request if requested."""
109
+ if FLAGS.dump_request_response:
110
+ logging.info('--request-start--')
111
+ logging.info('-headers-start-')
112
+ for h, v in headers.iteritems():
113
+ logging.info('%s: %s', h, v)
114
+ logging.info('-headers-end-')
115
+ logging.info('-path-parameters-start-')
116
+ for h, v in path_params.iteritems():
117
+ logging.info('%s: %s', h, v)
118
+ logging.info('-path-parameters-end-')
119
+ logging.info('body: %s', body)
120
+ logging.info('query: %s', query)
121
+ logging.info('--request-end--')
122
+
123
+ def request(self, headers, path_params, query_params, body_value):
124
+ """Updates outgoing requests with a serialized body.
125
+
126
+ Args:
127
+ headers: dict, request headers
128
+ path_params: dict, parameters that appear in the request path
129
+ query_params: dict, parameters that appear in the query
130
+ body_value: object, the request body as a Python object, which must be
131
+ serializable by simplejson.
132
+ Returns:
133
+ A tuple of (headers, path_params, query, body)
134
+
135
+ headers: dict, request headers
136
+ path_params: dict, parameters that appear in the request path
137
+ query: string, query part of the request URI
138
+ body: string, the body serialized as JSON
139
+ """
140
+ query = self._build_query(query_params)
141
+ headers['accept'] = self.accept
142
+ headers['accept-encoding'] = 'gzip, deflate'
143
+ if 'user-agent' in headers:
144
+ headers['user-agent'] += ' '
145
+ else:
146
+ headers['user-agent'] = ''
147
+ headers['user-agent'] += 'google-api-python-client/1.0'
148
+
149
+ if body_value is not None:
150
+ headers['content-type'] = self.content_type
151
+ body_value = self.serialize(body_value)
152
+ self._log_request(headers, path_params, query, body_value)
153
+ return (headers, path_params, query, body_value)
154
+
155
+ def _build_query(self, params):
156
+ """Builds a query string.
157
+
158
+ Args:
159
+ params: dict, the query parameters
160
+
161
+ Returns:
162
+ The query parameters properly encoded into an HTTP URI query string.
163
+ """
164
+ if self.alt_param is not None:
165
+ params.update({'alt': self.alt_param})
166
+ astuples = []
167
+ for key, value in params.iteritems():
168
+ if type(value) == type([]):
169
+ for x in value:
170
+ x = x.encode('utf-8')
171
+ astuples.append((key, x))
172
+ else:
173
+ if getattr(value, 'encode', False) and callable(value.encode):
174
+ value = value.encode('utf-8')
175
+ astuples.append((key, value))
176
+ return '?' + urllib.urlencode(astuples)
177
+
178
+ def _log_response(self, resp, content):
179
+ """Logs debugging information about the response if requested."""
180
+ if FLAGS.dump_request_response:
181
+ logging.info('--response-start--')
182
+ for h, v in resp.iteritems():
183
+ logging.info('%s: %s', h, v)
184
+ if content:
185
+ logging.info(content)
186
+ logging.info('--response-end--')
187
+
188
+ def response(self, resp, content):
189
+ """Convert the response wire format into a Python object.
190
+
191
+ Args:
192
+ resp: httplib2.Response, the HTTP response headers and status
193
+ content: string, the body of the HTTP response
194
+
195
+ Returns:
196
+ The body de-serialized as a Python object.
197
+
198
+ Raises:
199
+ apiclient.errors.HttpError if a non 2xx response is received.
200
+ """
201
+ self._log_response(resp, content)
202
+ # Error handling is TBD, for example, do we retry
203
+ # for some operation/error combinations?
204
+ if resp.status < 300:
205
+ if resp.status == 204:
206
+ # A 204: No Content response should be treated differently
207
+ # to all the other success states
208
+ return self.no_content_response
209
+ return self.deserialize(content)
210
+ else:
211
+ logging.debug('Content from bad request was: %s' % content)
212
+ raise HttpError(resp, content)
213
+
214
+ def serialize(self, body_value):
215
+ """Perform the actual Python object serialization.
216
+
217
+ Args:
218
+ body_value: object, the request body as a Python object.
219
+
220
+ Returns:
221
+ string, the body in serialized form.
222
+ """
223
+ _abstract()
224
+
225
+ def deserialize(self, content):
226
+ """Perform the actual deserialization from response string to Python
227
+ object.
228
+
229
+ Args:
230
+ content: string, the body of the HTTP response
231
+
232
+ Returns:
233
+ The body de-serialized as a Python object.
234
+ """
235
+ _abstract()
236
+
237
+
238
+ class JsonModel(BaseModel):
239
+ """Model class for JSON.
240
+
241
+ Serializes and de-serializes between JSON and the Python
242
+ object representation of HTTP request and response bodies.
243
+ """
244
+ accept = 'application/json'
245
+ content_type = 'application/json'
246
+ alt_param = 'json'
247
+
248
+ def __init__(self, data_wrapper=False):
249
+ """Construct a JsonModel.
250
+
251
+ Args:
252
+ data_wrapper: boolean, wrap requests and responses in a data wrapper
253
+ """
254
+ self._data_wrapper = data_wrapper
255
+
256
+ def serialize(self, body_value):
257
+ if (isinstance(body_value, dict) and 'data' not in body_value and
258
+ self._data_wrapper):
259
+ body_value = {'data': body_value}
260
+ return simplejson.dumps(body_value)
261
+
262
+ def deserialize(self, content):
263
+ body = simplejson.loads(content)
264
+ if isinstance(body, dict) and 'data' in body:
265
+ body = body['data']
266
+ return body
267
+
268
+ @property
269
+ def no_content_response(self):
270
+ return {}
271
+
272
+
273
+ class RawModel(JsonModel):
274
+ """Model class for requests that don't return JSON.
275
+
276
+ Serializes and de-serializes between JSON and the Python
277
+ object representation of HTTP request, and returns the raw bytes
278
+ of the response body.
279
+ """
280
+ accept = '*/*'
281
+ content_type = 'application/json'
282
+ alt_param = None
283
+
284
+ def deserialize(self, content):
285
+ return content
286
+
287
+ @property
288
+ def no_content_response(self):
289
+ return ''
290
+
291
+
292
+ class MediaModel(JsonModel):
293
+ """Model class for requests that return Media.
294
+
295
+ Serializes and de-serializes between JSON and the Python
296
+ object representation of HTTP request, and returns the raw bytes
297
+ of the response body.
298
+ """
299
+ accept = '*/*'
300
+ content_type = 'application/json'
301
+ alt_param = 'media'
302
+
303
+ def deserialize(self, content):
304
+ return content
305
+
306
+ @property
307
+ def no_content_response(self):
308
+ return ''
309
+
310
+
311
+ class ProtocolBufferModel(BaseModel):
312
+ """Model class for protocol buffers.
313
+
314
+ Serializes and de-serializes the binary protocol buffer sent in the HTTP
315
+ request and response bodies.
316
+ """
317
+ accept = 'application/x-protobuf'
318
+ content_type = 'application/x-protobuf'
319
+ alt_param = 'proto'
320
+
321
+ def __init__(self, protocol_buffer):
322
+ """Constructs a ProtocolBufferModel.
323
+
324
+ The serialzed protocol buffer returned in an HTTP response will be
325
+ de-serialized using the given protocol buffer class.
326
+
327
+ Args:
328
+ protocol_buffer: The protocol buffer class used to de-serialize a
329
+ response from the API.
330
+ """
331
+ self._protocol_buffer = protocol_buffer
332
+
333
+ def serialize(self, body_value):
334
+ return body_value.SerializeToString()
335
+
336
+ def deserialize(self, content):
337
+ return self._protocol_buffer.FromString(content)
338
+
339
+ @property
340
+ def no_content_response(self):
341
+ return self._protocol_buffer()
342
+
343
+
344
+ def makepatch(original, modified):
345
+ """Create a patch object.
346
+
347
+ Some methods support PATCH, an efficient way to send updates to a resource.
348
+ This method allows the easy construction of patch bodies by looking at the
349
+ differences between a resource before and after it was modified.
350
+
351
+ Args:
352
+ original: object, the original deserialized resource
353
+ modified: object, the modified deserialized resource
354
+ Returns:
355
+ An object that contains only the changes from original to modified, in a
356
+ form suitable to pass to a PATCH method.
357
+
358
+ Example usage:
359
+ item = service.activities().get(postid=postid, userid=userid).execute()
360
+ original = copy.deepcopy(item)
361
+ item['object']['content'] = 'This is updated.'
362
+ service.activities.patch(postid=postid, userid=userid,
363
+ body=makepatch(original, item)).execute()
364
+ """
365
+ patch = {}
366
+ for key, original_value in original.iteritems():
367
+ modified_value = modified.get(key, None)
368
+ if modified_value is None:
369
+ # Use None to signal that the element is deleted
370
+ patch[key] = None
371
+ elif original_value != modified_value:
372
+ if type(original_value) == type({}):
373
+ # Recursively descend objects
374
+ patch[key] = makepatch(original_value, modified_value)
375
+ else:
376
+ # In the case of simple types or arrays we just replace
377
+ patch[key] = modified_value
378
+ else:
379
+ # Don't add anything to patch if there's no change
380
+ pass
381
+ for key in modified:
382
+ if key not in original:
383
+ patch[key] = modified[key]
384
+
385
+ return patch