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-08-03 22:48:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-google-cloud-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-google-cloud-core.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-google-cloud-core"

Tue Aug  3 22:48:39 2021 rev:9 rq:909842 version:1.7.2

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-google-cloud-core/python-google-cloud-core.changes
        2021-04-14 10:11:23.241535054 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-google-cloud-core.new.1899/python-google-cloud-core.changes
      2021-08-03 22:48:53.380486097 +0200
@@ -1,0 +2,9 @@
+Tue Aug  3 00:43:52 UTC 2021 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Update to 1.7.2:
+  * pass kwargs through in 'from_service_account_json' (#109) (efc4bbf)
+  * add 'Client.close' (#100) (7387fc8)
+  * add 'Client.from_service_account_info' factory (#54) (7e59360) 
+- Actually use %pytest macro for testing
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ python-google-cloud-core.spec ++++++
--- /var/tmp/diff_new_pack.FvZaO8/_old  2021-08-03 22:48:53.828485557 +0200
+++ /var/tmp/diff_new_pack.FvZaO8/_new  2021-08-03 22:48:53.832485552 +0200
@@ -19,11 +19,10 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %bcond_without python2
 Name:           python-google-cloud-core
-Version:        1.6.0
+Version:        1.7.2
 Release:        0
 Summary:        Google Cloud API client core library
 License:        Apache-2.0
-Group:          Development/Languages/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.21.0}
@@ -64,7 +63,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py test
+%pytest
 
 %files %{python_files}
 %license LICENSE

++++++ google-cloud-core-1.6.0.tar.gz -> google-cloud-core-1.7.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.6.0/MANIFEST.in 
new/google-cloud-core-1.7.2/MANIFEST.in
--- old/google-cloud-core-1.6.0/MANIFEST.in     2021-02-06 02:19:50.000000000 
+0100
+++ new/google-cloud-core-1.7.2/MANIFEST.in     2021-07-27 20:05:41.000000000 
+0200
@@ -16,10 +16,10 @@
 
 # Generated by synthtool. DO NOT EDIT!
 include README.rst LICENSE
-recursive-include google *.json *.proto
+recursive-include google *.json *.proto py.typed
 recursive-include tests *
 global-exclude *.py[co]
 global-exclude __pycache__
 
 # Exclude scripts for samples readmegen
-prune scripts/readme-gen
\ No newline at end of file
+prune scripts/readme-gen
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.6.0/PKG-INFO 
new/google-cloud-core-1.7.2/PKG-INFO
--- old/google-cloud-core-1.6.0/PKG-INFO        2021-02-06 02:23:12.442483000 
+0100
+++ new/google-cloud-core-1.7.2/PKG-INFO        2021-07-27 20:08:24.116366000 
+0200
@@ -1,51 +1,11 @@
 Metadata-Version: 2.1
 Name: google-cloud-core
-Version: 1.6.0
+Version: 1.7.2
 Summary: Google Cloud API client core library
 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|
-        
-        This library is not meant to stand-alone. Instead it defines
-        common helpers (e.g. base ``Client`` classes) used by all of the
-        ``google-cloud-*`` packages.
-        
-        
-        -  `Documentation`_
-        
-        .. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-core.svg
-           :target: https://pypi.org/project/google-cloud-core/
-        .. |versions| image:: 
https://img.shields.io/pypi/pyversions/google-cloud-core.svg
-           :target: https://pypi.org/project/google-cloud-core/
-        .. _Documentation: 
https://googleapis.dev/python/google-cloud-core/latest
-        
-        Quick Start
-        -----------
-        
-        .. code-block:: console
-        
-            $ pip install --upgrade google-cloud-core
-        
-        For more information on setting up your Python development environment,
-        such as installing ``pip`` and ``virtualenv`` on your system, please 
refer
-        to `Python Development Environment Setup Guide`_ for Google Cloud 
Platform.
-        
-        .. _Python Development Environment Setup Guide: 
https://cloud.google.com/python/setup
-        
-        
-        Supported Python Versions
-        -------------------------
-        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 :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
@@ -62,3 +22,46 @@
 Classifier: Topic :: Internet
 Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*
 Provides-Extra: grpc
+License-File: LICENSE
+
+Core Helpers for Google Cloud Python Client Library
+===================================================
+
+|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
+``google-cloud-*`` packages.
+
+
+-  `Documentation`_
+
+.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-core.svg
+   :target: https://pypi.org/project/google-cloud-core/
+.. |versions| image:: 
https://img.shields.io/pypi/pyversions/google-cloud-core.svg
+   :target: https://pypi.org/project/google-cloud-core/
+.. _Documentation: https://googleapis.dev/python/google-cloud-core/latest
+
+Quick Start
+-----------
+
+.. code-block:: console
+
+    $ pip install --upgrade google-cloud-core
+
+For more information on setting up your Python development environment,
+such as installing ``pip`` and ``virtualenv`` on your system, please refer
+to `Python Development Environment Setup Guide`_ for Google Cloud Platform.
+
+.. _Python Development Environment Setup Guide: 
https://cloud.google.com/python/setup
+
+
+Supported Python Versions
+-------------------------
+Python >= 3.6
+
+Deprecated Python Versions
+--------------------------
+Python == 2.7. Python 2.7 support will be removed on January 1, 2020.
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.6.0/google/cloud/_http.py 
new/google-cloud-core-1.7.2/google/cloud/_http.py
--- old/google-cloud-core-1.6.0/google/cloud/_http.py   2021-02-06 
02:19:50.000000000 +0100
+++ new/google-cloud-core-1.7.2/google/cloud/_http.py   2021-07-27 
20:05:41.000000000 +0200
@@ -15,9 +15,10 @@
 """Shared implementation of connections to API servers."""
 
 import collections
+
 try:
     import collections.abc as collections_abc
-except ImportError:
+except ImportError:  # Python2
     import collections as collections_abc
 import json
 import os
@@ -34,9 +35,7 @@
 API_BASE_URL = "https://www.googleapis.com";
 """The base of the API call URL."""
 
-DEFAULT_USER_AGENT = "gcloud-python/{0}".format(
-    version.__version__
-)
+DEFAULT_USER_AGENT = "gcloud-python/{0}".format(version.__version__)
 """The user agent for google-cloud-python requests."""
 
 CLIENT_INFO_HEADER = "X-Goog-API-Client"
@@ -83,14 +82,12 @@
         :rtype: str
         :returns: user agent
         """
-        warnings.warn(
-            _USER_AGENT_ALL_CAPS_DEPRECATED, DeprecationWarning, stacklevel=2)
+        warnings.warn(_USER_AGENT_ALL_CAPS_DEPRECATED, DeprecationWarning, 
stacklevel=2)
         return self.user_agent
 
     @USER_AGENT.setter
     def USER_AGENT(self, value):
-        warnings.warn(
-            _USER_AGENT_ALL_CAPS_DEPRECATED, DeprecationWarning, stacklevel=2)
+        warnings.warn(_USER_AGENT_ALL_CAPS_DEPRECATED, DeprecationWarning, 
stacklevel=2)
         self.user_agent = value
 
     @property
@@ -114,13 +111,15 @@
         :returns: header keys / values
         """
         warnings.warn(
-            _EXTRA_HEADERS_ALL_CAPS_DEPRECATED, DeprecationWarning, 
stacklevel=2)
+            _EXTRA_HEADERS_ALL_CAPS_DEPRECATED, DeprecationWarning, 
stacklevel=2
+        )
         return self.extra_headers
 
     @_EXTRA_HEADERS.setter
     def _EXTRA_HEADERS(self, value):
         warnings.warn(
-            _EXTRA_HEADERS_ALL_CAPS_DEPRECATED, DeprecationWarning, 
stacklevel=2)
+            _EXTRA_HEADERS_ALL_CAPS_DEPRECATED, DeprecationWarning, 
stacklevel=2
+        )
         self.extra_headers = value
 
     @property
