We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Discussion] oauth2client credentials in a post-oauth2client world.
We recently switched `core` to use [`google-auth`](https://google-auth.readthedocs.io) in #2639 and completely removed support for `oauth2client`.

It is possible that some users are explicitly passing `oauth2client` credentials into `Client` constructors, e.g.:

```python
credentials = oauth2client.contrib.gce.AppAppsertionCredentials()
storage_client = storage.Client(credentials=credentials)
```

After `google-cloud-core==0.22.0` is released this code will no longer work. Only credentials from `google-auth` will work. There is a potential that we could break some user code and there may be some valid reasons for sticking with oauth2client in the near-term (user credentials and storage, for example).

`google-auth` offers a way to [`convert`](https://github.com/GoogleCloudPlatform/google-auth-library-python/blob/443df66cb6e7960205c1d2108e67220d27408efe/google/auth/_oauth2client.py#L136) credentials:

```python
import google.auth._oauth2client

new_credentials = google.auth._oauth2client.convert(old_credentials)
```

We have two options:

1. Tell users who still want to use oauth2client to use `google.auth._oauth2client` to convert their credentials.
2. Add code in our `Client` base class to automatically convert credentials and issue a warning.

I strongly prefer (1) so that we do not prolong oauth2client's lifetime and so that we can more quickly free ourselves to switch http libraries.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `core/google/cloud/client.py`
Content:
```
1 # Copyright 2015 Google Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """Base classes for client used to interact with Google Cloud APIs."""
16 
17 from google.oauth2 import service_account
18 import six
19 
20 from google.cloud._helpers import _determine_default_project
21 from google.cloud._http import Connection
22 from google.cloud.credentials import get_credentials
23 
24 
25 class _ClientFactoryMixin(object):
26     """Mixin to allow factories that create credentials.
27 
28     .. note::
29 
30         This class is virtual.
31     """
32 
33     @classmethod
34     def from_service_account_json(cls, json_credentials_path, *args, **kwargs):
35         """Factory to retrieve JSON credentials while creating client.
36 
37         :type json_credentials_path: str
38         :param json_credentials_path: The path to a private key file (this file
39                                       was given to you when you created the
40                                       service account). This file must contain
41                                       a JSON object with a private key and
42                                       other credentials information (downloaded
43                                       from the Google APIs console).
44 
45         :type args: tuple
46         :param args: Remaining positional arguments to pass to constructor.
47 
48         :type kwargs: dict
49         :param kwargs: Remaining keyword arguments to pass to constructor.
50 
51         :rtype: :class:`google.cloud.pubsub.client.Client`
52         :returns: The client created with the retrieved JSON credentials.
53         :raises: :class:`TypeError` if there is a conflict with the kwargs
54                  and the credentials created by the factory.
55         """
56         if 'credentials' in kwargs:
57             raise TypeError('credentials must not be in keyword arguments')
58         credentials = service_account.Credentials.from_service_account_file(
59             json_credentials_path)
60         kwargs['credentials'] = credentials
61         return cls(*args, **kwargs)
62 
63 
64 class Client(_ClientFactoryMixin):
65     """Client to bundle configuration needed for API requests.
66 
67     Assumes that the associated ``_connection_class`` only accepts
68     ``http`` and ``credentials`` in its constructor.
69 
70     :type credentials: :class:`google.auth.credentials.Credentials` or
71                        :class:`NoneType`
72     :param credentials: The OAuth2 Credentials to use for the connection
73                         owned by this client. If not passed (and if no ``http``
74                         object is passed), falls back to the default inferred
75                         from the environment.
76 
77     :type http: :class:`httplib2.Http` or class that defines ``request()``.
78     :param http: An optional HTTP object to make requests. If not passed, an
79                  ``http`` object is created that is bound to the
80                  ``credentials`` for the current object.
81     """
82 
83     _connection_class = Connection
84 
85     def __init__(self, credentials=None, http=None):
86         if credentials is None and http is None:
87             credentials = get_credentials()
88         self._connection = self._connection_class(
89             credentials=credentials, http=http)
90 
91 
92 class _ClientProjectMixin(object):
93     """Mixin to allow setting the project on the client.
94 
95     :type project: str
96     :param project: the project which the client acts on behalf of. If not
97                     passed falls back to the default inferred from the
98                     environment.
99 
100     :raises: :class:`EnvironmentError` if the project is neither passed in nor
101              set in the environment. :class:`ValueError` if the project value
102              is invalid.
103     """
104 
105     def __init__(self, project=None):
106         project = self._determine_default(project)
107         if project is None:
108             raise EnvironmentError('Project was not passed and could not be '
109                                    'determined from the environment.')
110         if isinstance(project, six.binary_type):
111             project = project.decode('utf-8')
112         if not isinstance(project, six.string_types):
113             raise ValueError('Project must be a string.')
114         self.project = project
115 
116     @staticmethod
117     def _determine_default(project):
118         """Helper:  use default project detection."""
119         return _determine_default_project(project)
120 
121 
122 class JSONClient(Client, _ClientProjectMixin):
123     """Client for Google JSON-based API.
124 
125     Assumes such APIs use the ``project`` and the client needs to store this
126     value.
127 
128     :type project: str
129     :param project: the project which the client acts on behalf of. If not
130                     passed falls back to the default inferred from the
131                     environment.
132 
133     :type credentials: :class:`google.auth.credentials.Credentials` or
134                        :class:`NoneType`
135     :param credentials: The OAuth2 Credentials to use for the connection
136                         owned by this client. If not passed (and if no ``http``
137                         object is passed), falls back to the default inferred
138                         from the environment.
139 
140     :type http: :class:`httplib2.Http` or class that defines ``request()``.
141     :param http: An optional HTTP object to make requests. If not passed, an
142                  ``http`` object is created that is bound to the
143                  ``credentials`` for the current object.
144 
145     :raises: :class:`ValueError` if the project is neither passed in nor
146              set in the environment.
147     """
148 
149     def __init__(self, project=None, credentials=None, http=None):
150         _ClientProjectMixin.__init__(self, project=project)
151         Client.__init__(self, credentials=credentials, http=http)
152
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/core/google/cloud/client.py b/core/google/cloud/client.py
--- a/core/google/cloud/client.py
+++ b/core/google/cloud/client.py
@@ -14,6 +14,7 @@
 
 """Base classes for client used to interact with Google Cloud APIs."""
 
+import google.auth.credentials
 from google.oauth2 import service_account
 import six
 
@@ -22,6 +23,13 @@
 from google.cloud.credentials import get_credentials
 
 
+_GOOGLE_AUTH_CREDENTIALS_HELP = (
+    'This library only supports credentials from google-auth-library-python. '
+    'See https://google-cloud-python.readthedocs.io/en/latest/'
+    'google-cloud-auth.html for help on authentication with this library.'
+)
+
+
 class _ClientFactoryMixin(object):
     """Mixin to allow factories that create credentials.
 
@@ -83,6 +91,10 @@
     _connection_class = Connection
 
     def __init__(self, credentials=None, http=None):
+        if (credentials is not None and
+                not isinstance(
+                    credentials, google.auth.credentials.Credentials)):
+            raise ValueError(_GOOGLE_AUTH_CREDENTIALS_HELP)
         if credentials is None and http is None:
             credentials = get_credentials()
         self._connection = self._connection_class(

{"golden_diff": "diff --git a/core/google/cloud/client.py b/core/google/cloud/client.py\n--- a/core/google/cloud/client.py\n+++ b/core/google/cloud/client.py\n@@ -14,6 +14,7 @@\n \n \"\"\"Base classes for client used to interact with Google Cloud APIs.\"\"\"\n \n+import google.auth.credentials\n from google.oauth2 import service_account\n import six\n \n@@ -22,6 +23,13 @@\n from google.cloud.credentials import get_credentials\n \n \n+_GOOGLE_AUTH_CREDENTIALS_HELP = (\n+    'This library only supports credentials from google-auth-library-python. '\n+    'See https://google-cloud-python.readthedocs.io/en/latest/'\n+    'google-cloud-auth.html for help on authentication with this library.'\n+)\n+\n+\n class _ClientFactoryMixin(object):\n     \"\"\"Mixin to allow factories that create credentials.\n \n@@ -83,6 +91,10 @@\n     _connection_class = Connection\n \n     def __init__(self, credentials=None, http=None):\n+        if (credentials is not None and\n+                not isinstance(\n+                    credentials, google.auth.credentials.Credentials)):\n+            raise ValueError(_GOOGLE_AUTH_CREDENTIALS_HELP)\n         if credentials is None and http is None:\n             credentials = get_credentials()\n         self._connection = self._connection_class(\n", "issue": "[Discussion] oauth2client credentials in a post-oauth2client world.\nWe recently switched `core` to use [`google-auth`](https://google-auth.readthedocs.io) in #2639 and completely removed support for `oauth2client`.\r\n\r\nIt is possible that some users are explicitly passing `oauth2client` credentials into `Client` constructors, e.g.:\r\n\r\n```python\r\ncredentials = oauth2client.contrib.gce.AppAppsertionCredentials()\r\nstorage_client = storage.Client(credentials=credentials)\r\n```\r\n\r\nAfter `google-cloud-core==0.22.0` is released this code will no longer work. Only credentials from `google-auth` will work. There is a potential that we could break some user code and there may be some valid reasons for sticking with oauth2client in the near-term (user credentials and storage, for example).\r\n\r\n`google-auth` offers a way to [`convert`](https://github.com/GoogleCloudPlatform/google-auth-library-python/blob/443df66cb6e7960205c1d2108e67220d27408efe/google/auth/_oauth2client.py#L136) credentials:\r\n\r\n```python\r\nimport google.auth._oauth2client\r\n\r\nnew_credentials = google.auth._oauth2client.convert(old_credentials)\r\n```\r\n\r\nWe have two options:\r\n\r\n1. Tell users who still want to use oauth2client to use `google.auth._oauth2client` to convert their credentials.\r\n2. Add code in our `Client` base class to automatically convert credentials and issue a warning.\r\n\r\nI strongly prefer (1) so that we do not prolong oauth2client's lifetime and so that we can more quickly free ourselves to switch http libraries.\n", "before_files": [{"content": "# Copyright 2015 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Base classes for client used to interact with Google Cloud APIs.\"\"\"\n\nfrom google.oauth2 import service_account\nimport six\n\nfrom google.cloud._helpers import _determine_default_project\nfrom google.cloud._http import Connection\nfrom google.cloud.credentials import get_credentials\n\n\nclass _ClientFactoryMixin(object):\n    \"\"\"Mixin to allow factories that create credentials.\n\n    .. note::\n\n        This class is virtual.\n    \"\"\"\n\n    @classmethod\n    def from_service_account_json(cls, json_credentials_path, *args, **kwargs):\n        \"\"\"Factory to retrieve JSON credentials while creating client.\n\n        :type json_credentials_path: str\n        :param json_credentials_path: The path to a private key file (this file\n                                      was given to you when you created the\n                                      service account). This file must contain\n                                      a JSON object with a private key and\n                                      other credentials information (downloaded\n                                      from the Google APIs console).\n\n        :type args: tuple\n        :param args: Remaining positional arguments to pass to constructor.\n\n        :type kwargs: dict\n        :param kwargs: Remaining keyword arguments to pass to constructor.\n\n        :rtype: :class:`google.cloud.pubsub.client.Client`\n        :returns: The client created with the retrieved JSON credentials.\n        :raises: :class:`TypeError` if there is a conflict with the kwargs\n                 and the credentials created by the factory.\n        \"\"\"\n        if 'credentials' in kwargs:\n            raise TypeError('credentials must not be in keyword arguments')\n        credentials = service_account.Credentials.from_service_account_file(\n            json_credentials_path)\n        kwargs['credentials'] = credentials\n        return cls(*args, **kwargs)\n\n\nclass Client(_ClientFactoryMixin):\n    \"\"\"Client to bundle configuration needed for API requests.\n\n    Assumes that the associated ``_connection_class`` only accepts\n    ``http`` and ``credentials`` in its constructor.\n\n    :type credentials: :class:`google.auth.credentials.Credentials` or\n                       :class:`NoneType`\n    :param credentials: The OAuth2 Credentials to use for the connection\n                        owned by this client. If not passed (and if no ``http``\n                        object is passed), falls back to the default inferred\n                        from the environment.\n\n    :type http: :class:`httplib2.Http` or class that defines ``request()``.\n    :param http: An optional HTTP object to make requests. If not passed, an\n                 ``http`` object is created that is bound to the\n                 ``credentials`` for the current object.\n    \"\"\"\n\n    _connection_class = Connection\n\n    def __init__(self, credentials=None, http=None):\n        if credentials is None and http is None:\n            credentials = get_credentials()\n        self._connection = self._connection_class(\n            credentials=credentials, http=http)\n\n\nclass _ClientProjectMixin(object):\n    \"\"\"Mixin to allow setting the project on the client.\n\n    :type project: str\n    :param project: the project which the client acts on behalf of. If not\n                    passed falls back to the default inferred from the\n                    environment.\n\n    :raises: :class:`EnvironmentError` if the project is neither passed in nor\n             set in the environment. :class:`ValueError` if the project value\n             is invalid.\n    \"\"\"\n\n    def __init__(self, project=None):\n        project = self._determine_default(project)\n        if project is None:\n            raise EnvironmentError('Project was not passed and could not be '\n                                   'determined from the environment.')\n        if isinstance(project, six.binary_type):\n            project = project.decode('utf-8')\n        if not isinstance(project, six.string_types):\n            raise ValueError('Project must be a string.')\n        self.project = project\n\n    @staticmethod\n    def _determine_default(project):\n        \"\"\"Helper:  use default project detection.\"\"\"\n        return _determine_default_project(project)\n\n\nclass JSONClient(Client, _ClientProjectMixin):\n    \"\"\"Client for Google JSON-based API.\n\n    Assumes such APIs use the ``project`` and the client needs to store this\n    value.\n\n    :type project: str\n    :param project: the project which the client acts on behalf of. If not\n                    passed falls back to the default inferred from the\n                    environment.\n\n    :type credentials: :class:`google.auth.credentials.Credentials` or\n                       :class:`NoneType`\n    :param credentials: The OAuth2 Credentials to use for the connection\n                        owned by this client. If not passed (and if no ``http``\n                        object is passed), falls back to the default inferred\n                        from the environment.\n\n    :type http: :class:`httplib2.Http` or class that defines ``request()``.\n    :param http: An optional HTTP object to make requests. If not passed, an\n                 ``http`` object is created that is bound to the\n                 ``credentials`` for the current object.\n\n    :raises: :class:`ValueError` if the project is neither passed in nor\n             set in the environment.\n    \"\"\"\n\n    def __init__(self, project=None, credentials=None, http=None):\n        _ClientProjectMixin.__init__(self, project=project)\n        Client.__init__(self, credentials=credentials, http=http)\n", "path": "core/google/cloud/client.py"}], "after_files": [{"content": "# Copyright 2015 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Base classes for client used to interact with Google Cloud APIs.\"\"\"\n\nimport google.auth.credentials\nfrom google.oauth2 import service_account\nimport six\n\nfrom google.cloud._helpers import _determine_default_project\nfrom google.cloud._http import Connection\nfrom google.cloud.credentials import get_credentials\n\n\n_GOOGLE_AUTH_CREDENTIALS_HELP = (\n    'This library only supports credentials from google-auth-library-python. '\n    'See https://google-cloud-python.readthedocs.io/en/latest/'\n    'google-cloud-auth.html for help on authentication with this library.'\n)\n\n\nclass _ClientFactoryMixin(object):\n    \"\"\"Mixin to allow factories that create credentials.\n\n    .. note::\n\n        This class is virtual.\n    \"\"\"\n\n    @classmethod\n    def from_service_account_json(cls, json_credentials_path, *args, **kwargs):\n        \"\"\"Factory to retrieve JSON credentials while creating client.\n\n        :type json_credentials_path: str\n        :param json_credentials_path: The path to a private key file (this file\n                                      was given to you when you created the\n                                      service account). This file must contain\n                                      a JSON object with a private key and\n                                      other credentials information (downloaded\n                                      from the Google APIs console).\n\n        :type args: tuple\n        :param args: Remaining positional arguments to pass to constructor.\n\n        :type kwargs: dict\n        :param kwargs: Remaining keyword arguments to pass to constructor.\n\n        :rtype: :class:`google.cloud.pubsub.client.Client`\n        :returns: The client created with the retrieved JSON credentials.\n        :raises: :class:`TypeError` if there is a conflict with the kwargs\n                 and the credentials created by the factory.\n        \"\"\"\n        if 'credentials' in kwargs:\n            raise TypeError('credentials must not be in keyword arguments')\n        credentials = service_account.Credentials.from_service_account_file(\n            json_credentials_path)\n        kwargs['credentials'] = credentials\n        return cls(*args, **kwargs)\n\n\nclass Client(_ClientFactoryMixin):\n    \"\"\"Client to bundle configuration needed for API requests.\n\n    Assumes that the associated ``_connection_class`` only accepts\n    ``http`` and ``credentials`` in its constructor.\n\n    :type credentials: :class:`google.auth.credentials.Credentials` or\n                       :class:`NoneType`\n    :param credentials: The OAuth2 Credentials to use for the connection\n                        owned by this client. If not passed (and if no ``http``\n                        object is passed), falls back to the default inferred\n                        from the environment.\n\n    :type http: :class:`httplib2.Http` or class that defines ``request()``.\n    :param http: An optional HTTP object to make requests. If not passed, an\n                 ``http`` object is created that is bound to the\n                 ``credentials`` for the current object.\n    \"\"\"\n\n    _connection_class = Connection\n\n    def __init__(self, credentials=None, http=None):\n        if (credentials is not None and\n                not isinstance(\n                    credentials, google.auth.credentials.Credentials)):\n            raise ValueError(_GOOGLE_AUTH_CREDENTIALS_HELP)\n        if credentials is None and http is None:\n            credentials = get_credentials()\n        self._connection = self._connection_class(\n            credentials=credentials, http=http)\n\n\nclass _ClientProjectMixin(object):\n    \"\"\"Mixin to allow setting the project on the client.\n\n    :type project: str\n    :param project: the project which the client acts on behalf of. If not\n                    passed falls back to the default inferred from the\n                    environment.\n\n    :raises: :class:`EnvironmentError` if the project is neither passed in nor\n             set in the environment. :class:`ValueError` if the project value\n             is invalid.\n    \"\"\"\n\n    def __init__(self, project=None):\n        project = self._determine_default(project)\n        if project is None:\n            raise EnvironmentError('Project was not passed and could not be '\n                                   'determined from the environment.')\n        if isinstance(project, six.binary_type):\n            project = project.decode('utf-8')\n        if not isinstance(project, six.string_types):\n            raise ValueError('Project must be a string.')\n        self.project = project\n\n    @staticmethod\n    def _determine_default(project):\n        \"\"\"Helper:  use default project detection.\"\"\"\n        return _determine_default_project(project)\n\n\nclass JSONClient(Client, _ClientProjectMixin):\n    \"\"\"Client for Google JSON-based API.\n\n    Assumes such APIs use the ``project`` and the client needs to store this\n    value.\n\n    :type project: str\n    :param project: the project which the client acts on behalf of. If not\n                    passed falls back to the default inferred from the\n                    environment.\n\n    :type credentials: :class:`google.auth.credentials.Credentials` or\n                       :class:`NoneType`\n    :param credentials: The OAuth2 Credentials to use for the connection\n                        owned by this client. If not passed (and if no ``http``\n                        object is passed), falls back to the default inferred\n                        from the environment.\n\n    :type http: :class:`httplib2.Http` or class that defines ``request()``.\n    :param http: An optional HTTP object to make requests. If not passed, an\n                 ``http`` object is created that is bound to the\n                 ``credentials`` for the current object.\n\n    :raises: :class:`ValueError` if the project is neither passed in nor\n             set in the environment.\n    \"\"\"\n\n    def __init__(self, project=None, credentials=None, http=None):\n        _ClientProjectMixin.__init__(self, project=project)\n        Client.__init__(self, credentials=credentials, http=http)\n", "path": "core/google/cloud/client.py"}]}