Hello community,
here is the log from the commit of package python-google-api-python-client for
openSUSE:Factory checked in at 2020-10-15 13:48:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-api-python-client (Old)
and /work/SRC/openSUSE:Factory/.python-google-api-python-client.new.3486
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-google-api-python-client"
Thu Oct 15 13:48:48 2020 rev:16 rq:833488 version:1.11.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-google-api-python-client/python-google-api-python-client.changes
2020-06-25 15:11:49.602193418 +0200
+++
/work/SRC/openSUSE:Factory/.python-google-api-python-client.new.3486/python-google-api-python-client.changes
2020-10-15 13:49:23.453274035 +0200
@@ -1,0 +2,28 @@
+Thu Sep 10 14:05:18 UTC 2020 - John Paul Adrian Glaubitz
<[email protected]>
+
+- Update to version 1.11.0
+ * add support for mtls env variables (#1008)
+- from version 1.10.1
+ * discovery uses V2 when version is None (#975), closes (#971)
+ * fix deprecation warnings due to invalid escape sequences. (#996), closes
(#995)
+ * fix link to service accounts documentation (#986)
+ * update generated docs (#981)
+- from version 1.10.0
+ * allow to use 'six.moves.collections_abc.Mapping' in
'client_options.from_dict()' (#943)
+ * Build universal wheels (#948)
+ * discovery supports retries (#967), closes (#848)
+ * consolidating and updating the Contribution Guide (#964), closes (#963)
+- from version 1.9.3
+ * update GOOGLE_API_USE_MTLS values (#940)
+- from version 1.9.2
+ * bump api-core version (#936)
+- from version 1.9.1
+ * fix python-api-core dependency issue (#931)
+- from version 1.9.0
+ * add mtls feature (#917)
+ * add templates for python samples projects (#506), (#924)
+- Refresh patches for new version
+ + python-google-api-python-client-no-unittest2.patch
+- Update BuildRequires and Requires from setup.py
+
+-------------------------------------------------------------------
Old:
----
google-api-python-client-1.8.4.tar.gz
New:
----
google-api-python-client-1.11.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-google-api-python-client.spec ++++++
--- /var/tmp/diff_new_pack.ucJiIH/_old 2020-10-15 13:49:24.229274359 +0200
+++ /var/tmp/diff_new_pack.ucJiIH/_new 2020-10-15 13:49:24.233274361 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-google-api-python-client
-Version: 1.8.4
+Version: 1.11.0
Release: 0
Summary: Google APIs Python Client
License: Apache-2.0
@@ -27,20 +27,21 @@
Source:
https://files.pythonhosted.org/packages/source/g/google-api-python-client/google-api-python-client-%{version}.tar.gz
# https://github.com/googleapis/google-api-python-client/pull/929
Patch0: python-google-api-python-client-no-unittest2.patch
-BuildRequires: %{python_module google-api-core >= 1.13.0}
-BuildRequires: %{python_module google-auth >= 1.4.1}
+BuildRequires: %{python_module google-api-core >= 1.18.0}
+BuildRequires: %{python_module google-auth >= 1.16.0}
BuildRequires: %{python_module google-auth-httplib2 >= 0.0.3}
BuildRequires: %{python_module httplib2 >= 0.9.2}
BuildRequires: %{python_module mock}
BuildRequires: %{python_module oauth2client}
+BuildRequires: %{python_module parameterized}
BuildRequires: %{python_module pytest}
BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module six >= 1.6.1}
BuildRequires: %{python_module uritemplate >= 3.0.0}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-Requires: python-google-api-core >= 1.13.0
-Requires: python-google-auth >= 1.4.1
+Requires: python-google-api-core >= 1.18.0
+Requires: python-google-auth >= 1.16.0
Requires: python-google-auth-httplib2 >= 0.0.3
Requires: python-httplib2 >= 0.9.2
Requires: python-six >= 1.6.1
++++++ google-api-python-client-1.8.4.tar.gz ->
google-api-python-client-1.11.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/PKG-INFO
new/google-api-python-client-1.11.0/PKG-INFO
--- old/google-api-python-client-1.8.4/PKG-INFO 2020-05-26 22:19:38.414078000
+0200
+++ new/google-api-python-client-1.11.0/PKG-INFO 2020-08-27
23:35:31.385575800 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-api-python-client
-Version: 1.8.4
+Version: 1.11.0
Summary: Google API Client Library for Python
Home-page: https://github.com/googleapis/google-api-python-client/
Author: Google LLC
@@ -74,7 +74,9 @@
## Contributing
- Please see the [contributing
page](http://google.github.io/google-api-python-client/contributing.html) for
more information. In particular, we love pull requests - but please make sure
to sign the contributor license agreement.
+ Please see our [Contribution Guide](CONTRIBUTING.rst).
+ In particular, we love pull requests - but please make sure to sign
+ the contributor license agreement.
Keywords: google api client
Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/README.md
new/google-api-python-client-1.11.0/README.md
--- old/google-api-python-client-1.8.4/README.md 2020-05-26
22:17:52.000000000 +0200
+++ new/google-api-python-client-1.11.0/README.md 2020-08-27
23:33:50.000000000 +0200
@@ -66,4 +66,6 @@
## Contributing
-Please see the [contributing
page](http://google.github.io/google-api-python-client/contributing.html) for
more information. In particular, we love pull requests - but please make sure
to sign the contributor license agreement.
+Please see our [Contribution Guide](CONTRIBUTING.rst).
+In particular, we love pull requests - but please make sure to sign
+the contributor license agreement.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/google_api_python_client.egg-info/PKG-INFO
new/google-api-python-client-1.11.0/google_api_python_client.egg-info/PKG-INFO
---
old/google-api-python-client-1.8.4/google_api_python_client.egg-info/PKG-INFO
2020-05-26 22:19:38.000000000 +0200
+++
new/google-api-python-client-1.11.0/google_api_python_client.egg-info/PKG-INFO
2020-08-27 23:35:31.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-api-python-client
-Version: 1.8.4
+Version: 1.11.0
Summary: Google API Client Library for Python
Home-page: https://github.com/googleapis/google-api-python-client/
Author: Google LLC
@@ -74,7 +74,9 @@
## Contributing
- Please see the [contributing
page](http://google.github.io/google-api-python-client/contributing.html) for
more information. In particular, we love pull requests - but please make sure
to sign the contributor license agreement.
+ Please see our [Contribution Guide](CONTRIBUTING.rst).
+ In particular, we love pull requests - but please make sure to sign
+ the contributor license agreement.
Keywords: google api client
Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/google_api_python_client.egg-info/SOURCES.txt
new/google-api-python-client-1.11.0/google_api_python_client.egg-info/SOURCES.txt
---
old/google-api-python-client-1.8.4/google_api_python_client.egg-info/SOURCES.txt
2020-05-26 22:19:38.000000000 +0200
+++
new/google-api-python-client-1.11.0/google_api_python_client.egg-info/SOURCES.txt
2020-08-27 23:35:31.000000000 +0200
@@ -1,6 +1,7 @@
LICENSE
MANIFEST.in
README.md
+setup.cfg
setup.py
apiclient/__init__.py
google_api_python_client.egg-info/PKG-INFO
@@ -36,6 +37,8 @@
tests/test_model.py
tests/test_protobuf_model.py
tests/test_schema.py
+tests/data/500.json
+tests/data/503.json
tests/data/bad_request.json
tests/data/bigquery.json
tests/data/certs.json
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/google_api_python_client.egg-info/requires.txt
new/google-api-python-client-1.11.0/google_api_python_client.egg-info/requires.txt
---
old/google-api-python-client-1.8.4/google_api_python_client.egg-info/requires.txt
2020-05-26 22:19:38.000000000 +0200
+++
new/google-api-python-client-1.11.0/google_api_python_client.egg-info/requires.txt
2020-08-27 23:35:31.000000000 +0200
@@ -1,6 +1,6 @@
httplib2<1dev,>=0.9.2
-google-auth>=1.4.1
+google-auth>=1.16.0
google-auth-httplib2>=0.0.3
-google-api-core<2dev,>=1.13.0
+google-api-core<2dev,>=1.18.0
six<2dev,>=1.6.1
uritemplate<4dev,>=3.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/googleapiclient/discovery.py
new/google-api-python-client-1.11.0/googleapiclient/discovery.py
--- old/google-api-python-client-1.8.4/googleapiclient/discovery.py
2020-05-26 22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/googleapiclient/discovery.py
2020-08-27 23:33:51.000000000 +0200
@@ -29,7 +29,7 @@
# Standard library imports
import copy
-
+from collections import OrderedDict
try:
from email.generator import BytesGenerator
except ImportError:
@@ -47,6 +47,13 @@
import httplib2
import uritemplate
import google.api_core.client_options
+from google.auth.transport import mtls
+from google.auth.exceptions import MutualTLSChannelError
+
+try:
+ import google_auth_httplib2
+except ImportError: # pragma: NO COVER
+ google_auth_httplib2 = None
# Local imports
from googleapiclient import _auth
@@ -110,6 +117,10 @@
}
_PAGE_TOKEN_NAMES = ("pageToken", "nextPageToken")
+# Parameters controlling mTLS behavior. See https://google.aip.dev/auth/4114.
+GOOGLE_API_USE_CLIENT_CERTIFICATE = "GOOGLE_API_USE_CLIENT_CERTIFICATE"
+GOOGLE_API_USE_MTLS_ENDPOINT = "GOOGLE_API_USE_MTLS_ENDPOINT"
+
# Parameters accepted by the stack, but not visible via discovery.
# TODO(dhermes): Remove 'userip' in 'v2'.
STACK_QUERY_PARAMETERS = frozenset(["trace", "pp", "userip", "strict"])
@@ -132,7 +143,7 @@
Returns:
The name with '_' appended if the name is a reserved word and '$' and '-'
- replaced with '_'.
+ replaced with '_'.
"""
name = name.replace("$", "_").replace("-", "_")
if keyword.iskeyword(name) or name in RESERVED_WORDS:
@@ -178,6 +189,9 @@
cache_discovery=True,
cache=None,
client_options=None,
+ adc_cert_path=None,
+ adc_key_path=None,
+ num_retries=1,
):
"""Construct a Resource for interacting with an API.
@@ -204,11 +218,40 @@
cache_discovery: Boolean, whether or not to cache the discovery doc.
cache: googleapiclient.discovery_cache.base.CacheBase, an optional
cache object for the discovery documents.
- client_options: Dictionary or google.api_core.client_options, Client
options to set user
- options on the client. API endpoint should be set through client_options.
+ client_options: Mapping object or google.api_core.client_options, client
+ options to set user options on the client.
+ (1) The API endpoint should be set through client_options. If API
endpoint
+ is not set, `GOOGLE_API_USE_MTLS_ENDPOINT` environment variable can be
used
+ to control which endpoint to use.
+ (2) client_cert_source is not supported, client cert should be provided
using
+ client_encrypted_cert_source instead. In order to use the provided client
+ cert, `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be
+ set to `true`.
+ More details on the environment variables are here:
+ https://google.aip.dev/auth/4114
+ adc_cert_path: str, client certificate file path to save the application
+ default client certificate for mTLS. This field is required if you want
to
+ use the default client certificate. `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable must be set to `true` in order to use this field,
+ otherwise this field doesn't nothing.
+ More details on the environment variables are here:
+ https://google.aip.dev/auth/4114
+ adc_key_path: str, client encrypted private key file path to save the
+ application default client encrypted private key for mTLS. This field is
+ required if you want to use the default client certificate.
+ `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be set to
+ `true` in order to use this field, otherwise this field doesn't nothing.
+ More details on the environment variables are here:
+ https://google.aip.dev/auth/4114
+ num_retries: Integer, number of times to retry discovery with
+ randomized exponential backoff in case of intermittent/connection issues.
Returns:
A Resource object with methods for interacting with the service.
+
+ Raises:
+ google.auth.exceptions.MutualTLSChannelError: if there are any problems
+ setting up mutual TLS channel.
"""
params = {"api": serviceName, "apiVersion": version}
@@ -217,12 +260,14 @@
else:
discovery_http = http
- for discovery_url in (discoveryServiceUrl, V2_DISCOVERY_URI):
+ for discovery_url in \
+ _discovery_service_uri_options(discoveryServiceUrl, version):
requested_url = uritemplate.expand(discovery_url, params)
try:
content = _retrieve_discovery_doc(
- requested_url, discovery_http, cache_discovery, cache,
developerKey
+ requested_url, discovery_http, cache_discovery, cache,
+ developerKey, num_retries=num_retries
)
return build_from_document(
content,
@@ -232,7 +277,9 @@
model=model,
requestBuilder=requestBuilder,
credentials=credentials,
- client_options=client_options
+ client_options=client_options,
+ adc_cert_path=adc_cert_path,
+ adc_key_path=adc_key_path,
)
except HttpError as e:
if e.resp.status == http_client.NOT_FOUND:
@@ -243,7 +290,31 @@
raise UnknownApiNameOrVersion("name: %s version: %s" % (serviceName,
version))
-def _retrieve_discovery_doc(url, http, cache_discovery, cache=None,
developerKey=None):
+def _discovery_service_uri_options(discoveryServiceUrl, version):
+ """
+ Returns Discovery URIs to be used for attemnting to build the API Resource.
+
+ Args:
+ discoveryServiceUrl:
+ string, the Original Discovery Service URL preferred by the customer.
+ version:
+ string, API Version requested
+
+ Returns:
+ A list of URIs to be tried for the Service Discovery, in order.
+ """
+
+ urls = [discoveryServiceUrl, V2_DISCOVERY_URI]
+ # V1 Discovery won't work if the requested version is None
+ if discoveryServiceUrl == V1_DISCOVERY_URI and version is None:
+ logger.warning(
+ "Discovery V1 does not support empty versions. Defaulting to
V2...")
+ urls.pop(0)
+ return list(OrderedDict.fromkeys(urls))
+
+
+def _retrieve_discovery_doc(url, http, cache_discovery,
+ cache=None, developerKey=None, num_retries=1):
"""Retrieves the discovery_doc from cache or the internet.
Args:
@@ -253,13 +324,16 @@
cache_discovery: Boolean, whether or not to cache the discovery doc.
cache: googleapiclient.discovery_cache.base.Cache, an optional cache
object for the discovery documents.
+ developerKey: string, Key for controlling API usage, generated
+ from the API Console.
+ num_retries: Integer, number of times to retry discovery with
+ randomized exponential backoff in case of intermittent/connection issues.
Returns:
A unicode string representation of the discovery document.
"""
if cache_discovery:
from . import discovery_cache
- from .discovery_cache import base
if cache is None:
cache = discovery_cache.autodetect()
@@ -279,10 +353,10 @@
actual_url = _add_query_parameter(url, "key", developerKey)
logger.debug("URL being requested: GET %s", actual_url)
- resp, content = http.request(actual_url)
-
- if resp.status >= 400:
- raise HttpError(resp, content, uri=actual_url)
+ # Execute this request with retries build into HttpRequest
+ # Note that it will already raise an error if we don't get a 2xx response
+ req = HttpRequest(http, HttpRequest.null_postproc, actual_url)
+ resp, content = req.execute(num_retries=num_retries)
try:
content = content.decode("utf-8")
@@ -309,7 +383,9 @@
model=None,
requestBuilder=HttpRequest,
credentials=None,
- client_options=None
+ client_options=None,
+ adc_cert_path=None,
+ adc_key_path=None,
):
"""Create a Resource for interacting with an API.
@@ -334,11 +410,38 @@
credentials: oauth2client.Credentials or
google.auth.credentials.Credentials, credentials to be used for
authentication.
- client_options: Dictionary or google.api_core.client_options, Client
options to set user
- options on the client. API endpoint should be set through client_options.
+ client_options: Mapping object or google.api_core.client_options, client
+ options to set user options on the client.
+ (1) The API endpoint should be set through client_options. If API
endpoint
+ is not set, `GOOGLE_API_USE_MTLS_ENDPOINT` environment variable can be
used
+ to control which endpoint to use.
+ (2) client_cert_source is not supported, client cert should be provided
using
+ client_encrypted_cert_source instead. In order to use the provided client
+ cert, `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be
+ set to `true`.
+ More details on the environment variables are here:
+ https://google.aip.dev/auth/4114
+ adc_cert_path: str, client certificate file path to save the application
+ default client certificate for mTLS. This field is required if you want
to
+ use the default client certificate. `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+ environment variable must be set to `true` in order to use this field,
+ otherwise this field doesn't nothing.
+ More details on the environment variables are here:
+ https://google.aip.dev/auth/4114
+ adc_key_path: str, client encrypted private key file path to save the
+ application default client encrypted private key for mTLS. This field is
+ required if you want to use the default client certificate.
+ `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be set to
+ `true` in order to use this field, otherwise this field doesn't nothing.
+ More details on the environment variables are here:
+ https://google.aip.dev/auth/4114
Returns:
A Resource object with methods for interacting with the service.
+
+ Raises:
+ google.auth.exceptions.MutualTLSChannelError: if there are any problems
+ setting up mutual TLS channel.
"""
if http is not None and credentials is not None:
@@ -349,7 +452,7 @@
elif isinstance(service, six.binary_type):
service = json.loads(service.decode("utf-8"))
- if "rootUrl" not in service and (isinstance(http, (HttpMock,
HttpMockSequence))):
+ if "rootUrl" not in service and isinstance(http, (HttpMock,
HttpMockSequence)):
logger.error(
"You are using HttpMock or HttpMockSequence without"
+ "having the service discovery doc in cache. Try calling "
@@ -359,12 +462,10 @@
raise InvalidJsonError()
# If an API Endpoint is provided on client options, use that as the base
URL
- base = urljoin(service['rootUrl'], service["servicePath"])
+ base = urljoin(service["rootUrl"], service["servicePath"])
if client_options:
- if type(client_options) == dict:
- client_options = google.api_core.client_options.from_dict(
- client_options
- )
+ if isinstance(client_options, six.moves.collections_abc.Mapping):
+ client_options =
google.api_core.client_options.from_dict(client_options)
if client_options.api_endpoint:
base = client_options.api_endpoint
@@ -400,6 +501,62 @@
else:
http = build_http()
+ # Obtain client cert and create mTLS http channel if cert exists.
+ client_cert_to_use = None
+ use_client_cert = os.getenv(GOOGLE_API_USE_CLIENT_CERTIFICATE, "false")
+ if not use_client_cert in ("true", "false"):
+ raise MutualTLSChannelError(
+ "Unsupported GOOGLE_API_USE_CLIENT_CERTIFICATE value. Accepted
values: true, false"
+ )
+ if client_options and client_options.client_cert_source:
+ raise MutualTLSChannelError(
+ "ClientOptions.client_cert_source is not supported, please use
ClientOptions.client_encrypted_cert_source."
+ )
+ if use_client_cert == "true":
+ if (
+ client_options
+ and hasattr(client_options, "client_encrypted_cert_source")
+ and client_options.client_encrypted_cert_source
+ ):
+ client_cert_to_use =
client_options.client_encrypted_cert_source
+ elif adc_cert_path and adc_key_path and
mtls.has_default_client_cert_source():
+ client_cert_to_use = mtls.default_client_encrypted_cert_source(
+ adc_cert_path, adc_key_path
+ )
+ if client_cert_to_use:
+ cert_path, key_path, passphrase = client_cert_to_use()
+
+ # The http object we built could be
google_auth_httplib2.AuthorizedHttp
+ # or httplib2.Http. In the first case we need to extract the
wrapped
+ # httplib2.Http object from google_auth_httplib2.AuthorizedHttp.
+ http_channel = (
+ http.http
+ if google_auth_httplib2
+ and isinstance(http, google_auth_httplib2.AuthorizedHttp)
+ else http
+ )
+ http_channel.add_certificate(key_path, cert_path, "", passphrase)
+
+ # If user doesn't provide api endpoint via client options, decide which
+ # api endpoint to use.
+ if "mtlsRootUrl" in service and (
+ not client_options or not client_options.api_endpoint
+ ):
+ mtls_endpoint = urljoin(service["mtlsRootUrl"],
service["servicePath"])
+ use_mtls_endpoint = os.getenv(GOOGLE_API_USE_MTLS_ENDPOINT, "auto")
+
+ if not use_mtls_endpoint in ("never", "auto", "always"):
+ raise MutualTLSChannelError(
+ "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted
values: never, auto, always"
+ )
+
+ # Switch to mTLS endpoint, if environment variable is "always", or
+ # environment varibable is "auto" and client cert exists.
+ if use_mtls_endpoint == "always" or (
+ use_mtls_endpoint == "auto" and client_cert_to_use
+ ):
+ base = mtls_endpoint
+
if model is None:
features = service.get("features", [])
model = JsonModel("dataWrapper" in features)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/googleapiclient/http.py
new/google-api-python-client-1.11.0/googleapiclient/http.py
--- old/google-api-python-client-1.8.4/googleapiclient/http.py 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/googleapiclient/http.py 2020-08-27
23:33:51.000000000 +0200
@@ -1118,6 +1118,10 @@
resumable=d["resumable"],
)
+ @staticmethod
+ def null_postproc(resp, contents):
+ return resp, contents
+
class BatchHttpRequest(object):
"""Batches multiple HttpRequest objects into a single HTTP request.
@@ -1168,7 +1172,7 @@
batch_uri = _LEGACY_BATCH_URI
if batch_uri == _LEGACY_BATCH_URI:
- LOGGER.warn(
+ LOGGER.warning(
"You have constructed a BatchHttpRequest using the legacy
batch "
"endpoint %s. This endpoint will be turned down on August 12,
2020. "
"Please provide the API-specific endpoint or use "
@@ -1416,7 +1420,7 @@
http: httplib2.Http, an http object to be used to make the request with.
order: list, list of request ids in the order they were added to the
batch.
- request: list, list of request objects to send.
+ requests: list, list of request objects to send.
Raises:
httplib2.HttpLib2Error if a transport error has occurred.
@@ -1690,9 +1694,8 @@
if headers is None:
headers = {"status": "200"}
if filename:
- f = open(filename, "rb")
- self.data = f.read()
- f.close()
+ with open(filename, "rb") as f:
+ self.data = f.read()
else:
self.data = None
self.response_headers = headers
@@ -1749,6 +1752,7 @@
"""
self._iterable = iterable
self.follow_redirects = True
+ self.request_sequence = list()
def request(
self,
@@ -1759,6 +1763,8 @@
redirections=1,
connection_type=None,
):
+ # Remember the request so after the fact this mock can be examined
+ self.request_sequence.append((uri, method, body, headers))
resp, content = self._iterable.pop(0)
content = six.ensure_binary(content)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/setup.cfg
new/google-api-python-client-1.11.0/setup.cfg
--- old/google-api-python-client-1.8.4/setup.cfg 2020-05-26
22:19:38.414078000 +0200
+++ new/google-api-python-client-1.11.0/setup.cfg 2020-08-27
23:35:31.385575800 +0200
@@ -1,3 +1,6 @@
+[bdist_wheel]
+universal = 1
+
[egg_info]
tag_build =
tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/setup.py
new/google-api-python-client-1.11.0/setup.py
--- old/google-api-python-client-1.8.4/setup.py 2020-05-26 22:17:53.000000000
+0200
+++ new/google-api-python-client-1.11.0/setup.py 2020-08-27
23:33:51.000000000 +0200
@@ -39,9 +39,9 @@
# currently upgrade their httplib2 version.
# Please see
https://github.com/googleapis/google-api-python-client/pull/841
"httplib2>=0.9.2,<1dev",
- "google-auth>=1.4.1",
+ "google-auth>=1.16.0",
"google-auth-httplib2>=0.0.3",
- "google-api-core>=1.13.0,<2dev",
+ "google-api-core>=1.18.0,<2dev",
"six>=1.6.1,<2dev",
"uritemplate>=3.0.0,<4dev",
]
@@ -52,7 +52,7 @@
with io.open(readme_filename, encoding="utf-8") as readme_file:
readme = readme_file.read()
-version = "1.8.4"
+version = "1.11.0"
setup(
name="google-api-python-client",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/data/500.json
new/google-api-python-client-1.11.0/tests/data/500.json
--- old/google-api-python-client-1.8.4/tests/data/500.json 1970-01-01
01:00:00.000000000 +0100
+++ new/google-api-python-client-1.11.0/tests/data/500.json 2020-08-27
23:33:51.000000000 +0200
@@ -0,0 +1,13 @@
+{
+ "error": {
+ "errors": [
+ {
+ "domain": "global",
+ "reason": "internalError",
+ "message": "We encountered an internal error. Please try again using
truncated exponential backoff."
+ }
+ ],
+ "code": 500,
+ "message": "Internal Server Error"
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/data/503.json
new/google-api-python-client-1.11.0/tests/data/503.json
--- old/google-api-python-client-1.8.4/tests/data/503.json 1970-01-01
01:00:00.000000000 +0100
+++ new/google-api-python-client-1.11.0/tests/data/503.json 2020-08-27
23:33:51.000000000 +0200
@@ -0,0 +1,13 @@
+{
+ "error": {
+ "errors": [
+ {
+ "domain": "global",
+ "reason": "backendError",
+ "message": "We encountered an internal error. Please try again using
truncated exponential backoff."
+ }
+ ],
+ "code": 503,
+ "message": "Service Unavailable"
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/tests/data/bigquery.json
new/google-api-python-client-1.11.0/tests/data/bigquery.json
--- old/google-api-python-client-1.8.4/tests/data/bigquery.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/bigquery.json
2020-08-27 23:33:51.000000000 +0200
@@ -19,6 +19,7 @@
"baseUrl": "https://www.googleapis.com/bigquery/v2/",
"basePath": "/bigquery/v2/",
"rootUrl": "https://www.googleapis.com/",
+ "mtlsRootUrl": "https://www.mtls.googleapis.com/",
"servicePath": "bigquery/v2/",
"batchPath": "batch",
"parameters": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/data/drive.json
new/google-api-python-client-1.11.0/tests/data/drive.json
--- old/google-api-python-client-1.8.4/tests/data/drive.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/drive.json 2020-08-27
23:33:51.000000000 +0200
@@ -19,6 +19,7 @@
"baseUrl": "https://www.googleapis.com/drive/v3/",
"basePath": "/drive/v3/",
"rootUrl": "https://www.googleapis.com/",
+ "mtlsRootUrl": "https://www.mtls.googleapis.com/",
"servicePath": "drive/v3/",
"batchPath": "batch",
"parameters": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/tests/data/latitude.json
new/google-api-python-client-1.11.0/tests/data/latitude.json
--- old/google-api-python-client-1.8.4/tests/data/latitude.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/latitude.json
2020-08-27 23:33:51.000000000 +0200
@@ -14,6 +14,7 @@
"protocol": "rest",
"basePath": "/latitude/v1/",
"rootUrl": "https://www.googleapis.com/",
+ "mtlsRootUrl": "https://www.mtls.googleapis.com/",
"servicePath": "latitude/v1/",
"auth": {
"oauth2": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/tests/data/logging.json
new/google-api-python-client-1.11.0/tests/data/logging.json
--- old/google-api-python-client-1.8.4/tests/data/logging.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/logging.json 2020-08-27
23:33:51.000000000 +0200
@@ -2086,5 +2086,6 @@
"ownerName": "Google",
"version": "v2",
"rootUrl": "https://logging.googleapis.com/",
+ "mtlsRootUrl": "https://logging.mtls.googleapis.com/",
"kind": "discovery#restDescription"
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/data/plus.json
new/google-api-python-client-1.11.0/tests/data/plus.json
--- old/google-api-python-client-1.8.4/tests/data/plus.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/plus.json 2020-08-27
23:33:51.000000000 +0200
@@ -16,6 +16,7 @@
"protocol": "rest",
"basePath": "/plus/v1/",
"rootUrl": "https://www.googleapis.com/",
+ "mtlsRootUrl": "https://www.mtls.googleapis.com/",
"servicePath": "plus/v1/",
"parameters": {
"alt": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/data/tasks.json
new/google-api-python-client-1.11.0/tests/data/tasks.json
--- old/google-api-python-client-1.8.4/tests/data/tasks.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/tasks.json 2020-08-27
23:33:51.000000000 +0200
@@ -16,6 +16,7 @@
"protocol": "rest",
"basePath": "/tasks/v1/",
"rootUrl": "https://www.googleapis.com/",
+ "mtlsRootUrl": "https://www.mtls.googleapis.com/",
"servicePath": "tasks/v1/",
"parameters": {
"alt": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/data/zoo.json
new/google-api-python-client-1.11.0/tests/data/zoo.json
--- old/google-api-python-client-1.8.4/tests/data/zoo.json 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/data/zoo.json 2020-08-27
23:33:51.000000000 +0200
@@ -6,6 +6,7 @@
"basePath": "/zoo/",
"batchPath": "batchZoo",
"rootUrl": "https://www.googleapis.com/",
+ "mtlsRootUrl": "https://www.mtls.googleapis.com/",
"servicePath": "zoo/v1/",
"rpcPath": "/rpc",
"parameters": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/google-api-python-client-1.8.4/tests/test_discovery.py
new/google-api-python-client-1.11.0/tests/test_discovery.py
--- old/google-api-python-client-1.8.4/tests/test_discovery.py 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/test_discovery.py 2020-08-27
23:33:51.000000000 +0200
@@ -38,10 +38,14 @@
import re
import sys
import unittest2 as unittest
+from collections import defaultdict
+from parameterized import parameterized
import mock
import google.auth.credentials
+from google.auth.transport import mtls
+from google.auth.exceptions import MutualTLSChannelError
import google_auth_httplib2
from googleapiclient.discovery import _fix_up_media_upload
from googleapiclient.discovery import _fix_up_method_description
@@ -56,6 +60,8 @@
from googleapiclient.discovery import ResourceMethodParameters
from googleapiclient.discovery import STACK_QUERY_PARAMETERS
from googleapiclient.discovery import STACK_QUERY_PARAMETER_DEFAULT_VALUE
+from googleapiclient.discovery import V1_DISCOVERY_URI
+from googleapiclient.discovery import V2_DISCOVERY_URI
from googleapiclient.discovery_cache import DISCOVERY_DOC_MAX_AGE
from googleapiclient.discovery_cache.base import Cache
from googleapiclient.errors import HttpError
@@ -104,10 +110,35 @@
testcase.assertEqual(expected_query[name], actual_query[name])
+def assert_discovery_uri(testcase, actual, service_name, version, discovery):
+ """Assert that discovery URI used was the one that was expected
+ for a given service and version."""
+ params = {"api": service_name, "apiVersion": version}
+ expanded_requested_uri = uritemplate.expand(discovery, params)
+ assertUrisEqual(testcase, expanded_requested_uri, actual)
+
+
+def validate_discovery_requests(testcase, http_mock, service_name,
+ version, discovery):
+ """Validates that there have > 0 calls to Http Discovery
+ and that LAST discovery URI used was the one that was expected
+ for a given service and version."""
+ testcase.assertTrue(len(http_mock.request_sequence) > 0)
+ if len(http_mock.request_sequence) > 0:
+ actual_uri = http_mock.request_sequence[-1][0]
+ assert_discovery_uri(testcase,
+ actual_uri, service_name, version, discovery)
+
+
def datafile(filename):
return os.path.join(DATA_DIR, filename)
+def read_datafile(filename, mode='r'):
+ with open(datafile(filename), mode=mode) as f:
+ return f.read()
+
+
class SetupHttplib2(unittest.TestCase):
def test_retries(self):
# Merely loading googleapiclient.discovery should set the RETRIES to 1.
@@ -116,8 +147,7 @@
class Utilities(unittest.TestCase):
def setUp(self):
- with open(datafile("zoo.json"), "r") as fh:
- self.zoo_root_desc = json.loads(fh.read())
+ self.zoo_root_desc = json.loads(read_datafile("zoo.json", "r"))
self.zoo_get_method_desc = self.zoo_root_desc["methods"]["query"]
self.zoo_animals_resource = self.zoo_root_desc["resources"]["animals"]
self.zoo_insert_method_desc =
self.zoo_animals_resource["methods"]["insert"]
@@ -224,7 +254,11 @@
final_max_size,
final_media_path_url,
):
- fake_root_desc = {"rootUrl": "http://root/", "servicePath": "fake/"}
+ fake_root_desc = {
+ "rootUrl": "http://root/",
+ "servicePath": "fake/",
+ "mtlsRootUrl": "http://root/",
+ }
fake_path_url = "fake-path/"
accept, max_size, media_path_url = _fix_up_media_upload(
@@ -422,8 +456,8 @@
def test_unknown_api_name_or_version(self):
http = HttpMockSequence(
[
- ({"status": "404"}, open(datafile("zoo.json"), "rb").read()),
- ({"status": "404"}, open(datafile("zoo.json"), "rb").read()),
+ ({"status": "404"}, read_datafile("zoo.json", "rb")),
+ ({"status": "404"}, read_datafile("zoo.json", "rb")),
]
)
with self.assertRaises(UnknownApiNameOrVersion):
@@ -439,28 +473,28 @@
MOCK_CREDENTIALS = mock.Mock(spec=google.auth.credentials.Credentials)
def test_can_build_from_local_document(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
plus = build_from_document(
discovery,
base="https://www.googleapis.com/",
credentials=self.MOCK_CREDENTIALS,
)
- self.assertTrue(plus is not None)
+ self.assertIsNotNone(plus)
self.assertTrue(hasattr(plus, "activities"))
def test_can_build_from_local_deserialized_document(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
discovery = json.loads(discovery)
plus = build_from_document(
discovery,
base="https://www.googleapis.com/",
credentials=self.MOCK_CREDENTIALS,
)
- self.assertTrue(plus is not None)
+ self.assertIsNotNone(plus)
self.assertTrue(hasattr(plus, "activities"))
def test_building_with_base_remembers_base(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
base = "https://www.example.com/"
plus = build_from_document(
@@ -469,7 +503,7 @@
self.assertEqual("https://www.googleapis.com/plus/v1/", plus._baseUrl)
def test_building_with_optional_http_with_authorization(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
plus = build_from_document(
discovery,
base="https://www.googleapis.com/",
@@ -483,7 +517,7 @@
self.assertGreater(plus._http.http.timeout, 0)
def test_building_with_optional_http_with_no_authorization(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
# Cleanup auth field, so we would use plain http client
discovery = json.loads(discovery)
discovery["auth"] = {}
@@ -499,14 +533,14 @@
def test_building_with_explicit_http(self):
http = HttpMock()
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
plus = build_from_document(
discovery, base="https://www.googleapis.com/", http=http
)
self.assertEqual(plus._http, http)
def test_building_with_developer_key_skips_adc(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
plus = build_from_document(
discovery, base="https://www.googleapis.com/", developerKey="123"
)
@@ -516,31 +550,262 @@
self.assertNotIsInstance(plus._http,
google_auth_httplib2.AuthorizedHttp)
def test_api_endpoint_override_from_client_options(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
api_endpoint = "https://foo.googleapis.com/"
options = google.api_core.client_options.ClientOptions(
api_endpoint=api_endpoint
)
plus = build_from_document(
- discovery,
- client_options=options,
- credentials=self.MOCK_CREDENTIALS
+ discovery, client_options=options,
credentials=self.MOCK_CREDENTIALS
+ )
+
+ self.assertEqual(plus._baseUrl, api_endpoint)
+
+ def test_api_endpoint_override_from_client_options_mapping_object(self):
+
+ discovery = read_datafile("plus.json")
+ api_endpoint = "https://foo.googleapis.com/"
+ mapping_object = defaultdict(str)
+ mapping_object['api_endpoint'] = api_endpoint
+ plus = build_from_document(
+ discovery, client_options=mapping_object
)
self.assertEqual(plus._baseUrl, api_endpoint)
def test_api_endpoint_override_from_client_options_dict(self):
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
api_endpoint = "https://foo.googleapis.com/"
plus = build_from_document(
- discovery,
+ discovery,
client_options={"api_endpoint": api_endpoint},
- credentials=self.MOCK_CREDENTIALS
+ credentials=self.MOCK_CREDENTIALS,
)
self.assertEqual(plus._baseUrl, api_endpoint)
+REGULAR_ENDPOINT = "https://www.googleapis.com/plus/v1/"
+MTLS_ENDPOINT = "https://www.mtls.googleapis.com/plus/v1/"
+
+
+class DiscoveryFromDocumentMutualTLS(unittest.TestCase):
+ MOCK_CREDENTIALS = mock.Mock(spec=google.auth.credentials.Credentials)
+ ADC_CERT_PATH = "adc_cert_path"
+ ADC_KEY_PATH = "adc_key_path"
+ ADC_PASSPHRASE = "adc_passphrase"
+
+ def check_http_client_cert(self, resource, has_client_cert="false"):
+ if isinstance(resource._http, google_auth_httplib2.AuthorizedHttp):
+ certs = list(resource._http.http.certificates.iter(""))
+ else:
+ certs = list(resource._http.certificates.iter(""))
+ if has_client_cert == "true":
+ self.assertEqual(len(certs), 1)
+ self.assertEqual(
+ certs[0], (self.ADC_KEY_PATH, self.ADC_CERT_PATH,
self.ADC_PASSPHRASE)
+ )
+ else:
+ self.assertEqual(len(certs), 0)
+
+ def client_encrypted_cert_source(self):
+ return self.ADC_CERT_PATH, self.ADC_KEY_PATH, self.ADC_PASSPHRASE
+
+ @parameterized.expand(
+ [
+ ("never", "true"),
+ ("auto", "true"),
+ ("always", "true"),
+ ("never", "false"),
+ ("auto", "false"),
+ ("always", "false"),
+ ]
+ )
+ def test_mtls_not_trigger_if_http_provided(self, use_mtls_env,
use_client_cert):
+ discovery = read_datafile("plus.json")
+
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_env}
+ ):
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_CLIENT_CERTIFICATE":
use_client_cert}
+ ):
+ plus = build_from_document(discovery, http=httplib2.Http())
+ self.assertIsNotNone(plus)
+ self.assertEqual(plus._baseUrl, REGULAR_ENDPOINT)
+ self.check_http_client_cert(plus, has_client_cert="false")
+
+ @parameterized.expand(
+ [
+ ("never", "true"),
+ ("auto", "true"),
+ ("always", "true"),
+ ("never", "false"),
+ ("auto", "false"),
+ ("always", "false"),
+ ]
+ )
+ def test_exception_with_client_cert_source(self, use_mtls_env,
use_client_cert):
+ discovery = read_datafile("plus.json")
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_env}
+ ):
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_CLIENT_CERTIFICATE":
use_client_cert}
+ ):
+ with self.assertRaises(MutualTLSChannelError):
+ build_from_document(
+ discovery,
+ credentials=self.MOCK_CREDENTIALS,
+ client_options={"client_cert_source": mock.Mock()},
+ )
+
+ @parameterized.expand(
+ [
+ ("never", "true", REGULAR_ENDPOINT),
+ ("auto", "true", MTLS_ENDPOINT),
+ ("always", "true", MTLS_ENDPOINT),
+ ("never", "false", REGULAR_ENDPOINT),
+ ("auto", "false", REGULAR_ENDPOINT),
+ ("always", "false", MTLS_ENDPOINT),
+ ]
+ )
+ def test_mtls_with_provided_client_cert(
+ self, use_mtls_env, use_client_cert, base_url
+ ):
+ discovery = read_datafile("plus.json")
+
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_env}
+ ):
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_CLIENT_CERTIFICATE":
use_client_cert}
+ ):
+ plus = build_from_document(
+ discovery,
+ credentials=self.MOCK_CREDENTIALS,
+ client_options={
+ "client_encrypted_cert_source":
self.client_encrypted_cert_source
+ },
+ )
+ self.assertIsNotNone(plus)
+ self.check_http_client_cert(plus,
has_client_cert=use_client_cert)
+ self.assertEqual(plus._baseUrl, base_url)
+
+ @parameterized.expand(
+ [
+ ("never", "true"),
+ ("auto", "true"),
+ ("always", "true"),
+ ("never", "false"),
+ ("auto", "false"),
+ ("always", "false"),
+ ]
+ )
+ def test_endpoint_not_switch(self, use_mtls_env, use_client_cert):
+ # Test endpoint is not switched if user provided api endpoint
+ discovery = read_datafile("plus.json")
+
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_env}
+ ):
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_CLIENT_CERTIFICATE":
use_client_cert}
+ ):
+ plus = build_from_document(
+ discovery,
+ credentials=self.MOCK_CREDENTIALS,
+ client_options={
+ "api_endpoint": "https://foo.googleapis.com",
+ "client_encrypted_cert_source":
self.client_encrypted_cert_source,
+ },
+ )
+ self.assertIsNotNone(plus)
+ self.check_http_client_cert(plus,
has_client_cert=use_client_cert)
+ self.assertEqual(plus._baseUrl, "https://foo.googleapis.com")
+
+ @parameterized.expand(
+ [
+ ("never", "true", REGULAR_ENDPOINT),
+ ("auto", "true", MTLS_ENDPOINT),
+ ("always", "true", MTLS_ENDPOINT),
+ ("never", "false", REGULAR_ENDPOINT),
+ ("auto", "false", REGULAR_ENDPOINT),
+ ("always", "false", MTLS_ENDPOINT),
+ ]
+ )
+ @mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
autospec=True
+ )
+ @mock.patch(
+ "google.auth.transport.mtls.default_client_encrypted_cert_source",
autospec=True
+ )
+ def test_mtls_with_default_client_cert(
+ self,
+ use_mtls_env,
+ use_client_cert,
+ base_url,
+ default_client_encrypted_cert_source,
+ has_default_client_cert_source,
+ ):
+ has_default_client_cert_source.return_value = True
+ default_client_encrypted_cert_source.return_value = (
+ self.client_encrypted_cert_source
+ )
+ discovery = read_datafile("plus.json")
+
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_env}
+ ):
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_CLIENT_CERTIFICATE":
use_client_cert}
+ ):
+ plus = build_from_document(
+ discovery,
+ credentials=self.MOCK_CREDENTIALS,
+ adc_cert_path=self.ADC_CERT_PATH,
+ adc_key_path=self.ADC_KEY_PATH,
+ )
+ self.assertIsNotNone(plus)
+ self.check_http_client_cert(plus,
has_client_cert=use_client_cert)
+ self.assertEqual(plus._baseUrl, base_url)
+
+ @parameterized.expand(
+ [
+ ("never", "true", REGULAR_ENDPOINT),
+ ("auto", "true", REGULAR_ENDPOINT),
+ ("always", "true", MTLS_ENDPOINT),
+ ("never", "false", REGULAR_ENDPOINT),
+ ("auto", "false", REGULAR_ENDPOINT),
+ ("always", "false", MTLS_ENDPOINT),
+ ]
+ )
+ @mock.patch(
+ "google.auth.transport.mtls.has_default_client_cert_source",
autospec=True
+ )
+ def test_mtls_with_no_client_cert(
+ self, use_mtls_env, use_client_cert, base_url,
has_default_client_cert_source
+ ):
+ has_default_client_cert_source.return_value = False
+ discovery = read_datafile("plus.json")
+
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": use_mtls_env}
+ ):
+ with mock.patch.dict(
+ "os.environ", {"GOOGLE_API_USE_CLIENT_CERTIFICATE":
use_client_cert}
+ ):
+ plus = build_from_document(
+ discovery,
+ credentials=self.MOCK_CREDENTIALS,
+ adc_cert_path=self.ADC_CERT_PATH,
+ adc_key_path=self.ADC_KEY_PATH,
+ )
+ self.assertIsNotNone(plus)
+ self.check_http_client_cert(plus, has_client_cert="false")
+ self.assertEqual(plus._baseUrl, base_url)
+
+
class DiscoveryFromHttp(unittest.TestCase):
def setUp(self):
self.old_environ = os.environ.copy()
@@ -554,7 +819,7 @@
os.environ["REMOTE_ADDR"] = "10.0.0.1"
try:
http = HttpMockSequence(
- [({"status": "400"}, open(datafile("zoo.json"), "rb").read())]
+ [({"status": "400"}, read_datafile("zoo.json", "rb"))]
)
zoo = build(
"zoo",
@@ -572,7 +837,7 @@
# out of the raised exception.
try:
http = HttpMockSequence(
- [({"status": "400"}, open(datafile("zoo.json"), "rb").read())]
+ [({"status": "400"}, read_datafile("zoo.json", "rb"))]
)
zoo = build(
"zoo",
@@ -590,7 +855,7 @@
# out of the raised exception.
try:
http = HttpMockSequence(
- [({"status": "400"}, open(datafile("zoo.json"), "rb").read())]
+ [({"status": "400"}, read_datafile("zoo.json", "rb"))]
)
zoo = build(
"zoo",
@@ -607,7 +872,7 @@
http = HttpMockSequence(
[
({"status": "404"}, "Not found"),
- ({"status": "200"}, open(datafile("zoo.json"), "rb").read()),
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
]
)
zoo = build("zoo", "v1", http=http, cache_discovery=False)
@@ -617,7 +882,7 @@
http = HttpMockSequence(
[
({"status": "404"}, "Not found"),
- ({"status": "200"}, open(datafile("zoo.json"), "rb").read()),
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
]
)
api_endpoint = "https://foo.googleapis.com/"
@@ -633,7 +898,7 @@
http = HttpMockSequence(
[
({"status": "404"}, "Not found"),
- ({"status": "200"}, open(datafile("zoo.json"), "rb").read()),
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
]
)
api_endpoint = "https://foo.googleapis.com/"
@@ -646,9 +911,103 @@
)
self.assertEqual(zoo._baseUrl, api_endpoint)
+ def test_discovery_with_empty_version_uses_v2(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
+ ]
+ )
+ build("zoo", version=None, http=http, cache_discovery=False)
+ validate_discovery_requests(self, http, "zoo", None, V2_DISCOVERY_URI)
-class DiscoveryFromAppEngineCache(unittest.TestCase):
+ def test_discovery_with_empty_version_preserves_custom_uri(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
+ ]
+ )
+ custom_discovery_uri = "https://foo.bar/$discovery"
+ build(
+ "zoo", version=None, http=http,
+ cache_discovery=False, discoveryServiceUrl=custom_discovery_uri)
+ validate_discovery_requests(
+ self, http, "zoo", None, custom_discovery_uri)
+
+ def test_discovery_with_valid_version_uses_v1(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
+ ]
+ )
+ build("zoo", version="v123", http=http, cache_discovery=False)
+ validate_discovery_requests(self, http, "zoo", "v123",
V1_DISCOVERY_URI)
+
+
+class DiscoveryRetryFromHttp(unittest.TestCase):
+ def test_repeated_500_retries_and_fails(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "500"}, read_datafile("500.json", "rb")),
+ ({"status": "503"}, read_datafile("503.json", "rb")),
+ ]
+ )
+ with self.assertRaises(HttpError):
+ with mock.patch("time.sleep") as mocked_sleep:
+ build("zoo", "v1", http=http, cache_discovery=False)
+
+ mocked_sleep.assert_called_once()
+ # We also want to verify that we stayed with v1 discovery
+ validate_discovery_requests(self, http, "zoo", "v1", V1_DISCOVERY_URI)
+
+ def test_v2_repeated_500_retries_and_fails(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "404"}, "Not found"), # last v1 discovery call
+ ({"status": "500"}, read_datafile("500.json", "rb")),
+ ({"status": "503"}, read_datafile("503.json", "rb")),
+ ]
+ )
+ with self.assertRaises(HttpError):
+ with mock.patch("time.sleep") as mocked_sleep:
+ build("zoo", "v1", http=http, cache_discovery=False)
+
+ mocked_sleep.assert_called_once()
+ # We also want to verify that we switched to v2 discovery
+ validate_discovery_requests(self, http, "zoo", "v1", V2_DISCOVERY_URI)
+
+ def test_single_500_retries_and_succeeds(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "500"}, read_datafile("500.json", "rb")),
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
+ ]
+ )
+ with mock.patch("time.sleep") as mocked_sleep:
+ zoo = build("zoo", "v1", http=http, cache_discovery=False)
+ self.assertTrue(hasattr(zoo, "animals"))
+ mocked_sleep.assert_called_once()
+ # We also want to verify that we stayed with v1 discovery
+ validate_discovery_requests(self, http, "zoo", "v1", V1_DISCOVERY_URI)
+
+ def test_single_500_then_404_retries_and_succeeds(self):
+ http = HttpMockSequence(
+ [
+ ({"status": "500"}, read_datafile("500.json", "rb")),
+ ({"status": "404"}, "Not found"), # last v1 discovery call
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
+ ]
+ )
+ with mock.patch("time.sleep") as mocked_sleep:
+ zoo = build("zoo", "v1", http=http, cache_discovery=False)
+
+ self.assertTrue(hasattr(zoo, "animals"))
+ mocked_sleep.assert_called_once()
+ # We also want to verify that we switched to v2 discovery
+ validate_discovery_requests(self, http, "zoo", "v1", V2_DISCOVERY_URI)
+
+
+class DiscoveryFromAppEngineCache(unittest.TestCase):
def setUp(self):
self.old_environ = os.environ.copy()
os.environ["APPENGINE_RUNTIME"] = "python27"
@@ -685,8 +1044,7 @@
)
# memcache.set is called once
- with open(datafile("plus.json")) as f:
- content = f.read()
+ content = read_datafile("plus.json")
self.mocked_api.memcache.set.assert_called_once_with(
url, content, time=DISCOVERY_DOC_MAX_AGE, namespace=namespace
)
@@ -743,8 +1101,7 @@
cache.get.assert_called_once_with(url)
# cache.set is called once
- with open(datafile("plus.json")) as f:
- content = f.read()
+ content = read_datafile("plus.json")
cache.set.assert_called_once_with(url, content)
# Make sure there is a cache entry for the plus v1 discovery doc.
@@ -905,7 +1262,7 @@
def test_tunnel_patch(self):
http = HttpMockSequence(
[
- ({"status": "200"}, open(datafile("zoo.json"), "rb").read()),
+ ({"status": "200"}, read_datafile("zoo.json", "rb")),
({"status": "200"}, "echo_request_headers_as_json"),
]
)
@@ -925,13 +1282,13 @@
credentials = mock.Mock(spec=GoogleCredentials)
credentials.create_scoped_required.return_value = False
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
service = build_from_document(discovery, credentials=credentials)
self.assertEqual(service._http, credentials.authorize.return_value)
def test_google_auth_credentials(self):
credentials = mock.Mock(spec=google.auth.credentials.Credentials)
- discovery = open(datafile("plus.json")).read()
+ discovery = read_datafile("plus.json")
service = build_from_document(discovery, credentials=credentials)
self.assertIsInstance(service._http,
google_auth_httplib2.AuthorizedHttp)
@@ -939,7 +1296,7 @@
def test_no_scopes_no_credentials(self):
# Zoo doesn't have scopes
- discovery = open(datafile("zoo.json")).read()
+ discovery = read_datafile("zoo.json")
service = build_from_document(discovery)
# Should be an ordinary httplib2.Http instance and not AuthorizedHttp.
self.assertIsInstance(service._http, httplib2.Http)
@@ -1069,8 +1426,7 @@
request = zoo.animals().insert(media_body=datafile("small.png"),
body={})
self.assertTrue(request.headers["content-type"].startswith("multipart/related"))
- with open(datafile("small.png"), "rb") as f:
- contents = f.read()
+ contents = read_datafile("small.png", "rb")
boundary = re.match(b"--=+([^=]+)", request.body).group(1)
self.assertEqual(
request.body.rstrip(b"\n"), # Python 2.6 does not add a trailing
\n
@@ -1116,7 +1472,7 @@
self.assertEqual("image/png", request.resumable.mimetype())
- self.assertNotEquals(request.body, None)
+ self.assertNotEqual(request.body, None)
self.assertEqual(request.resumable_uri, None)
http = HttpMockSequence(
@@ -1580,8 +1936,7 @@
# instances upon un-pickling
def _dummy_zoo_request(self):
- with open(os.path.join(DATA_DIR, "zoo.json"), "rU") as fh:
- zoo_contents = fh.read()
+ zoo_contents = read_datafile("zoo.json")
zoo_uri = uritemplate.expand(DISCOVERY_URI, {"api": "zoo",
"apiVersion": "v1"})
if "REMOTE_ADDR" in os.environ:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/google-api-python-client-1.8.4/tests/test_http.py
new/google-api-python-client-1.11.0/tests/test_http.py
--- old/google-api-python-client-1.8.4/tests/test_http.py 2020-05-26
22:17:53.000000000 +0200
+++ new/google-api-python-client-1.11.0/tests/test_http.py 2020-08-27
23:33:51.000000000 +0200
@@ -1097,6 +1097,11 @@
request.execute()
request._sleep.assert_not_called()
+ def test_null_postproc(self):
+ resp, content = HttpRequest.null_postproc("foo", "bar")
+ self.assertEqual(resp, "foo")
+ self.assertEqual(content, "bar")
+
class TestBatch(unittest.TestCase):
def setUp(self):
++++++ python-google-api-python-client-no-unittest2.patch ++++++
--- /var/tmp/diff_new_pack.ucJiIH/_old 2020-10-15 13:49:24.345274408 +0200
+++ /var/tmp/diff_new_pack.ucJiIH/_new 2020-10-15 13:49:24.345274408 +0200
@@ -1,8 +1,7 @@
-Index: google-api-python-client-1.8.4/tests/test__auth.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test__auth.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test__auth.py 2020-06-01
15:48:23.340280191 +0200
-@@ -18,7 +18,7 @@ import google.auth.credentials
+diff -Nru google-api-python-client-1.11.0.orig/tests/test__auth.py
google-api-python-client-1.11.0/tests/test__auth.py
+--- google-api-python-client-1.11.0.orig/tests/test__auth.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test__auth.py 2020-09-10
15:54:13.243410474 +0200
+@@ -18,7 +18,7 @@
import google_auth_httplib2
import httplib2
import oauth2client.client
@@ -11,11 +10,10 @@
from googleapiclient import _auth
-Index: google-api-python-client-1.8.4/tests/test_channel.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_channel.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_channel.py 2020-06-01
15:48:45.200411976 +0200
-@@ -3,7 +3,7 @@ from __future__ import absolute_import
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_channel.py
google-api-python-client-1.11.0/tests/test_channel.py
+--- google-api-python-client-1.11.0.orig/tests/test_channel.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_channel.py 2020-09-10
15:54:13.243410474 +0200
+@@ -3,7 +3,7 @@
__author__ = "[email protected] (Joe Gregorio)"
@@ -24,23 +22,9 @@
import datetime
from googleapiclient import channel
-Index: google-api-python-client-1.8.4/tests/test_discovery.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_discovery.py
2020-05-26 22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_discovery.py 2020-06-01
15:49:06.480540264 +0200
-@@ -37,7 +37,7 @@ import os
- import pickle
- import re
- import sys
--import unittest2 as unittest
-+import unittest
-
- import mock
-
-Index: google-api-python-client-1.8.4/tests/test_discovery_cache.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_discovery_cache.py
2020-05-26 22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_discovery_cache.py
2020-06-01 15:49:21.664631801 +0200
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_discovery_cache.py
google-api-python-client-1.11.0/tests/test_discovery_cache.py
+--- google-api-python-client-1.11.0.orig/tests/test_discovery_cache.py
2020-08-27 23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_discovery_cache.py
2020-09-10 15:54:13.243410474 +0200
@@ -18,7 +18,7 @@
"""Discovery document cache tests."""
@@ -50,11 +34,22 @@
import mock
-Index: google-api-python-client-1.8.4/tests/test_errors.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_errors.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_errors.py 2020-06-01
15:49:32.728698502 +0200
-@@ -21,7 +21,7 @@ from __future__ import absolute_import
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_discovery.py
google-api-python-client-1.11.0/tests/test_discovery.py
+--- google-api-python-client-1.11.0.orig/tests/test_discovery.py
2020-08-27 23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_discovery.py 2020-09-10
15:54:40.883760261 +0200
+@@ -37,7 +37,7 @@
+ import pickle
+ import re
+ import sys
+-import unittest2 as unittest
++import unittest
+ from collections import defaultdict
+
+ from parameterized import parameterized
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_errors.py
google-api-python-client-1.11.0/tests/test_errors.py
+--- google-api-python-client-1.11.0.orig/tests/test_errors.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_errors.py 2020-09-10
15:54:13.247410524 +0200
+@@ -21,7 +21,7 @@
__author__ = "[email protected] (Ali Afshar)"
@@ -63,11 +58,10 @@
import httplib2
-Index: google-api-python-client-1.8.4/tests/test_http.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_http.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_http.py 2020-06-01
15:49:53.456823460 +0200
-@@ -35,7 +35,7 @@ import io
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_http.py
google-api-python-client-1.11.0/tests/test_http.py
+--- google-api-python-client-1.11.0.orig/tests/test_http.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_http.py 2020-09-10
15:54:13.247410524 +0200
+@@ -35,7 +35,7 @@
import logging
import mock
import os
@@ -76,11 +70,10 @@
import random
import socket
import ssl
-Index: google-api-python-client-1.8.4/tests/test_json_model.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_json_model.py
2020-05-26 22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_json_model.py 2020-06-01
15:50:08.064911523 +0200
-@@ -28,7 +28,7 @@ import json
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_json_model.py
google-api-python-client-1.11.0/tests/test_json_model.py
+--- google-api-python-client-1.11.0.orig/tests/test_json_model.py
2020-08-27 23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_json_model.py 2020-09-10
15:54:13.247410524 +0200
+@@ -28,7 +28,7 @@
import os
import pkg_resources
import platform
@@ -89,11 +82,10 @@
import httplib2
import googleapiclient.model
-Index: google-api-python-client-1.8.4/tests/test_mocks.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_mocks.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_mocks.py 2020-06-01
15:50:21.572991364 +0200
-@@ -24,7 +24,7 @@ __author__ = "[email protected] (Joe
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_mocks.py
google-api-python-client-1.11.0/tests/test_mocks.py
+--- google-api-python-client-1.11.0.orig/tests/test_mocks.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_mocks.py 2020-09-10
15:54:13.247410524 +0200
+@@ -24,7 +24,7 @@
import httplib2
import os
@@ -102,11 +94,10 @@
from googleapiclient.errors import HttpError
from googleapiclient.errors import UnexpectedBodyError
-Index: google-api-python-client-1.8.4/tests/test_model.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_model.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_model.py 2020-06-01
15:50:35.321072029 +0200
-@@ -23,7 +23,7 @@ from __future__ import absolute_import
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_model.py
google-api-python-client-1.11.0/tests/test_model.py
+--- google-api-python-client-1.11.0.orig/tests/test_model.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_model.py 2020-09-10
15:54:13.247410524 +0200
+@@ -23,7 +23,7 @@
__author__ = "[email protected] (Joe Gregorio)"
@@ -115,11 +106,10 @@
from googleapiclient.model import BaseModel
from googleapiclient.model import makepatch
-Index: google-api-python-client-1.8.4/tests/test_protobuf_model.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_protobuf_model.py
2020-05-26 22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_protobuf_model.py
2020-06-01 15:50:53.605179328 +0200
-@@ -22,7 +22,7 @@ from __future__ import absolute_import
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_protobuf_model.py
google-api-python-client-1.11.0/tests/test_protobuf_model.py
+--- google-api-python-client-1.11.0.orig/tests/test_protobuf_model.py
2020-08-27 23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_protobuf_model.py
2020-09-10 15:54:13.247410524 +0200
+@@ -22,7 +22,7 @@
__author__ = "[email protected] (Matt McDonald)"
@@ -128,11 +118,10 @@
import httplib2
import googleapiclient.model
-Index: google-api-python-client-1.8.4/tests/test_schema.py
-===================================================================
---- google-api-python-client-1.8.4.orig/tests/test_schema.py 2020-05-26
22:17:53.000000000 +0200
-+++ google-api-python-client-1.8.4/tests/test_schema.py 2020-06-01
15:51:08.885268956 +0200
-@@ -19,7 +19,7 @@ __author__ = "[email protected] (Joe
+diff -Nru google-api-python-client-1.11.0.orig/tests/test_schema.py
google-api-python-client-1.11.0/tests/test_schema.py
+--- google-api-python-client-1.11.0.orig/tests/test_schema.py 2020-08-27
23:33:51.000000000 +0200
++++ google-api-python-client-1.11.0/tests/test_schema.py 2020-09-10
15:54:13.247410524 +0200
+@@ -19,7 +19,7 @@
import json
import os