Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-google-cloud-core for 
openSUSE:Factory checked in at 2021-04-14 10:10:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-cloud-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-google-cloud-core.new.2401 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-google-cloud-core"

Wed Apr 14 10:10:55 2021 rev:8 rq:884874 version:1.6.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-google-cloud-core/python-google-cloud-core.changes
        2020-04-21 13:10:49.748831654 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-google-cloud-core.new.2401/python-google-cloud-core.changes
      2021-04-14 10:11:23.241535054 +0200
@@ -1,0 +2,13 @@
+Tue Apr  6 07:45:12 UTC 2021 - Dirk M??ller <dmuel...@suse.com>
+
+- update to 1.6.0:
+  * add mtls support
+  * infer project from explicit service account creds
+  * add support for Python 3.9, drop support for Python 3.5
+  * require six>=1.12.0 and google-api-core>=1.21.
+  * avoid using 'pkg_resources' to determine version
+  * handle query_params tuples in JSONConnection.build_api_url
+  * add quota_project, credentials file, and scopes options
+  * add support for Python 3.8  
+
+-------------------------------------------------------------------

Old:
----
  google-cloud-core-1.3.0.tar.gz

New:
----
  google-cloud-core-1.6.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-google-cloud-core.spec ++++++
--- /var/tmp/diff_new_pack.nwPd1h/_old  2021-04-14 10:11:23.817536026 +0200
+++ /var/tmp/diff_new_pack.nwPd1h/_new  2021-04-14 10:11:23.821536033 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-google-cloud-core
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,21 +19,24 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %bcond_without python2
 Name:           python-google-cloud-core
-Version:        1.3.0
+Version:        1.6.0
 Release:        0
 Summary:        Google Cloud API client core library
 License:        Apache-2.0
 Group:          Development/Languages/Python
-URL:            https://github.com/GoogleCloudPlatform/google-cloud-python
+URL:            https://github.com/googleapis/python-cloud-core
 Source:         
https://files.pythonhosted.org/packages/source/g/google-cloud-core/google-cloud-core-%{version}.tar.gz
-BuildRequires:  %{python_module google-api-core >= 1.16.0}
+BuildRequires:  %{python_module google-api-core >= 1.21.0}
+BuildRequires:  %{python_module google-auth >= 1.24.0}
 BuildRequires:  %{python_module grpcio >= 1.8.2}
 BuildRequires:  %{python_module mock}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-Requires:       python-google-api-core >= 1.16.0
+Requires:       python-google-api-core >= 1.21.0
+Requires:       python-google-auth >= 1.24.0
+Requires:       python-six >= 1.12.0
 Recommends:     python-grpcio >= 1.8.2
 BuildArch:      noarch
 %if %{with python2}

++++++ google-cloud-core-1.3.0.tar.gz -> google-cloud-core-1.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/MANIFEST.in 
new/google-cloud-core-1.6.0/MANIFEST.in
--- old/google-cloud-core-1.3.0/MANIFEST.in     2020-01-31 22:59:39.000000000 
+0100
+++ new/google-cloud-core-1.6.0/MANIFEST.in     2021-02-06 02:19:50.000000000 
+0100
@@ -1,3 +1,25 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 Google LLC
+#
+# 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
+#
+#     https://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.
+
+# Generated by synthtool. DO NOT EDIT!
 include README.rst LICENSE
+recursive-include google *.json *.proto
 recursive-include tests *
-global-exclude *.pyc __pycache__
+global-exclude *.py[co]
+global-exclude __pycache__
+
+# Exclude scripts for samples readmegen
+prune scripts/readme-gen
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/PKG-INFO 
new/google-cloud-core-1.6.0/PKG-INFO
--- old/google-cloud-core-1.3.0/PKG-INFO        2020-01-31 23:02:20.810099000 
+0100
+++ new/google-cloud-core-1.6.0/PKG-INFO        2021-02-06 02:23:12.442483000 
+0100
@@ -1,15 +1,15 @@
 Metadata-Version: 2.1
 Name: google-cloud-core
-Version: 1.3.0
+Version: 1.6.0
 Summary: Google Cloud API client core library
-Home-page: https://github.com/GoogleCloudPlatform/google-cloud-python
+Home-page: https://github.com/googleapis/python-cloud-core
 Author: Google LLC
 Author-email: googleapis-packa...@google.com
 License: Apache 2.0
 Description: Core Helpers for Google Cloud Python Client Library
         ===================================================
         
-        |pypi| |versions| 
+        |pypi| |versions|
         
         This library is not meant to stand-alone. Instead it defines
         common helpers (e.g. base ``Client`` classes) used by all of the
@@ -40,24 +40,25 @@
         
         Supported Python Versions
         -------------------------
