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

Unified Diff: third_party/gsutil/third_party/apitools/apitools/base/py/util.py

Issue 1377933002: [catapult] - Copy Telemetry's gsutilz over to third_party. (Closed) Base URL: https://github.com/catapult-project/catapult.git@master
Patch Set: Rename to gsutil. Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: third_party/gsutil/third_party/apitools/apitools/base/py/util.py
diff --git a/third_party/gsutil/third_party/apitools/apitools/base/py/util.py b/third_party/gsutil/third_party/apitools/apitools/base/py/util.py
new file mode 100755
index 0000000000000000000000000000000000000000..779dd97f13dce1d5f076118b66accb3e3666974c
--- /dev/null
+++ b/third_party/gsutil/third_party/apitools/apitools/base/py/util.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+"""Assorted utilities shared between parts of apitools."""
+
+import collections
+import os
+import random
+
+from protorpc import messages
+import six
+from six.moves import http_client
+import six.moves.urllib.error as urllib_error
+import six.moves.urllib.parse as urllib_parse
+import six.moves.urllib.request as urllib_request
+
+from apitools.base.py import encoding
+from apitools.base.py import exceptions
+
+__all__ = [
+ 'DetectGae',
+ 'DetectGce',
+]
+
+_RESERVED_URI_CHARS = r":/?#[]@!$&'()*+,;="
+
+
+def DetectGae():
+ """Determine whether or not we're running on GAE.
+
+ This is based on:
+ https://developers.google.com/appengine/docs/python/#The_Environment
+
+ Returns:
+ True iff we're running on GAE.
+ """
+ server_software = os.environ.get('SERVER_SOFTWARE', '')
+ return (server_software.startswith('Development/') or
+ server_software.startswith('Google App Engine/'))
+
+
+def DetectGce():
+ """Determine whether or not we're running on GCE.
+
+ This is based on:
+ https://cloud.google.com/compute/docs/metadata#runninggce
+
+ Returns:
+ True iff we're running on a GCE instance.
+ """
+ try:
+ o = urllib_request.build_opener(urllib_request.ProxyHandler({})).open(
+ urllib_request.Request('http://metadata.google.internal'))
+ except urllib_error.URLError:
+ return False
+ return (o.getcode() == http_client.OK and
+ o.headers.get('metadata-flavor') == 'Google')
+
+
+def NormalizeScopes(scope_spec):
+ """Normalize scope_spec to a set of strings."""
+ if isinstance(scope_spec, six.string_types):
+ return set(scope_spec.split(' '))
+ elif isinstance(scope_spec, collections.Iterable):
+ return set(scope_spec)
+ raise exceptions.TypecheckError(
+ 'NormalizeScopes expected string or iterable, found %s' % (
+ type(scope_spec),))
+
+
+def Typecheck(arg, arg_type, msg=None):
+ if not isinstance(arg, arg_type):
+ if msg is None:
+ if isinstance(arg_type, tuple):
+ msg = 'Type of arg is "%s", not one of %r' % (
+ type(arg), arg_type)
+ else:
+ msg = 'Type of arg is "%s", not "%s"' % (type(arg), arg_type)
+ raise exceptions.TypecheckError(msg)
+ return arg
+
+
+def ExpandRelativePath(method_config, params, relative_path=None):
+ """Determine the relative path for request."""
+ path = relative_path or method_config.relative_path or ''
+
+ for param in method_config.path_params:
+ param_template = '{%s}' % param
+ # For more details about "reserved word expansion", see:
+ # http://tools.ietf.org/html/rfc6570#section-3.2.2
+ reserved_chars = ''
+ reserved_template = '{+%s}' % param
+ if reserved_template in path:
+ reserved_chars = _RESERVED_URI_CHARS
+ path = path.replace(reserved_template, param_template)
+ if param_template not in path:
+ raise exceptions.InvalidUserInputError(
+ 'Missing path parameter %s' % param)
+ try:
+ # TODO(craigcitro): Do we want to support some sophisticated
+ # mapping here?
+ value = params[param]
+ except KeyError:
+ raise exceptions.InvalidUserInputError(
+ 'Request missing required parameter %s' % param)
+ if value is None:
+ raise exceptions.InvalidUserInputError(
+ 'Request missing required parameter %s' % param)
+ try:
+ if not isinstance(value, six.string_types):
+ value = str(value)
+ path = path.replace(param_template,
+ urllib_parse.quote(value.encode('utf_8'),
+ reserved_chars))
+ except TypeError as e:
+ raise exceptions.InvalidUserInputError(
+ 'Error setting required parameter %s to value %s: %s' % (
+ param, value, e))
+ return path
+
+
+def CalculateWaitForRetry(retry_attempt, max_wait=60):
+ """Calculates amount of time to wait before a retry attempt.
+
+ Wait time grows exponentially with the number of attempts. A
+ random amount of jitter is added to spread out retry attempts from
+ different clients.
+
+ Args:
+ retry_attempt: Retry attempt counter.
+ max_wait: Upper bound for wait time.
+
+ Returns:
+ Amount of time to wait before retrying request.
+
+ """
+
+ wait_time = 2 ** retry_attempt
+ # randrange requires a nonzero interval, so we want to drop it if
+ # the range is too small for jitter.
+ if retry_attempt:
+ max_jitter = (2 ** retry_attempt) / 2
+ wait_time += random.randrange(-max_jitter, max_jitter)
+ return min(wait_time, max_wait)
+
+
+def AcceptableMimeType(accept_patterns, mime_type):
+ """Return True iff mime_type is acceptable for one of accept_patterns.
+
+ Note that this function assumes that all patterns in accept_patterns
+ will be simple types of the form "type/subtype", where one or both
+ of these can be "*". We do not support parameters (i.e. "; q=") in
+ patterns.
+
+ Args:
+ accept_patterns: list of acceptable MIME types.
+ mime_type: the mime type we would like to match.
+
+ Returns:
+ Whether or not mime_type matches (at least) one of these patterns.
+ """
+ if '/' not in mime_type:
+ raise exceptions.InvalidUserInputError(
+ 'Invalid MIME type: "%s"' % mime_type)
+ unsupported_patterns = [p for p in accept_patterns if ';' in p]
+ if unsupported_patterns:
+ raise exceptions.GeneratedClientError(
+ 'MIME patterns with parameter unsupported: "%s"' % ', '.join(
+ unsupported_patterns))
+
+ def MimeTypeMatches(pattern, mime_type):
+ """Return True iff mime_type is acceptable for pattern."""
+ # Some systems use a single '*' instead of '*/*'.
+ if pattern == '*':
+ pattern = '*/*'
+ return all(accept in ('*', provided) for accept, provided
+ in zip(pattern.split('/'), mime_type.split('/')))
+
+ return any(MimeTypeMatches(pattern, mime_type)
+ for pattern in accept_patterns)
+
+
+def MapParamNames(params, request_type):
+ """Reverse parameter remappings for URL construction."""
+ return [encoding.GetCustomJsonFieldMapping(request_type, json_name=p) or p
+ for p in params]
+
+
+def MapRequestParams(params, request_type):
+ """Perform any renames/remappings needed for URL construction.
+
+ Currently, we have several ways to customize JSON encoding, in
+ particular of field names and enums. This works fine for JSON
+ bodies, but also needs to be applied for path and query parameters
+ in the URL.
+
+ This function takes a dictionary from param names to values, and
+ performs any registered mappings. We also need the request type (to
+ look up the mappings).
+
+ Args:
+ params: (dict) Map from param names to values
+ request_type: (protorpc.messages.Message) request type for this API call
+
+ Returns:
+ A new dict of the same size, with all registered mappings applied.
+ """
+ new_params = dict(params)
+ for param_name, value in params.items():
+ field_remapping = encoding.GetCustomJsonFieldMapping(
+ request_type, python_name=param_name)
+ if field_remapping is not None:
+ new_params[field_remapping] = new_params.pop(param_name)
+ if isinstance(value, messages.Enum):
+ new_params[param_name] = encoding.GetCustomJsonEnumMapping(
+ type(value), python_name=str(value)) or str(value)
+ return new_params

Powered by Google App Engine
This is Rietveld 408576698