Skip to content

Commit 71b7237

Browse files
tonyparthenioujreback
authored andcommitted
Resolve ImportError in read_gbq which appears with oauthclient >= 2.0
closes #12572 closes #12582
1 parent e9fde88 commit 71b7237

File tree

7 files changed

+74
-12
lines changed

7 files changed

+74
-12
lines changed

ci/requirements-2.7.pip

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ blosc
22
httplib2
33
google-api-python-client == 1.2
44
python-gflags == 2.0
5+
oauth2client == 1.5.0
56
pathlib
67
py

ci/requirements-3.4.pip

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ python-dateutil==2.2
22
blosc
33
httplib2
44
google-api-python-client
5+
oauth2client

doc/source/install.rst

+5-3
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,11 @@ Optional Dependencies
267267
<http://www.vergenet.net/~conrad/software/xsel/>`__, or `xclip
268268
<http://sourceforge.net/projects/xclip/>`__: necessary to use
269269
:func:`~pandas.io.clipboard.read_clipboard`. Most package managers on Linux distributions will have ``xclip`` and/or ``xsel`` immediately available for installation.
270-
* Google's `python-gflags <http://code.google.com/p/python-gflags/>`__
271-
and `google-api-python-client <http://github.com/google/google-api-python-client>`__: Needed for :mod:`~pandas.io.gbq`
272-
* `httplib2 <http://pypi.python.org/pypi/httplib2>`__: Needed for :mod:`~pandas.io.gbq`
270+
* Google's `python-gflags <http://code.google.com/p/python-gflags/>`__ ,
271+
`oauth2client <https://github.com/google/oauth2client>`__ ,
272+
`httplib2 <http://pypi.python.org/pypi/httplib2>`__
273+
and `google-api-python-client <http://github.com/google/google-api-python-client>`__
274+
: Needed for :mod:`~pandas.io.gbq`
273275
* One of the following combinations of libraries is needed to use the
274276
top-level :func:`~pandas.io.html.read_html` function:
275277

doc/source/io.rst

+8
Original file line numberDiff line numberDiff line change
@@ -4168,6 +4168,12 @@ DataFrame with a shape and data types derived from the source table.
41684168
Additionally, DataFrames can be inserted into new BigQuery tables or appended
41694169
to existing tables.
41704170

4171+
You will need to install some additional dependencies:
4172+
4173+
- Google's `python-gflags <http://code.google.com/p/python-gflags/>`__
4174+
- `httplib2 <http://pypi.python.org/pypi/httplib2>`__
4175+
- `google-api-python-client <http://github.com/google/google-api-python-client>`__
4176+
41714177
.. warning::
41724178

41734179
To use this module, you will need a valid BigQuery account. Refer to the
@@ -4206,6 +4212,8 @@ is particularly useful when working on remote servers (eg. jupyter iPython noteb
42064212
Additional information on service accounts can be found
42074213
`here <https://developers.google.com/identity/protocols/OAuth2#serviceaccount>`__.
42084214

4215+
You will need to install an additional dependency: `oauth2client <https://github.com/google/oauth2client>`__.
4216+
42094217
.. note::
42104218

42114219
The `'private_key'` parameter can be set to either the file path of the service account key

doc/source/whatsnew/v0.18.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ Other enhancements
511511
- Added ``DataFrame.style.format`` for more flexible formatting of cell values (:issue:`11692`)
512512
- ``DataFrame.select_dtypes`` now allows the ``np.float16`` typecode (:issue:`11990`)
513513
- ``pivot_table()`` now accepts most iterables for the ``values`` parameter (:issue:`12017`)
514-
- Added Google ``BigQuery`` service account authentication support, which enables authentication on remote servers. (:issue:`11881`). For further details see :ref:`here <io.bigquery_authentication>`
514+
- Added Google ``BigQuery`` service account authentication support, which enables authentication on remote servers. (:issue:`11881`, :issue:`12572`). For further details see :ref:`here <io.bigquery_authentication>`
515515
- ``HDFStore`` is now iterable: ``for k in store`` is equivalent to ``for k in store.keys()`` (:issue:`12221`).
516516
- Add missing methods/fields to ``.dt`` for ``Period`` (:issue:`8848`)
517517
- The entire codebase has been ``PEP``-ified (:issue:`12096`)

pandas/io/gbq.py

+34-7
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ def _test_google_api_imports():
5050
from apiclient.errors import HttpError # noqa
5151
from oauth2client.client import AccessTokenRefreshError # noqa
5252
from oauth2client.client import OAuth2WebServerFlow # noqa
53-
from oauth2client.client import SignedJwtAssertionCredentials # noqa
5453
from oauth2client.file import Storage # noqa
5554
from oauth2client.tools import run_flow, argparser # noqa
5655
except ImportError as e:
@@ -179,7 +178,30 @@ def get_user_account_credentials(self):
179178
return credentials
180179

181180
def get_service_account_credentials(self):
182-
from oauth2client.client import SignedJwtAssertionCredentials
181+
# Bug fix for https://github.com/pydata/pandas/issues/12572
182+
# We need to know that a supported version of oauth2client is installed
183+
# Test that either of the following is installed:
184+
# - SignedJwtAssertionCredentials from oauth2client.client
185+
# - ServiceAccountCredentials from oauth2client.service_account
186+
# SignedJwtAssertionCredentials is available in oauthclient < 2.0.0
187+
# ServiceAccountCredentials is available in oauthclient >= 2.0.0
188+
oauth2client_v1 = True
189+
oauth2client_v2 = True
190+
191+
try:
192+
from oauth2client.client import SignedJwtAssertionCredentials
193+
except ImportError:
194+
oauth2client_v1 = False
195+
196+
try:
197+
from oauth2client.service_account import ServiceAccountCredentials
198+
except ImportError:
199+
oauth2client_v2 = False
200+
201+
if not oauth2client_v1 and not oauth2client_v2:
202+
raise ImportError("Missing oauth2client required for BigQuery "
203+
"service account support")
204+
183205
from os.path import isfile
184206

185207
try:
@@ -197,11 +219,16 @@ def get_service_account_credentials(self):
197219
json_key['private_key'] = bytes(
198220
json_key['private_key'], 'UTF-8')
199221

200-
return SignedJwtAssertionCredentials(
201-
json_key['client_email'],
202-
json_key['private_key'],
203-
self.scope,
204-
)
222+
if oauth2client_v1:
223+
return SignedJwtAssertionCredentials(
224+
json_key['client_email'],
225+
json_key['private_key'],
226+
self.scope,
227+
)
228+
else:
229+
return ServiceAccountCredentials.from_json_keyfile_dict(
230+
json_key,
231+
self.scope)
205232
except (KeyError, ValueError, TypeError, AttributeError):
206233
raise InvalidPrivateKeyFormat(
207234
"Private key is missing or invalid. It should be service "

pandas/io/tests/test_gbq.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ def _test_imports():
7777

7878
from oauth2client.client import OAuth2WebServerFlow # noqa
7979
from oauth2client.client import AccessTokenRefreshError # noqa
80-
from oauth2client.client import SignedJwtAssertionCredentials # noqa
8180

8281
from oauth2client.file import Storage # noqa
8382
from oauth2client.tools import run_flow # noqa
@@ -115,6 +114,30 @@ def _test_imports():
115114
raise ImportError(
116115
"pandas requires httplib2 for Google BigQuery support")
117116

117+
# Bug fix for https://github.com/pydata/pandas/issues/12572
118+
# We need to know that a supported version of oauth2client is installed
119+
# Test that either of the following is installed:
120+
# - SignedJwtAssertionCredentials from oauth2client.client
121+
# - ServiceAccountCredentials from oauth2client.service_account
122+
# SignedJwtAssertionCredentials is available in oauthclient < 2.0.0
123+
# ServiceAccountCredentials is available in oauthclient >= 2.0.0
124+
oauth2client_v1 = True
125+
oauth2client_v2 = True
126+
127+
try:
128+
from oauth2client.client import SignedJwtAssertionCredentials # noqa
129+
except ImportError:
130+
oauth2client_v1 = False
131+
132+
try:
133+
from oauth2client.service_account import ServiceAccountCredentials # noqa
134+
except ImportError:
135+
oauth2client_v2 = False
136+
137+
if not oauth2client_v1 and not oauth2client_v2:
138+
raise ImportError("Missing oauth2client required for BigQuery "
139+
"service account support")
140+
118141

119142
def test_requirements():
120143
try:

0 commit comments

Comments
 (0)