-        Python >= 3.5
+        Python >= 3.6
         
         Deprecated Python Versions
         --------------------------
         Python == 2.7. Python 2.7 support will be removed on January 1, 2020.
         
 Platform: Posix; MacOS X; Windows
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: Apache Software License
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
 Classifier: Operating System :: OS Independent
 Classifier: Topic :: Internet
-Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
+Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*
 Provides-Extra: grpc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/README.rst 
new/google-cloud-core-1.6.0/README.rst
--- old/google-cloud-core-1.3.0/README.rst      2020-01-31 22:59:39.000000000 
+0100
+++ new/google-cloud-core-1.6.0/README.rst      2021-02-06 02:19:50.000000000 
+0100
@@ -1,7 +1,7 @@
 Core Helpers for Google Cloud Python Client Library
 ===================================================
 
-|pypi| |versions| 
+|pypi| |versions|
 
 This library is not meant to stand-alone. Instead it defines
 common helpers (e.g. base ``Client`` classes) used by all of the
@@ -32,7 +32,7 @@
 
 Supported Python Versions
 -------------------------
-Python >= 3.5
+Python >= 3.6
 
 Deprecated Python Versions
 --------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/google/cloud/_http.py 
new/google-cloud-core-1.6.0/google/cloud/_http.py
--- old/google-cloud-core-1.3.0/google/cloud/_http.py   2020-01-31 
22:59:39.000000000 +0100
+++ new/google-cloud-core-1.6.0/google/cloud/_http.py   2021-02-06 
02:19:50.000000000 +0100
@@ -14,22 +14,28 @@
 
 """Shared implementation of connections to API servers."""
 
+import collections
+try:
+    import collections.abc as collections_abc
+except ImportError:
+    import collections as collections_abc
 import json
+import os
 import platform
 import warnings
 
-from pkg_resources import get_distribution
 from six.moves.urllib.parse import urlencode
 
 from google.api_core.client_info import ClientInfo
 from google.cloud import exceptions
+from google.cloud import version
 
 
 API_BASE_URL = "https://www.googleapis.com";
 """The base of the API call URL."""
 
 DEFAULT_USER_AGENT = "gcloud-python/{0}".format(
-    get_distribution("google-cloud-core").version
+    version.__version__
 )
 """The user agent for google-cloud-python requests."""
 
@@ -171,12 +177,56 @@
     API_BASE_URL = None
     """The base of the API call URL."""
 
+    API_BASE_MTLS_URL = None
+    """The base of the API call URL for mutual TLS."""
+
+    ALLOW_AUTO_SWITCH_TO_MTLS_URL = False
+    """Indicates if auto switch to mTLS url is allowed."""
+
     API_VERSION = None
     """The version of the API, used in building the API call's URL."""
 
     API_URL_TEMPLATE = None
     """A template for the URL of a particular API call."""
 
+    def get_api_base_url_for_mtls(self, api_base_url=None):
+        """Return the api base url for mutual TLS.
+
+        Typically, you shouldn't need to use this method.
+
+        The logic is as follows:
+
+        If `api_base_url` is provided, just return this value; otherwise, the
+        return value depends `GOOGLE_API_USE_MTLS_ENDPOINT` environment 
variable
+        value.
+
+        If the environment variable value is "always", return 
`API_BASE_MTLS_URL`.
+        If the environment variable value is "never", return `API_BASE_URL`.
+        Otherwise, if `ALLOW_AUTO_SWITCH_TO_MTLS_URL` is True and the 
underlying
+        http is mTLS, then return `API_BASE_MTLS_URL`; otherwise return 
`API_BASE_URL`.
+
+        :type api_base_url: str
+        :param api_base_url: User provided api base url. It takes precedence 
over
+                             `API_BASE_URL` and `API_BASE_MTLS_URL`.
+
+        :rtype: str
+        :returns: The api base url used for mTLS.
+        """
+        if api_base_url:
+            return api_base_url
+
+        env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
+        if env == "always":
+            url_to_use = self.API_BASE_MTLS_URL
+        elif env == "never":
+            url_to_use = self.API_BASE_URL
+        else:
+            if self.ALLOW_AUTO_SWITCH_TO_MTLS_URL:
+                url_to_use = self.API_BASE_MTLS_URL if self.http.is_mtls else 
self.API_BASE_URL
+            else:
+                url_to_use = self.API_BASE_URL
+        return url_to_use
+
     def build_api_url(
         self, path, query_params=None, api_base_url=None, api_version=None
     ):
@@ -205,14 +255,24 @@
         :returns: The URL assembled from the pieces provided.
         """
         url = self.API_URL_TEMPLATE.format(
-            api_base_url=(api_base_url or self.API_BASE_URL),
+            api_base_url=self.get_api_base_url_for_mtls(api_base_url),
             api_version=(api_version or self.API_VERSION),
             path=path,
         )
 
         query_params = query_params or {}
-        if query_params:
-            url += "?" + urlencode(query_params, doseq=True)
+
+        if isinstance(query_params, collections_abc.Mapping):
+            query_params = query_params.copy()
+        else:
+            query_params_dict = collections.defaultdict(list)
+            for key, value in query_params:
+                query_params_dict[key].append(value)
+            query_params = query_params_dict
+
+        query_params.setdefault("prettyPrint", "false")
+
+        url += "?" + urlencode(query_params, doseq=True)
 
         return url
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/google/cloud/client.py 
new/google-cloud-core-1.6.0/google/cloud/client.py
--- old/google-cloud-core-1.3.0/google/cloud/client.py  2020-01-31 
22:59:39.000000000 +0100
+++ new/google-cloud-core-1.6.0/google/cloud/client.py  2021-02-06 
02:19:50.000000000 +0100
@@ -16,11 +16,15 @@
 
 import io
 import json
+import os
 from pickle import PicklingError
 
 import six
 
+import google.api_core.client_options
+import google.api_core.exceptions
 import google.auth
+from google.auth import environment_vars
 import google.auth.credentials
 import google.auth.transport.requests
 from google.cloud._helpers import _determine_default_project
@@ -102,6 +106,8 @@
             (Optional) The OAuth2 Credentials to use for this client. If not
             passed (and if no ``_http`` object is passed), falls back to the
             default inferred from the environment.
+        client_options (google.api_core.client_options.ClientOptions):
+            (Optional) Custom options for the client.
         _http (requests.Session):
             (Optional) HTTP object to make requests. Can be any object that
             defines ``request()`` with the same interface as
@@ -123,17 +129,37 @@
     Needs to be set by subclasses.
     """
 
-    def __init__(self, credentials=None, _http=None):
-        if credentials is not None and not isinstance(
-            credentials, google.auth.credentials.Credentials
-        ):
+    def __init__(self, credentials=None, _http=None, client_options=None):
+        if isinstance(client_options, dict):
+            client_options = 
google.api_core.client_options.from_dict(client_options)
+        if client_options is None:
+            client_options = google.api_core.client_options.ClientOptions()
+
+        if credentials and client_options.credentials_file:
+            raise google.api_core.exceptions.DuplicateCredentialArgs(
+                "'credentials' and 'client_options.credentials_file' are 
mutually exclusive.")
+
+        if credentials and not isinstance(credentials, 
google.auth.credentials.Credentials):
             raise ValueError(_GOOGLE_AUTH_CREDENTIALS_HELP)
-        if credentials is None and _http is None:
-            credentials, _ = google.auth.default()
+
+        scopes = client_options.scopes or self.SCOPE
+
+        # if no http is provided, credentials must exist
+        if not _http and credentials is None:
+            if client_options.credentials_file:
+                credentials, _ = google.auth.load_credentials_from_file(
+                    client_options.credentials_file, scopes=scopes)
+            else:
+                credentials, _ = google.auth.default(scopes=scopes)
+
         self._credentials = google.auth.credentials.with_scopes_if_required(
-            credentials, self.SCOPE
-        )
+            credentials, scopes=scopes)
+
+        if client_options.quota_project_id:
+            self._credentials = 
self._credentials.with_quota_project(client_options.quota_project_id)
+
         self._http_internal = _http
+        self._client_cert_source = client_options.client_cert_source
 
     def __getstate__(self):
         """Explicitly state that clients are not pickleable."""
@@ -158,6 +184,7 @@
                 self._credentials,
                 refresh_timeout=_CREDENTIALS_REFRESH_TIMEOUT,
             )
+            
self._http_internal.configure_mtls_channel(self._client_cert_source)
         return self._http_internal
 
 
@@ -165,26 +192,50 @@
     """Mixin to allow setting the project on the client.
 
     :type project: str
-    :param project: the project which the client acts on behalf of. If not
-                    passed falls back to the default inferred from the
-                    environment.
+    :param project:
+        (Optional) the project which the client acts on behalf of. If not
+        passed, falls back to the default inferred from the environment.
+
+    :type credentials: :class:`google.auth.credentials.Credentials`
+    :param credentials:
+        (Optional) credentials used to discover a project, if not passed.
 
     :raises: :class:`EnvironmentError` if the project is neither passed in nor
-             set in the environment. :class:`ValueError` if the project value
-             is invalid.
+             set on the credentials or in the environment. :class:`ValueError`
+             if the project value is invalid.
     """
 
-    def __init__(self, project=None):
-        project = self._determine_default(project)
+    def __init__(self, project=None, credentials=None):
+        # This test duplicates the one from `google.auth.default`, but earlier,
+        # for backward compatibility:  we want the environment variable to
+        # override any project set on the credentials.  See:
+        # https://github.com/googleapis/python-cloud-core/issues/27
+        if project is None:
+            project = os.getenv(
+                environment_vars.PROJECT,
+                os.getenv(environment_vars.LEGACY_PROJECT),
+            )
+
+        # Project set on explicit credentials overrides discovery from
+        # SDK / GAE / GCE.
+        if project is None and credentials is not None:
+            project = getattr(credentials, "project_id", None)
+
+        if project is None:
+            project = self._determine_default(project)
+
         if project is None:
             raise EnvironmentError(
                 "Project was not passed and could not be "
                 "determined from the environment."
             )
+
         if isinstance(project, six.binary_type):
             project = project.decode("utf-8")
+
         if not isinstance(project, six.string_types):
             raise ValueError("Project must be a string.")
+
         self.project = project
 
     @staticmethod
@@ -222,6 +273,6 @@
 
     _SET_PROJECT = True  # Used by from_service_account_json()
 
-    def __init__(self, project=None, credentials=None, _http=None):
-        _ClientProjectMixin.__init__(self, project=project)
-        Client.__init__(self, credentials=credentials, _http=_http)
+    def __init__(self, project=None, credentials=None, client_options=None, 
_http=None):
+        _ClientProjectMixin.__init__(self, project=project, 
credentials=credentials)
+        Client.__init__(self, credentials=credentials, 
client_options=client_options, _http=_http)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/google/cloud/version.py 
new/google-cloud-core-1.6.0/google/cloud/version.py
--- old/google-cloud-core-1.3.0/google/cloud/version.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/google-cloud-core-1.6.0/google/cloud/version.py 2021-02-06 
02:19:50.000000000 +0100
@@ -0,0 +1,15 @@
+# Copyright 2020 Google LLC
+#
+# 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.
+
+__version__ = "1.6.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-cloud-core-1.3.0/google_cloud_core.egg-info/PKG-INFO 
new/google-cloud-core-1.6.0/google_cloud_core.egg-info/PKG-INFO
--- old/google-cloud-core-1.3.0/google_cloud_core.egg-info/PKG-INFO     
2020-01-31 23:02:20.000000000 +0100
+++ new/google-cloud-core-1.6.0/google_cloud_core.egg-info/PKG-INFO     
2021-02-06 02:23:12.000000000 +0100
@@ -1,15 +1,15 @@
 Metadata-Version: 2.1
 Name: google-cloud-core
-Version: 1.3.0
+Version: 1.6.0
 Summary: Google Cloud API client core library
-Home-page: https://github.com/GoogleCloudPlatform/google-cloud-python
+Home-page: https://github.com/googleapis/python-cloud-core
 Author: Google LLC
 Author-email: googleapis-packa...@google.com
 License: Apache 2.0
 Description: Core Helpers for Google Cloud Python Client Library
         ===================================================
         
-        |pypi| |versions| 
+        |pypi| |versions|
         
         This library is not meant to stand-alone. Instead it defines
         common helpers (e.g. base ``Client`` classes) used by all of the
@@ -40,24 +40,25 @@
         
         Supported Python Versions
         -------------------------
-        Python >= 3.5
+        Python >= 3.6
         
         Deprecated Python Versions
         --------------------------
         Python == 2.7. Python 2.7 support will be removed on January 1, 2020.
         
 Platform: Posix; MacOS X; Windows
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: Apache Software License
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
 Classifier: Operating System :: OS Independent
 Classifier: Topic :: Internet
-Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
+Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*
 Provides-Extra: grpc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-cloud-core-1.3.0/google_cloud_core.egg-info/SOURCES.txt 
new/google-cloud-core-1.6.0/google_cloud_core.egg-info/SOURCES.txt
--- old/google-cloud-core-1.3.0/google_cloud_core.egg-info/SOURCES.txt  
2020-01-31 23:02:20.000000000 +0100
+++ new/google-cloud-core-1.6.0/google_cloud_core.egg-info/SOURCES.txt  
2021-02-06 02:23:12.000000000 +0100
@@ -13,6 +13,7 @@
 google/cloud/exceptions.py
 google/cloud/obsolete.py
 google/cloud/operation.py
+google/cloud/version.py
 google_cloud_core.egg-info/PKG-INFO
 google_cloud_core.egg-info/SOURCES.txt
 google_cloud_core.egg-info/dependency_links.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-cloud-core-1.3.0/google_cloud_core.egg-info/requires.txt 
new/google-cloud-core-1.6.0/google_cloud_core.egg-info/requires.txt
--- old/google-cloud-core-1.3.0/google_cloud_core.egg-info/requires.txt 
2020-01-31 23:02:20.000000000 +0100
+++ new/google-cloud-core-1.6.0/google_cloud_core.egg-info/requires.txt 
2021-02-06 02:23:12.000000000 +0100
@@ -1,4 +1,6 @@
-google-api-core<2.0.0dev,>=1.16.0
+google-api-core<2.0.0dev,>=1.21.0
+google-auth<2.0dev,>=1.24.0
+six>=1.12.0
 
 [grpc]
 grpcio<2.0dev,>=1.8.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/setup.py 
new/google-cloud-core-1.6.0/setup.py
--- old/google-cloud-core-1.3.0/setup.py        2020-01-31 22:59:39.000000000 
+0100
+++ new/google-cloud-core-1.6.0/setup.py        2021-02-06 02:19:50.000000000 
+0100
@@ -22,13 +22,18 @@
 
 name = "google-cloud-core"
 description = "Google Cloud API client core library"
-version = "1.3.0"
 # Should be one of:
 # 'Development Status :: 3 - Alpha'
 # 'Development Status :: 4 - Beta'
 # 'Development Status :: 5 - Production/Stable'
-release_status = "Development Status :: 4 - Beta"
-dependencies = ["google-api-core >= 1.16.0, < 2.0.0dev"]
+release_status = "Development Status :: 5 - Production/Stable"
+dependencies = [
+    "google-api-core >= 1.21.0, < 2.0.0dev",
+    "google-auth >= 1.24.0, < 2.0dev",
+    # Support six==1.12.0 due to App Engine standard runtime.
+    # https://github.com/googleapis/python-cloud-core/issues/45
+    "six >=1.12.0",
+]
 extras = {"grpc": "grpcio >= 1.8.2, < 2.0dev"}
 
 
@@ -36,6 +41,11 @@
 
 package_root = os.path.abspath(os.path.dirname(__file__))
 
+version = {}
+with open(os.path.join(package_root, "google/cloud/version.py")) as fp:
+    exec(fp.read(), version)
+version = version["__version__"]
+
 readme_filename = os.path.join(package_root, "README.rst")
 with io.open(readme_filename, encoding="utf-8") as readme_file:
     readme = readme_file.read()
@@ -60,7 +70,7 @@
     author="Google LLC",
     author_email="googleapis-packa...@google.com",
     license="Apache 2.0",
-    url="https://github.com/GoogleCloudPlatform/google-cloud-python";,
+    url="https://github.com/googleapis/python-cloud-core";,
     classifiers=[
         release_status,
         "Intended Audience :: Developers",
@@ -69,9 +79,10 @@
         "Programming Language :: Python :: 2",
         "Programming Language :: Python :: 2.7",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
-        'Programming Language :: Python :: 3.7',
+        "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
         "Operating System :: OS Independent",
         "Topic :: Internet",
     ],
@@ -80,7 +91,7 @@
     namespace_packages=namespaces,
     install_requires=dependencies,
     extras_require=extras,
-    python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*',
+    python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*",
     include_package_data=True,
     zip_safe=False,
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/tests/unit/test__http.py 
new/google-cloud-core-1.6.0/tests/unit/test__http.py
--- old/google-cloud-core-1.3.0/tests/unit/test__http.py        2020-01-31 
22:59:39.000000000 +0100
+++ new/google-cloud-core-1.6.0/tests/unit/test__http.py        2021-02-06 
02:19:50.000000000 +0100
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import json
+import os
 import unittest
 import warnings
 
@@ -165,6 +166,7 @@
         class MockConnection(self._get_target_class()):
             API_URL_TEMPLATE = "{api_base_url}/mock/{api_version}{path}"
             API_BASE_URL = "http://mock";
+            API_BASE_MTLS_URL = "https://mock.mtls";
             API_VERSION = "vMOCK"
 
         return MockConnection(*args, **kw)
@@ -184,9 +186,16 @@
         client = object()
         conn = self._make_mock_one(client)
         # Intended to emulate self.mock_template
-        URI = "/".join([conn.API_BASE_URL, "mock", conn.API_VERSION, "foo"])
+        URI = "/".join([conn.API_BASE_URL, "mock", conn.API_VERSION, 
"foo?prettyPrint=false"])
         self.assertEqual(conn.build_api_url("/foo"), URI)
 
+    def test_build_api_url_w_pretty_print_query_params(self):
+        client = object()
+        conn = self._make_mock_one(client)
+        uri = conn.build_api_url("/foo", {"prettyPrint": "true"})
+        URI = "/".join([conn.API_BASE_URL, "mock", conn.API_VERSION, 
"foo?prettyPrint=true"])
+        self.assertEqual(uri, URI)
+
     def test_build_api_url_w_extra_query_params(self):
         from six.moves.urllib.parse import parse_qs
         from six.moves.urllib.parse import urlsplit
@@ -203,6 +212,69 @@
         parms = dict(parse_qs(qs))
         self.assertEqual(parms["bar"], ["baz"])
         self.assertEqual(parms["qux"], ["quux", "corge"])
+        self.assertEqual(parms["prettyPrint"], ["false"])
+
+    def test_build_api_url_w_extra_query_params_tuples(self):
+        from six.moves.urllib.parse import parse_qs
+        from six.moves.urllib.parse import urlsplit
+
+        client = object()
+        conn = self._make_mock_one(client)
+        uri = conn.build_api_url("/foo", [("bar", "baz"), ("qux", "quux"), 
("qux", "corge")])
+
+        scheme, netloc, path, qs, _ = urlsplit(uri)
+        self.assertEqual("%s://%s" % (scheme, netloc), conn.API_BASE_URL)
+        # Intended to emulate mock_template
+        PATH = "/".join(["", "mock", conn.API_VERSION, "foo"])
+        self.assertEqual(path, PATH)
+        parms = dict(parse_qs(qs))
+        self.assertEqual(parms["bar"], ["baz"])
+        self.assertEqual(parms["qux"], ["quux", "corge"])
+        self.assertEqual(parms["prettyPrint"], ["false"])
+
+    def test_get_api_base_url_for_mtls_w_api_base_url(self):
+        client = object()
+        conn = self._make_mock_one(client)
+        uri = conn.get_api_base_url_for_mtls(api_base_url="http://foo";)
+        self.assertEqual(uri, "http://foo";)
+
+    def test_get_api_base_url_for_mtls_env_always(self):
+        client = object()
+        conn = self._make_mock_one(client)
+        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": 
"always"}):
+            uri = conn.get_api_base_url_for_mtls()
+            self.assertEqual(uri, "https://mock.mtls";)
+
+    def test_get_api_base_url_for_mtls_env_never(self):
+        client = object()
+        conn = self._make_mock_one(client)
+        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": 
"never"}):
+            uri = conn.get_api_base_url_for_mtls()
+            self.assertEqual(uri, "http://mock";)
+
+    def test_get_api_base_url_for_mtls_env_auto(self):
+        client = mock.Mock()
+        client._http = mock.Mock()
+        client._http.is_mtls = False
+        conn = self._make_mock_one(client)
+
+        # ALLOW_AUTO_SWITCH_TO_MTLS_URL is False, so use regular endpoint.
+        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": 
"auto"}):
+            uri = conn.get_api_base_url_for_mtls()
+            self.assertEqual(uri, "http://mock";)
+
+        # ALLOW_AUTO_SWITCH_TO_MTLS_URL is True, so now endpoint dependes
+        # on client._http.is_mtls
+        conn.ALLOW_AUTO_SWITCH_TO_MTLS_URL = True
+
+        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": 
"auto"}):
+            uri = conn.get_api_base_url_for_mtls()
+            self.assertEqual(uri, "http://mock";)
+
+        client._http.is_mtls = True
+        with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": 
"auto"}):
+            uri = conn.get_api_base_url_for_mtls()
+            self.assertEqual(uri, "https://mock.mtls";)
 
     def test__make_request_no_data_no_content_type_no_headers(self):
         from google.cloud._http import CLIENT_INFO_HEADER
@@ -319,7 +391,7 @@
             "User-Agent": conn.user_agent,
             CLIENT_INFO_HEADER: conn.user_agent,
         }
