googleapiclient 1.6.1

This commit is contained in:
Jay Lee
2017-01-24 14:03:03 -05:00
parent 22dc39eb85
commit b06b8608d0
4 changed files with 133 additions and 33 deletions

View File

@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
__version__ = "1.5.5"
__version__ = "1.6.1"
# Set default logging handler to avoid "No handler found" warnings.
import logging

View File

@@ -0,0 +1,91 @@
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helpers for authentication using oauth2client or google-auth."""
import httplib2
try:
import google.auth
import google.auth.credentials
import google_auth_httplib2
HAS_GOOGLE_AUTH = True
except ImportError: # pragma: NO COVER
HAS_GOOGLE_AUTH = False
try:
import oauth2client
import oauth2client.client
HAS_OAUTH2CLIENT = True
except ImportError: # pragma: NO COVER
HAS_OAUTH2CLIENT = False
def default_credentials():
"""Returns Application Default Credentials."""
if HAS_GOOGLE_AUTH:
credentials, _ = google.auth.default()
return credentials
elif HAS_OAUTH2CLIENT:
return oauth2client.client.GoogleCredentials.get_application_default()
else:
raise EnvironmentError(
'No authentication library is available. Please install either '
'google-auth or oauth2client.')
def with_scopes(credentials, scopes):
"""Scopes the credentials if necessary.
Args:
credentials (Union[
google.auth.credentials.Credentials,
oauth2client.client.Credentials]): The credentials to scope.
scopes (Sequence[str]): The list of scopes.
Returns:
Union[google.auth.credentials.Credentials,
oauth2client.client.Credentials]: The scoped credentials.
"""
if HAS_GOOGLE_AUTH and isinstance(
credentials, google.auth.credentials.Credentials):
return google.auth.credentials.with_scopes_if_required(
credentials, scopes)
else:
try:
if credentials.create_scoped_required():
return credentials.create_scoped(scopes)
else:
return credentials
except AttributeError:
return credentials
def authorized_http(credentials):
"""Returns an http client that is authorized with the given credentials.
Args:
credentials (Union[
google.auth.credentials.Credentials,
oauth2client.client.Credentials]): The credentials to use.
Returns:
Union[httplib2.Http, google_auth_httplib2.AuthorizedHttp]: An
authorized http client.
"""
if HAS_GOOGLE_AUTH and isinstance(
credentials, google.auth.credentials.Credentials):
return google_auth_httplib2.AuthorizedHttp(credentials)
else:
return credentials.authorize(httplib2.Http())

View File

@@ -53,6 +53,7 @@ import httplib2
import uritemplate
# Local imports
from googleapiclient import _auth
from googleapiclient import mimeparse
from googleapiclient.errors import HttpError
from googleapiclient.errors import InvalidJsonError
@@ -197,7 +198,8 @@ def build(serviceName,
model: googleapiclient.Model, converts to and from the wire format.
requestBuilder: googleapiclient.http.HttpRequest, encapsulator for an HTTP
request.
credentials: oauth2client.Credentials, credentials to be used for
credentials: oauth2client.Credentials or
google.auth.credentials.Credentials, credentials to be used for
authentication.
cache_discovery: Boolean, whether or not to cache the discovery doc.
cache: googleapiclient.discovery_cache.base.CacheBase, an optional
@@ -211,15 +213,14 @@ def build(serviceName,
'apiVersion': version
}
if http is None:
http = httplib2.Http()
discovery_http = http if http is not None else httplib2.Http()
for discovery_url in (discoveryServiceUrl, V2_DISCOVERY_URI,):
requested_url = uritemplate.expand(discovery_url, params)
try:
content = _retrieve_discovery_doc(requested_url, http, cache_discovery,
cache)
content = _retrieve_discovery_doc(
requested_url, discovery_http, cache_discovery, cache)
return build_from_document(content, base=discovery_url, http=http,
developerKey=developerKey, model=model, requestBuilder=requestBuilder,
credentials=credentials)
@@ -316,17 +317,16 @@ def build_from_document(
model: Model class instance that serializes and de-serializes requests and
responses.
requestBuilder: Takes an http request and packages it up to be executed.
credentials: object, credentials to be used for authentication.
credentials: oauth2client.Credentials or
google.auth.credentials.Credentials, credentials to be used for
authentication.
Returns:
A Resource object with methods for interacting with the service.
"""
if http is None:
http = httplib2.Http()
# future is no longer used.
future = {}
if http is not None and credentials is not None:
raise ValueError('Arguments http and credentials are mutually exclusive.')
if isinstance(service, six.string_types):
service = json.loads(service)
@@ -342,31 +342,36 @@ def build_from_document(
base = urljoin(service['rootUrl'], service['servicePath'])
schema = Schemas(service)
if credentials:
# If credentials were passed in, we could have two cases:
# 1. the scopes were specified, in which case the given credentials
# are used for authorizing the http;
# 2. the scopes were not provided (meaning the Application Default
# Credentials are to be used). In this case, the Application Default
# Credentials are built and used instead of the original credentials.
# If there are no scopes found (meaning the given service requires no
# authentication), there is no authorization of the http.
if (isinstance(credentials, GoogleCredentials) and
credentials.create_scoped_required()):
scopes = service.get('auth', {}).get('oauth2', {}).get('scopes', {})
if scopes:
credentials = credentials.create_scoped(list(scopes.keys()))
else:
# No need to authorize the http object
# if the service does not require authentication.
credentials = None
# If the http client is not specified, then we must construct an http client
# to make requests. If the service has scopes, then we also need to setup
# authentication.
if http is None:
# Does the service require scopes?
scopes = list(
service.get('auth', {}).get('oauth2', {}).get('scopes', {}).keys())
if credentials:
http = credentials.authorize(http)
# If so, then the we need to setup authentication.
if scopes:
# If the user didn't pass in credentials, attempt to acquire application
# default credentials.
if credentials is None:
credentials = _auth.default_credentials()
# The credentials need to be scoped.
credentials = _auth.with_scopes(credentials, scopes)
# Create an authorized http instance
http = _auth.authorized_http(credentials)
# If the service doesn't require scopes then there is no need for
# authentication.
else:
http = httplib2.Http()
if model is None:
features = service.get('features', [])
model = JsonModel('dataWrapper' in features)
return Resource(http=http, baseUrl=base, model=model,
developerKey=developerKey, requestBuilder=requestBuilder,
resourceDesc=service, rootDesc=service, schema=schema)

View File

@@ -996,7 +996,11 @@ class HttpRequest(object):
elif resp.status == 308:
self._in_error_state = False
# A "308 Resume Incomplete" indicates we are not done.
self.resumable_progress = int(resp['range'].split('-')[1]) + 1
try:
self.resumable_progress = int(resp['range'].split('-')[1]) + 1
except KeyError:
# If resp doesn't contain range header, resumable progress is 0
self.resumable_progress = 0
if 'location' in resp:
self.resumable_uri = resp['location']
else: