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

Unified Diff: tools/telemetry/third_party/gsutilz/third_party/apitools/apitools/base/py/base_api.py

Issue 1376593003: Roll gsutil version to 4.15. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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: tools/telemetry/third_party/gsutilz/third_party/apitools/apitools/base/py/base_api.py
diff --git a/tools/telemetry/third_party/gsutilz/third_party/apitools/apitools/base/py/base_api.py b/tools/telemetry/third_party/gsutilz/third_party/apitools/apitools/base/py/base_api.py
old mode 100755
new mode 100644
index d10314b67895b691b52d57bed31bfaaa8977bb41..97bbb6f69b1830c25b946fb18b1954dd23eb03f1
--- a/tools/telemetry/third_party/gsutilz/third_party/apitools/apitools/base/py/base_api.py
+++ b/tools/telemetry/third_party/gsutilz/third_party/apitools/apitools/base/py/base_api.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
"""Base class for api services."""
+import base64
import contextlib
import datetime
import logging
@@ -126,12 +127,29 @@ def NormalizeApiEndpoint(api_endpoint):
return api_endpoint
+def _urljoin(base, url): # pylint: disable=invalid-name
+ """Custom urljoin replacement supporting : before / in url."""
+ # In general, it's unsafe to simply join base and url. However, for
+ # the case of discovery documents, we know:
+ # * base will never contain params, query, or fragment
+ # * url will never contain a scheme or net_loc.
+ # In general, this means we can safely join on /; we just need to
+ # ensure we end up with precisely one / joining base and url. The
+ # exception here is the case of media uploads, where url will be an
+ # absolute url.
+ if url.startswith('http://') or url.startswith('https://'):
+ return urllib.parse.urljoin(base, url)
+ new_base = base if base.endswith('/') else base + '/'
+ new_url = url[1:] if url.startswith('/') else url
+ return new_base + new_url
+
+
class _UrlBuilder(object):
"""Convenient container for url data."""
def __init__(self, base_url, relative_path=None, query_params=None):
- components = urllib.parse.urlsplit(urllib.parse.urljoin(
+ components = urllib.parse.urlsplit(_urljoin(
base_url, relative_path or ''))
if components.fragment:
raise exceptions.ConfigurationValueError(
@@ -184,6 +202,11 @@ class _UrlBuilder(object):
self.__scheme, self.__netloc, self.relative_path, self.query, ''))
+def _SkipGetCredentials():
+ """Hook for skipping credentials. For internal use."""
+ return False
+
+
class BaseApiClient(object):
"""Base class for client libraries."""
@@ -198,7 +221,7 @@ class BaseApiClient(object):
def __init__(self, url, credentials=None, get_credentials=True, http=None,
model=None, log_request=False, log_response=False,
- num_retries=5, credentials_args=None,
+ num_retries=5, max_retry_wait=60, credentials_args=None,
default_global_params=None, additional_http_headers=None):
_RequireClassAttrs(self, ('_package', '_scopes', 'messages_module'))
if default_global_params is not None:
@@ -207,9 +230,12 @@ class BaseApiClient(object):
self.log_request = log_request
self.log_response = log_response
self.__num_retries = 5
+ self.__max_retry_wait = 60
# We let the @property machinery below do our validation.
self.num_retries = num_retries
+ self.max_retry_wait = max_retry_wait
self._credentials = credentials
+ get_credentials = get_credentials and not _SkipGetCredentials()
if get_credentials and not credentials:
credentials_args = credentials_args or {}
self._SetCredentials(**credentials_args)
@@ -334,6 +360,18 @@ class BaseApiClient(object):
'Cannot have negative value for num_retries')
self.__num_retries = value
+ @property
+ def max_retry_wait(self):
+ return self.__max_retry_wait
+
+ @max_retry_wait.setter
+ def max_retry_wait(self, value):
+ util.Typecheck(value, six.integer_types)
+ if value <= 0:
+ raise exceptions.InvalidDataError(
+ 'max_retry_wait must be a postiive integer')
+ self.__max_retry_wait = value
+
@contextlib.contextmanager
def WithRetries(self, num_retries):
old_num_retries = self.num_retries
@@ -452,6 +490,18 @@ class BaseApiService(object):
query_info['pp'] = 0
return query_info
+ def __FinalUrlValue(self, value, field):
+ """Encode value for the URL, using field to skip encoding for bytes."""
+ if isinstance(field, messages.BytesField) and value is not None:
+ return base64.urlsafe_b64encode(value)
+ elif isinstance(value, six.text_type):
+ return value.encode('utf8')
+ elif isinstance(value, six.binary_type):
+ return value.decode('utf8')
+ elif isinstance(value, datetime.datetime):
+ return value.isoformat()
+ return value
+
def __ConstructQueryParams(self, query_params, request, global_params):
"""Construct a dictionary of query parameters for this request."""
# First, handle the global params.
@@ -460,23 +510,24 @@ class BaseApiService(object):
global_param_names = util.MapParamNames(
[x.name for x in self.__client.params_type.all_fields()],
self.__client.params_type)
- query_info = dict((param, getattr(global_params, param))
- for param in global_param_names)
+ global_params_type = type(global_params)
+ query_info = dict(
+ (param,
+ self.__FinalUrlValue(getattr(global_params, param),
+ getattr(global_params_type, param)))
+ for param in global_param_names)
# Next, add the query params.
query_param_names = util.MapParamNames(query_params, type(request))
- query_info.update((param, getattr(request, param, None))
- for param in query_param_names)
+ request_type = type(request)
+ query_info.update(
+ (param,
+ self.__FinalUrlValue(getattr(request, param, None),
+ getattr(request_type, param)))
+ for param in query_param_names)
query_info = dict((k, v) for k, v in query_info.items()
if v is not None)
query_info = self.__EncodePrettyPrint(query_info)
query_info = util.MapRequestParams(query_info, type(request))
- for k, v in query_info.items():
- if isinstance(v, six.text_type):
- query_info[k] = v.encode('utf8')
- elif isinstance(v, str):
- query_info[k] = v.decode('utf8')
- elif isinstance(v, datetime.datetime):
- query_info[k] = v.isoformat()
return query_info
def __ConstructRelativePath(self, method_config, request,
@@ -547,6 +598,9 @@ class BaseApiService(object):
util.Typecheck(body_field, messages.MessageField)
body_type = body_field.type
+ # If there was no body provided, we use an empty message of the
+ # appropriate type.
+ body_value = body_value or body_type()
if upload and not body_value:
# We're going to fill in the body later.
return
@@ -617,7 +671,8 @@ class BaseApiService(object):
if upload and upload.bytes_http:
http = upload.bytes_http
http_response = http_wrapper.MakeRequest(
- http, http_request, retries=self.__client.num_retries)
+ http, http_request, retries=self.__client.num_retries,
+ max_retry_wait=self.__client.max_retry_wait)
return self.ProcessHttpResponse(method_config, http_response)

Powered by Google App Engine
This is Rietveld 408576698