-        expected_url = "{base}/mock/{version}{path}".format(
+        expected_url = "{base}/mock/{version}{path}?prettyPrint=false".format(
             base=conn.API_BASE_URL, version=conn.API_VERSION, path=path
         )
         http.request.assert_called_once_with(
@@ -481,7 +553,7 @@
             "User-Agent": conn.user_agent,
             CLIENT_INFO_HEADER: conn.user_agent,
         }
-        expected_url = "{base}/mock/{version}{path}".format(
+        expected_url = "{base}/mock/{version}{path}?prettyPrint=false".format(
             base=conn.API_BASE_URL, version=conn.API_VERSION, path=path
         )
         http.request.assert_called_once_with(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.3.0/tests/unit/test_client.py 
new/google-cloud-core-1.6.0/tests/unit/test_client.py
--- old/google-cloud-core-1.3.0/tests/unit/test_client.py       2020-01-31 
22:59:39.000000000 +0100
+++ new/google-cloud-core-1.6.0/tests/unit/test_client.py       2021-02-06 
02:19:50.000000000 +0100
@@ -22,7 +22,7 @@
 def _make_credentials():
     import google.auth.credentials
 
-    return mock.Mock(spec=google.auth.credentials.Credentials)
+    return mock.Mock(spec=google.auth.credentials.CredentialsWithQuotaProject)
 
 
 class Test_ClientFactoryMixin(unittest.TestCase):
@@ -50,14 +50,14 @@
     def test_unpickleable(self):
         import pickle
 
-        CREDENTIALS = _make_credentials()
+        credentials = _make_credentials()
         HTTP = object()
 
-        client_obj = self._make_one(credentials=CREDENTIALS, _http=HTTP)
+        client_obj = self._make_one(credentials=credentials, _http=HTTP)
         with self.assertRaises(pickle.PicklingError):
             pickle.dumps(client_obj)
 
-    def test_constructor_defaults(self):
+    def test_ctor_defaults(self):
         credentials = _make_credentials()
 
         patch = mock.patch("google.auth.default", return_value=(credentials, 
None))
@@ -66,9 +66,9 @@
 
         self.assertIs(client_obj._credentials, credentials)
         self.assertIsNone(client_obj._http_internal)
-        default.assert_called_once_with()
+        default.assert_called_once_with(scopes=None)
 
-    def test_constructor_explicit(self):
+    def test_ctor_explicit(self):
         credentials = _make_credentials()
         http = mock.sentinel.http
         client_obj = self._make_one(credentials=credentials, _http=http)
@@ -76,12 +76,73 @@
         self.assertIs(client_obj._credentials, credentials)
         self.assertIs(client_obj._http_internal, http)
 
-    def test_constructor_bad_credentials(self):
+    def test_ctor_client_options_w_conflicting_creds(self):
+        from google.api_core.exceptions import DuplicateCredentialArgs
+
+        credentials = _make_credentials()
+        client_options = {'credentials_file': '/path/to/creds.json'}
+        with self.assertRaises(DuplicateCredentialArgs):
+            self._make_one(credentials=credentials, 
client_options=client_options)
+
+    def test_ctor_bad_credentials(self):
         credentials = mock.sentinel.credentials
 
         with self.assertRaises(ValueError):
             self._make_one(credentials=credentials)
 
+    def test_ctor_client_options_w_creds_file_scopes(self):
+        credentials = _make_credentials()
+        credentials_file = '/path/to/creds.json'
+        scopes = ['SCOPE1', 'SCOPE2']
+        client_options = {'credentials_file': credentials_file, 'scopes': 
scopes}
+
+        patch = mock.patch("google.auth.load_credentials_from_file", 
return_value=(credentials, None))
+        with patch as load_credentials_from_file:
+            client_obj = self._make_one(client_options=client_options)
+
+        self.assertIs(client_obj._credentials, credentials)
+        self.assertIsNone(client_obj._http_internal)
+        load_credentials_from_file.assert_called_once_with(credentials_file, 
scopes=scopes)
+
+    def test_ctor_client_options_w_quota_project(self):
+        credentials = _make_credentials()
+        quota_project_id = 'quota-project-123'
+        client_options = {'quota_project_id': quota_project_id}
+
+        client_obj = self._make_one(credentials=credentials, 
client_options=client_options)
+
+        self.assertIs(client_obj._credentials, 
credentials.with_quota_project.return_value)
+        
credentials.with_quota_project.assert_called_once_with(quota_project_id)
+
+    def test_ctor__http_property_existing(self):
+        credentials = _make_credentials()
+        http = object()
+        client = self._make_one(credentials=credentials, _http=http)
+        self.assertIs(client._http_internal, http)
+        self.assertIs(client._http, http)
+
+    def test_ctor__http_property_new(self):
+        from google.cloud.client import _CREDENTIALS_REFRESH_TIMEOUT
+
+        credentials = _make_credentials()
+        mock_client_cert_source = mock.Mock()
+        client_options = {'client_cert_source': mock_client_cert_source}
+        client = self._make_one(credentials=credentials, 
client_options=client_options)
+        self.assertIsNone(client._http_internal)
+
+        with mock.patch('google.auth.transport.requests.AuthorizedSession') as 
AuthorizedSession:
+            session = mock.Mock()
+            session.configure_mtls_channel = mock.Mock()
+            AuthorizedSession.return_value = session
+            self.assertIs(client._http, session)
+            # Check the mock.
+            AuthorizedSession.assert_called_once_with(credentials, 
refresh_timeout=_CREDENTIALS_REFRESH_TIMEOUT)
+            
session.configure_mtls_channel.assert_called_once_with(mock_client_cert_source)
+            # Make sure the cached value is used on subsequent access.
+            self.assertIs(client._http_internal, session)
+            self.assertIs(client._http, session)
+            self.assertEqual(AuthorizedSession.call_count, 1)
+
     def test_from_service_account_json(self):
         from google.cloud import _helpers
 
@@ -114,31 +175,131 @@
                 mock.sentinel.filename, credentials=mock.sentinel.credentials
             )
 
-    def test__http_property_existing(self):
-        credentials = _make_credentials()
-        http = object()
-        client = self._make_one(credentials=credentials, _http=http)
-        self.assertIs(client._http_internal, http)
-        self.assertIs(client._http, http)
 
-    def test__http_property_new(self):
-        from google.cloud.client import _CREDENTIALS_REFRESH_TIMEOUT
-        credentials = _make_credentials()
-        client = self._make_one(credentials=credentials)
-        self.assertIsNone(client._http_internal)
+class Test_ClientProjectMixin(unittest.TestCase):
+    @staticmethod
+    def _get_target_class():
+        from google.cloud.client import _ClientProjectMixin
+
+        return _ClientProjectMixin
 
-        authorized_session_patch = mock.patch(
-            "google.auth.transport.requests.AuthorizedSession",
-            return_value=mock.sentinel.http,
+    def _make_one(self, *args, **kw):
+        return self._get_target_class()(*args, **kw)
+
+    def test_ctor_defaults_wo_envvar(self):
+        environ = {}
+        patch_env = mock.patch("os.environ", new=environ)
+        patch_default = mock.patch(
+            "google.cloud.client._determine_default_project",
+            return_value=None,
         )
-        with authorized_session_patch as AuthorizedSession:
-            self.assertIs(client._http, mock.sentinel.http)
-            # Check the mock.
-            AuthorizedSession.assert_called_once_with(credentials, 
refresh_timeout=_CREDENTIALS_REFRESH_TIMEOUT)
-            # Make sure the cached value is used on subsequent access.
-            self.assertIs(client._http_internal, mock.sentinel.http)
-            self.assertIs(client._http, mock.sentinel.http)
-            self.assertEqual(AuthorizedSession.call_count, 1)
+        with patch_env:
+            with patch_default as patched:
+                with self.assertRaises(EnvironmentError):
+                    self._make_one()
+
+        patched.assert_called_once_with(None)
+
+    def test_ctor_defaults_w_envvar(self):
+        from google.auth.environment_vars import PROJECT
+
+        project = "some-project-123"
+        environ = {PROJECT: project}
+        patch_env = mock.patch("os.environ", new=environ)
+        with patch_env:
+            client = self._make_one()
+
+        self.assertEqual(client.project, project)
+
+    def test_ctor_defaults_w_legacy_envvar(self):
+        from google.auth.environment_vars import LEGACY_PROJECT
+
+        project = "some-project-123"
+        environ = {LEGACY_PROJECT: project}
+        patch_env = mock.patch("os.environ", new=environ)
+        with patch_env:
+            client = self._make_one()
+
+        self.assertEqual(client.project, project)
+
+    def test_ctor_w_explicit_project(self):
+        explicit_project = "explicit-project-456"
+        patch_default = mock.patch(
+            "google.cloud.client._determine_default_project",
+            return_value=None,
+        )
+        with patch_default as patched:
+            client = self._make_one(project=explicit_project)
+
+        self.assertEqual(client.project, explicit_project)
+
+        patched.assert_not_called()
+
+    def test_ctor_w_explicit_project_bytes(self):
+        explicit_project = b"explicit-project-456"
+        patch_default = mock.patch(
+            "google.cloud.client._determine_default_project",
+            return_value=None,
+        )
+        with patch_default as patched:
+            client = self._make_one(project=explicit_project)
+
+        self.assertEqual(client.project, explicit_project.decode("utf-8"))
+
+        patched.assert_not_called()
+
+    def test_ctor_w_explicit_project_invalid(self):
+        explicit_project = object()
+        patch_default = mock.patch(
+            "google.cloud.client._determine_default_project",
+            return_value=None,
+        )
+        with patch_default as patched:
+            with self.assertRaises(ValueError):
+                self._make_one(project=explicit_project)
+
+        patched.assert_not_called()
+
+    @staticmethod
+    def _make_credentials(**kw):
+        from google.auth.credentials import Credentials
+
+        class _Credentials(Credentials):
+            def __init__(self, **kw):
+                self.__dict__.update(kw)
+
+            def refresh(self):  # pragma: NO COVER
+                pass
+
+        return _Credentials(**kw)
+
+    def test_ctor_w_explicit_credentials_wo_project(self):
+        default_project = "default-project-123"
+        credentials = self._make_credentials()
+        patch_default = mock.patch(
+            "google.cloud.client._determine_default_project",
+            return_value=default_project,
+        )
+        with patch_default as patched:
+            client = self._make_one(credentials=credentials)
+
+        self.assertEqual(client.project, default_project)
+
+        patched.assert_called_once_with(None)
+
+    def test_ctor_w_explicit_credentials_w_project(self):
+        project = "credentials-project-456"
+        credentials = self._make_credentials(project_id=project)
+        patch_default = mock.patch(
+            "google.cloud.client._determine_default_project",
+            return_value=None,
+        )
+        with patch_default as patched:
+            client = self._make_one(credentials=credentials)
+
+        self.assertEqual(client.project, project)
+
+        patched.assert_not_called()
 
 
 class TestClientWithProject(unittest.TestCase):
@@ -167,7 +328,7 @@
         self.assertEqual(client_obj.project, project)
         self.assertIs(client_obj._credentials, credentials)
         self.assertIsNone(client_obj._http_internal)
-        default.assert_called_once_with()
+        default.assert_called_once_with(scopes=None)
         _determine_default_project.assert_called_once_with(None)
 
     def test_constructor_missing_project(self):

Reply via email to