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

Side by Side Diff: third_party/google-endpoints/apitools/base/py/util.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 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
(Empty)
1 #!/usr/bin/env python
2 #
3 # Copyright 2015 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 """Assorted utilities shared between parts of apitools."""
18
19 import collections
20 import os
21 import random
22
23 import six
24 from six.moves import http_client
25 import six.moves.urllib.error as urllib_error
26 import six.moves.urllib.parse as urllib_parse
27 import six.moves.urllib.request as urllib_request
28
29 from apitools.base.protorpclite import messages
30 from apitools.base.py import encoding
31 from apitools.base.py import exceptions
32
33 __all__ = [
34 'DetectGae',
35 'DetectGce',
36 ]
37
38 _RESERVED_URI_CHARS = r":/?#[]@!$&'()*+,;="
39
40
41 def DetectGae():
42 """Determine whether or not we're running on GAE.
43
44 This is based on:
45 https://developers.google.com/appengine/docs/python/#The_Environment
46
47 Returns:
48 True iff we're running on GAE.
49 """
50 server_software = os.environ.get('SERVER_SOFTWARE', '')
51 return (server_software.startswith('Development/') or
52 server_software.startswith('Google App Engine/'))
53
54
55 def DetectGce():
56 """Determine whether or not we're running on GCE.
57
58 This is based on:
59 https://cloud.google.com/compute/docs/metadata#runninggce
60
61 Returns:
62 True iff we're running on a GCE instance.
63 """
64 try:
65 o = urllib_request.build_opener(urllib_request.ProxyHandler({})).open(
66 urllib_request.Request('http://metadata.google.internal'))
67 except urllib_error.URLError:
68 return False
69 return (o.getcode() == http_client.OK and
70 o.headers.get('metadata-flavor') == 'Google')
71
72
73 def NormalizeScopes(scope_spec):
74 """Normalize scope_spec to a set of strings."""
75 if isinstance(scope_spec, six.string_types):
76 return set(scope_spec.split(' '))
77 elif isinstance(scope_spec, collections.Iterable):
78 return set(scope_spec)
79 raise exceptions.TypecheckError(
80 'NormalizeScopes expected string or iterable, found %s' % (
81 type(scope_spec),))
82
83
84 def Typecheck(arg, arg_type, msg=None):
85 if not isinstance(arg, arg_type):
86 if msg is None:
87 if isinstance(arg_type, tuple):
88 msg = 'Type of arg is "%s", not one of %r' % (
89 type(arg), arg_type)
90 else:
91 msg = 'Type of arg is "%s", not "%s"' % (type(arg), arg_type)
92 raise exceptions.TypecheckError(msg)
93 return arg
94
95
96 def ExpandRelativePath(method_config, params, relative_path=None):
97 """Determine the relative path for request."""
98 path = relative_path or method_config.relative_path or ''
99
100 for param in method_config.path_params:
101 param_template = '{%s}' % param
102 # For more details about "reserved word expansion", see:
103 # http://tools.ietf.org/html/rfc6570#section-3.2.2
104 reserved_chars = ''
105 reserved_template = '{+%s}' % param
106 if reserved_template in path:
107 reserved_chars = _RESERVED_URI_CHARS
108 path = path.replace(reserved_template, param_template)
109 if param_template not in path:
110 raise exceptions.InvalidUserInputError(
111 'Missing path parameter %s' % param)
112 try:
113 # TODO(craigcitro): Do we want to support some sophisticated
114 # mapping here?
115 value = params[param]
116 except KeyError:
117 raise exceptions.InvalidUserInputError(
118 'Request missing required parameter %s' % param)
119 if value is None:
120 raise exceptions.InvalidUserInputError(
121 'Request missing required parameter %s' % param)
122 try:
123 if not isinstance(value, six.string_types):
124 value = str(value)
125 path = path.replace(param_template,
126 urllib_parse.quote(value.encode('utf_8'),
127 reserved_chars))
128 except TypeError as e:
129 raise exceptions.InvalidUserInputError(
130 'Error setting required parameter %s to value %s: %s' % (
131 param, value, e))
132 return path
133
134
135 def CalculateWaitForRetry(retry_attempt, max_wait=60):
136 """Calculates amount of time to wait before a retry attempt.
137
138 Wait time grows exponentially with the number of attempts. A
139 random amount of jitter is added to spread out retry attempts from
140 different clients.
141
142 Args:
143 retry_attempt: Retry attempt counter.
144 max_wait: Upper bound for wait time [seconds].
145
146 Returns:
147 Number of seconds to wait before retrying request.
148
149 """
150
151 wait_time = 2 ** retry_attempt
152 max_jitter = wait_time / 4.0
153 wait_time += random.uniform(-max_jitter, max_jitter)
154 return max(1, min(wait_time, max_wait))
155
156
157 def AcceptableMimeType(accept_patterns, mime_type):
158 """Return True iff mime_type is acceptable for one of accept_patterns.
159
160 Note that this function assumes that all patterns in accept_patterns
161 will be simple types of the form "type/subtype", where one or both
162 of these can be "*". We do not support parameters (i.e. "; q=") in
163 patterns.
164
165 Args:
166 accept_patterns: list of acceptable MIME types.
167 mime_type: the mime type we would like to match.
168
169 Returns:
170 Whether or not mime_type matches (at least) one of these patterns.
171 """
172 if '/' not in mime_type:
173 raise exceptions.InvalidUserInputError(
174 'Invalid MIME type: "%s"' % mime_type)
175 unsupported_patterns = [p for p in accept_patterns if ';' in p]
176 if unsupported_patterns:
177 raise exceptions.GeneratedClientError(
178 'MIME patterns with parameter unsupported: "%s"' % ', '.join(
179 unsupported_patterns))
180
181 def MimeTypeMatches(pattern, mime_type):
182 """Return True iff mime_type is acceptable for pattern."""
183 # Some systems use a single '*' instead of '*/*'.
184 if pattern == '*':
185 pattern = '*/*'
186 return all(accept in ('*', provided) for accept, provided
187 in zip(pattern.split('/'), mime_type.split('/')))
188
189 return any(MimeTypeMatches(pattern, mime_type)
190 for pattern in accept_patterns)
191
192
193 def MapParamNames(params, request_type):
194 """Reverse parameter remappings for URL construction."""
195 return [encoding.GetCustomJsonFieldMapping(request_type, json_name=p) or p
196 for p in params]
197
198
199 def MapRequestParams(params, request_type):
200 """Perform any renames/remappings needed for URL construction.
201
202 Currently, we have several ways to customize JSON encoding, in
203 particular of field names and enums. This works fine for JSON
204 bodies, but also needs to be applied for path and query parameters
205 in the URL.
206
207 This function takes a dictionary from param names to values, and
208 performs any registered mappings. We also need the request type (to
209 look up the mappings).
210
211 Args:
212 params: (dict) Map from param names to values
213 request_type: (protorpc.messages.Message) request type for this API call
214
215 Returns:
216 A new dict of the same size, with all registered mappings applied.
217 """
218 new_params = dict(params)
219 for param_name, value in params.items():
220 field_remapping = encoding.GetCustomJsonFieldMapping(
221 request_type, python_name=param_name)
222 if field_remapping is not None:
223 new_params[field_remapping] = new_params.pop(param_name)
224 if isinstance(value, messages.Enum):
225 new_params[param_name] = encoding.GetCustomJsonEnumMapping(
226 type(value), python_name=str(value)) or str(value)
227 return new_params
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698