@@ -222,7 +221,9 @@
             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
+                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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.6.0/google/cloud/client.py 
new/google-cloud-core-1.7.2/google/cloud/client.py
--- old/google-cloud-core-1.6.0/google/cloud/client.py  2021-02-06 
02:19:50.000000000 +0100
+++ new/google-cloud-core-1.7.2/google/cloud/client.py  2021-07-27 
20:05:41.000000000 +0200
@@ -52,6 +52,36 @@
     _SET_PROJECT = False
 
     @classmethod
+    def from_service_account_info(cls, info, *args, **kwargs):
+        """Factory to retrieve JSON credentials while creating client.
+
+        :type info: str
+        :param info:
+            The JSON object with a private key and other credentials
+            information (downloaded from the Google APIs console).
+
+        :type args: tuple
+        :param args: Remaining positional arguments to pass to constructor.
+
+        :param kwargs: Remaining keyword arguments to pass to constructor.
+
+        :rtype: :class:`_ClientFactoryMixin`
+        :returns: The client created with the retrieved JSON credentials.
+        :raises TypeError: if there is a conflict with the kwargs
+                 and the credentials created by the factory.
+        """
+        if "credentials" in kwargs:
+            raise TypeError("credentials must not be in keyword arguments")
+
+        credentials = 
service_account.Credentials.from_service_account_info(info)
+        if cls._SET_PROJECT:
+            if "project" not in kwargs:
+                kwargs["project"] = info.get("project_id")
+
+        kwargs["credentials"] = credentials
+        return cls(*args, **kwargs)
+
+    @classmethod
     def from_service_account_json(cls, json_credentials_path, *args, **kwargs):
         """Factory to retrieve JSON credentials while creating client.
 
@@ -73,19 +103,10 @@
         :raises TypeError: if there is a conflict with the kwargs
                  and the credentials created by the factory.
         """
-        if "credentials" in kwargs:
-            raise TypeError("credentials must not be in keyword arguments")
         with io.open(json_credentials_path, "r", encoding="utf-8") as json_fi:
             credentials_info = json.load(json_fi)
-        credentials = service_account.Credentials.from_service_account_info(
-            credentials_info
-        )
-        if cls._SET_PROJECT:
-            if "project" not in kwargs:
-                kwargs["project"] = credentials_info.get("project_id")
 
-        kwargs["credentials"] = credentials
-        return cls(*args, **kwargs)
+        return cls.from_service_account_info(credentials_info, *args, **kwargs)
 
 
 class Client(_ClientFactoryMixin):
@@ -137,9 +158,12 @@
 
         if credentials and client_options.credentials_file:
             raise google.api_core.exceptions.DuplicateCredentialArgs(
-                "'credentials' and 'client_options.credentials_file' are 
mutually exclusive.")
+                "'credentials' and 'client_options.credentials_file' are 
mutually exclusive."
+            )
 
-        if credentials and not isinstance(credentials, 
google.auth.credentials.Credentials):
+        if credentials and not isinstance(
+            credentials, google.auth.credentials.Credentials
+        ):
             raise ValueError(_GOOGLE_AUTH_CREDENTIALS_HELP)
 
         scopes = client_options.scopes or self.SCOPE
@@ -148,15 +172,19 @@
         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)
+                    client_options.credentials_file, scopes=scopes
+                )
             else:
                 credentials, _ = google.auth.default(scopes=scopes)
 
         self._credentials = google.auth.credentials.with_scopes_if_required(
-            credentials, scopes=scopes)
+            credentials, scopes=scopes
+        )
 
         if client_options.quota_project_id:
-            self._credentials = 
self._credentials.with_quota_project(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
@@ -181,12 +209,26 @@
         """
         if self._http_internal is None:
             self._http_internal = 
google.auth.transport.requests.AuthorizedSession(
-                self._credentials,
-                refresh_timeout=_CREDENTIALS_REFRESH_TIMEOUT,
+                self._credentials, 
refresh_timeout=_CREDENTIALS_REFRESH_TIMEOUT,
             )
             
self._http_internal.configure_mtls_channel(self._client_cert_source)
         return self._http_internal
 
+    def close(self):
+        """Clean up transport, if set.
+
+        Suggested use:
+
+        .. code-block:: python
+
+           import contextlib
+
+           with contextlib.closing(client):  # closes on exit
+               do_something_with(client)
+        """
+        if self._http_internal is not None:
+            self._http_internal.close()
+
 
 class _ClientProjectMixin(object):
     """Mixin to allow setting the project on the client.
@@ -212,8 +254,7 @@
         # 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),
+                environment_vars.PROJECT, 
os.getenv(environment_vars.LEGACY_PROJECT),
             )
 
         # Project set on explicit credentials overrides discovery from
@@ -275,4 +316,6 @@
 
     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)
+        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.6.0/google/cloud/version.py 
new/google-cloud-core-1.7.2/google/cloud/version.py
--- old/google-cloud-core-1.6.0/google/cloud/version.py 2021-02-06 
02:19:50.000000000 +0100
+++ new/google-cloud-core-1.7.2/google/cloud/version.py 2021-07-27 
20:05:41.000000000 +0200
@@ -12,4 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-__version__ = "1.6.0"
+__version__ = "1.7.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/google-cloud-core-1.6.0/google_cloud_core.egg-info/PKG-INFO 
new/google-cloud-core-1.7.2/google_cloud_core.egg-info/PKG-INFO
--- old/google-cloud-core-1.6.0/google_cloud_core.egg-info/PKG-INFO     
2021-02-06 02:23:12.000000000 +0100
+++ new/google-cloud-core-1.7.2/google_cloud_core.egg-info/PKG-INFO     
2021-07-27 20:08:23.000000000 +0200
@@ -1,51 +1,11 @@
 Metadata-Version: 2.1
 Name: google-cloud-core
-Version: 1.6.0
+Version: 1.7.2
 Summary: Google Cloud API client core library
 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|
-        
-        This library is not meant to stand-alone. Instead it defines
-        common helpers (e.g. base ``Client`` classes) used by all of the
-        ``google-cloud-*`` packages.
-        
-        
-        -  `Documentation`_
-        
-        .. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-core.svg
-           :target: https://pypi.org/project/google-cloud-core/
-        .. |versions| image:: 
https://img.shields.io/pypi/pyversions/google-cloud-core.svg
-           :target: https://pypi.org/project/google-cloud-core/
-        .. _Documentation: 
https://googleapis.dev/python/google-cloud-core/latest
-        
-        Quick Start
-        -----------
-        
-        .. code-block:: console
-        
-            $ pip install --upgrade google-cloud-core
-        
-        For more information on setting up your Python development environment,
-        such as installing ``pip`` and ``virtualenv`` on your system, please 
refer
-        to `Python Development Environment Setup Guide`_ for Google Cloud 
Platform.
-        
-        .. _Python Development Environment Setup Guide: 
https://cloud.google.com/python/setup
-        
-        
-        Supported Python Versions
-        -------------------------
-        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 :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
@@ -62,3 +22,46 @@
 Classifier: Topic :: Internet
 Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*
 Provides-Extra: grpc
+License-File: LICENSE
+
+Core Helpers for Google Cloud Python Client Library
+===================================================
+
+|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
+``google-cloud-*`` packages.
+
+
+-  `Documentation`_
+
+.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-core.svg
+   :target: https://pypi.org/project/google-cloud-core/
+.. |versions| image:: 
https://img.shields.io/pypi/pyversions/google-cloud-core.svg
+   :target: https://pypi.org/project/google-cloud-core/
+.. _Documentation: https://googleapis.dev/python/google-cloud-core/latest
+
+Quick Start
+-----------
+
+.. code-block:: console
+
+    $ pip install --upgrade google-cloud-core
+
+For more information on setting up your Python development environment,
+such as installing ``pip`` and ``virtualenv`` on your system, please refer
+to `Python Development Environment Setup Guide`_ for Google Cloud Platform.
+
+.. _Python Development Environment Setup Guide: 
https://cloud.google.com/python/setup
+
+
+Supported Python Versions
+-------------------------
+Python >= 3.6
+
+Deprecated Python Versions
+--------------------------
+Python == 2.7. Python 2.7 support will be removed on January 1, 2020.
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.6.0/tests/unit/test__http.py 
new/google-cloud-core-1.7.2/tests/unit/test__http.py
--- old/google-cloud-core-1.6.0/tests/unit/test__http.py        2021-02-06 
02:19:50.000000000 +0100
+++ new/google-cloud-core-1.7.2/tests/unit/test__http.py        2021-07-27 
20:05:41.000000000 +0200
@@ -134,6 +134,11 @@
     response._content = content
     response.headers = headers
     response.request = requests.Request()
+
+    # Work around requests 'charset_normalizer' idiocy.
+    # See https://github.com/googleapis/python-cloud-core/issues/117
+    response.encoding = "utf-8"
+
     return response
 
 
@@ -186,14 +191,18 @@
         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?prettyPrint=false"])
+        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"])
+        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):
@@ -220,7 +229,9 @@
 
         client = object()
         conn = self._make_mock_one(client)
-        uri = conn.build_api_url("/foo", [("bar", "baz"), ("qux", "quux"), 
("qux", "corge")])
+        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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/google-cloud-core-1.6.0/tests/unit/test_client.py 
new/google-cloud-core-1.7.2/tests/unit/test_client.py
--- old/google-cloud-core-1.6.0/tests/unit/test_client.py       2021-02-06 
02:19:50.000000000 +0100
+++ new/google-cloud-core-1.7.2/tests/unit/test_client.py       2021-07-27 
20:05:41.000000000 +0200
@@ -80,7 +80,7 @@
         from google.api_core.exceptions import DuplicateCredentialArgs
 
         credentials = _make_credentials()
-        client_options = {'credentials_file': '/path/to/creds.json'}
+        client_options = {"credentials_file": "/path/to/creds.json"}
         with self.assertRaises(DuplicateCredentialArgs):
             self._make_one(credentials=credentials, 
client_options=client_options)
 
@@ -92,26 +92,34 @@
 
     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}
+        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))
+        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)
+        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}
+        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)
+        client_obj = self._make_one(
+            credentials=credentials, client_options=client_options
+        )
 
-        self.assertIs(client_obj._credentials, 
credentials.with_quota_project.return_value)
+        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):
@@ -126,32 +134,62 @@
 
         credentials = _make_credentials()
         mock_client_cert_source = mock.Mock()
-        client_options = {'client_cert_source': mock_client_cert_source}
+        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:
+        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)
+            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_info(self):
+        klass = self._get_target_class()
+
+        info = {"dummy": "value", "valid": "json"}
+        constructor_patch = mock.patch(
+            
"google.oauth2.service_account.Credentials.from_service_account_info",
+            return_value=_make_credentials(),
+        )
+
+        with constructor_patch as constructor:
+            client_obj = klass.from_service_account_info(info)
+
+        self.assertIs(client_obj._credentials, constructor.return_value)
+        self.assertIsNone(client_obj._http_internal)
+        constructor.assert_called_once_with(info)
+
+    def test_from_service_account_info_w_explicit_credentials(self):
+        KLASS = self._get_target_class()
+
+        info = {"dummy": "value", "valid": "json"}
+
+        with self.assertRaises(TypeError):
+            KLASS.from_service_account_info(info, 
credentials=mock.sentinel.credentials)
+
     def test_from_service_account_json(self):
         from google.cloud import _helpers
 
         klass = self._get_target_class()
 
-        # Mock both the file opening and the credentials constructor.
         info = {"dummy": "value", "valid": "json"}
-        json_fi = io.StringIO(_helpers._bytes_to_unicode(json.dumps(info)))
-        file_open_patch = mock.patch("io.open", return_value=json_fi)
+        json_file = io.StringIO(_helpers._bytes_to_unicode(json.dumps(info)))
+
+        file_open_patch = mock.patch("io.open", return_value=json_file)
         constructor_patch = mock.patch(
             "google.oauth2.service_account.Credentials." 
"from_service_account_info",
             return_value=_make_credentials(),
@@ -167,13 +205,20 @@
         file_open.assert_called_once_with(mock.sentinel.filename, "r", 
encoding="utf-8")
         constructor.assert_called_once_with(info)
 
-    def test_from_service_account_json_bad_args(self):
-        KLASS = self._get_target_class()
+    def test_close_w__http_internal_none(self):
+        credentials = _make_credentials()
+        client_obj = self._make_one(credentials=credentials, _http=None)
 
-        with self.assertRaises(TypeError):
-            KLASS.from_service_account_json(
-                mock.sentinel.filename, credentials=mock.sentinel.credentials
-            )
+        client_obj.close()  # noraise
+
+    def test_close_w__http_internal_set(self):
+        credentials = _make_credentials()
+        http = mock.Mock(spec=["close"])
+        client_obj = self._make_one(credentials=credentials, _http=http)
+
+        client_obj.close()
+
+        http.close.assert_called_once_with()
 
 
 class Test_ClientProjectMixin(unittest.TestCase):
@@ -190,8 +235,7 @@
         environ = {}
         patch_env = mock.patch("os.environ", new=environ)
         patch_default = mock.patch(
-            "google.cloud.client._determine_default_project",
-            return_value=None,
+            "google.cloud.client._determine_default_project", 
return_value=None,
         )
         with patch_env:
             with patch_default as patched:
@@ -225,8 +269,7 @@
     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,
+            "google.cloud.client._determine_default_project", 
return_value=None,
         )
         with patch_default as patched:
             client = self._make_one(project=explicit_project)
@@ -238,8 +281,7 @@
     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,
+            "google.cloud.client._determine_default_project", 
return_value=None,
         )
         with patch_default as patched:
             client = self._make_one(project=explicit_project)
@@ -251,8 +293,7 @@
     def test_ctor_w_explicit_project_invalid(self):
         explicit_project = object()
         patch_default = mock.patch(
-            "google.cloud.client._determine_default_project",
-            return_value=None,
+            "google.cloud.client._determine_default_project", 
return_value=None,
         )
         with patch_default as patched:
             with self.assertRaises(ValueError):
@@ -291,8 +332,7 @@
         project = "credentials-project-456"
         credentials = self._make_credentials(project_id=project)
         patch_default = mock.patch(
-            "google.cloud.client._determine_default_project",
-            return_value=None,
+            "google.cloud.client._determine_default_project", 
return_value=None,
         )
         with patch_default as patched:
             client = self._make_one(credentials=credentials)
@@ -377,18 +417,78 @@
         PROJECT = u"PROJECT"
         self._explicit_ctor_helper(PROJECT)
 
+    def _from_service_account_info_helper(self, project=None):
+        klass = self._get_target_class()
+
+        default_project = "eye-d-of-project"
+        info = {"dummy": "value", "valid": "json", "project_id": 
default_project}
+        kwargs = {}
+
+        if project is None:
+            expected_project = default_project
+        else:
+            expected_project = project
+            kwargs["project"] = project
+
+        constructor_patch = mock.patch(
+            
"google.oauth2.service_account.Credentials.from_service_account_info",
+            return_value=_make_credentials(),
+        )
+
+        with constructor_patch as constructor:
+            client_obj = klass.from_service_account_info(info, **kwargs)
+
+        self.assertIs(client_obj._credentials, constructor.return_value)
+        self.assertIsNone(client_obj._http_internal)
+        self.assertEqual(client_obj.project, expected_project)
+
+        constructor.assert_called_once_with(info)
+
+    def test_from_service_account_info(self):
+        self._from_service_account_info_helper()
+
+    def test_from_service_account_info_with_project(self):
+        self._from_service_account_info_helper(project="prah-jekt")
+
+    def test_from_service_account_info_with_posarg(self):
+        class Derived(self._get_target_class()):
+            def __init__(self, required, **kwargs):
+                super(Derived, self).__init__(**kwargs)
+                self.required = required
+
+        project = "eye-d-of-project"
+        info = {"dummy": "value", "valid": "json", "project_id": project}
+
+        # Mock both the file opening and the credentials constructor.
+        constructor_patch = mock.patch(
+            
"google.oauth2.service_account.Credentials.from_service_account_info",
+            return_value=_make_credentials(),
+        )
+
+        with constructor_patch as constructor:
+            client_obj = Derived.from_service_account_info(info, "REQUIRED")
+
+        self.assertIsInstance(client_obj, Derived)
+        self.assertIs(client_obj._credentials, constructor.return_value)
+        self.assertIsNone(client_obj._http_internal)
+        self.assertEqual(client_obj.project, project)
+        self.assertEqual(client_obj.required, "REQUIRED")
+
+        # Check that mocks were called as expected.
+        constructor.assert_called_once_with(info)
+
     def _from_service_account_json_helper(self, project=None):
         from google.cloud import _helpers
 
         klass = self._get_target_class()
 
-        info = {"dummy": "value", "valid": "json"}
+        default_project = "eye-d-of-project"
+        info = {"dummy": "value", "valid": "json", "project_id": 
default_project}
         if project is None:
             expected_project = "eye-d-of-project"
         else:
             expected_project = project
 
-        info["project_id"] = expected_project
         # Mock both the file opening and the credentials constructor.
         json_fi = io.StringIO(_helpers._bytes_to_unicode(json.dumps(info)))
         file_open_patch = mock.patch("io.open", return_value=json_fi)
@@ -418,3 +518,38 @@
 
     def test_from_service_account_json_project_set(self):
         self._from_service_account_json_helper(project="prah-jekt")
+
+    def test_from_service_account_json_with_posarg(self):
+        from google.cloud import _helpers
+
+        class Derived(self._get_target_class()):
+            def __init__(self, required, **kwargs):
+                super(Derived, self).__init__(**kwargs)
+                self.required = required
+
+        project = "eye-d-of-project"
+        info = {"dummy": "value", "valid": "json", "project_id": project}
+
+        # Mock both the file opening and the credentials constructor.
+        json_fi = io.StringIO(_helpers._bytes_to_unicode(json.dumps(info)))
+        file_open_patch = mock.patch("io.open", return_value=json_fi)
+        constructor_patch = mock.patch(
+            
"google.oauth2.service_account.Credentials.from_service_account_info",
+            return_value=_make_credentials(),
+        )
+
+        with file_open_patch as file_open:
+            with constructor_patch as constructor:
+                client_obj = Derived.from_service_account_json(
+                    mock.sentinel.filename, "REQUIRED"
+                )
+
+        self.assertIsInstance(client_obj, Derived)
+        self.assertIs(client_obj._credentials, constructor.return_value)
+        self.assertIsNone(client_obj._http_internal)
+        self.assertEqual(client_obj.project, project)
+        self.assertEqual(client_obj.required, "REQUIRED")
+
+        # Check that mocks were called as expected.
+        file_open.assert_called_once_with(mock.sentinel.filename, "r", 
encoding="utf-8")
+        constructor.assert_called_once_with(info)

Reply via email to