diff --git a/ci/requirements-2.7.pip b/ci/requirements-2.7.pip index 9bc533110cea3..54596ad2a8169 100644 --- a/ci/requirements-2.7.pip +++ b/ci/requirements-2.7.pip @@ -2,5 +2,6 @@ blosc httplib2 google-api-python-client == 1.2 python-gflags == 2.0 +oauth2client == 1.5.0 pathlib py diff --git a/ci/requirements-3.4.pip b/ci/requirements-3.4.pip index 62be867437af1..55986a0220bf0 100644 --- a/ci/requirements-3.4.pip +++ b/ci/requirements-3.4.pip @@ -2,3 +2,4 @@ python-dateutil==2.2 blosc httplib2 google-api-python-client +oauth2client diff --git a/doc/source/install.rst b/doc/source/install.rst index 11b9115aa9c81..c1950ee7bf76c 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -267,9 +267,11 @@ Optional Dependencies `__, or `xclip `__: necessary to use :func:`~pandas.io.clipboard.read_clipboard`. Most package managers on Linux distributions will have ``xclip`` and/or ``xsel`` immediately available for installation. -* Google's `python-gflags `__ - and `google-api-python-client `__: Needed for :mod:`~pandas.io.gbq` -* `httplib2 `__: Needed for :mod:`~pandas.io.gbq` +* Google's `python-gflags `__ , + `oauth2client `__ , + `httplib2 `__ + and `google-api-python-client `__ + : Needed for :mod:`~pandas.io.gbq` * One of the following combinations of libraries is needed to use the top-level :func:`~pandas.io.html.read_html` function: diff --git a/doc/source/whatsnew/v0.18.0.txt b/doc/source/whatsnew/v0.18.0.txt index 90ded17286c9f..acd9533165c6d 100644 --- a/doc/source/whatsnew/v0.18.0.txt +++ b/doc/source/whatsnew/v0.18.0.txt @@ -1271,3 +1271,4 @@ Bug Fixes - Bug when specifying a UTC ``DatetimeIndex`` by setting ``utc=True`` in ``.to_datetime`` (:issue:`11934`) - Bug when increasing the buffer size of CSV reader in ``read_csv`` (:issue:`12494`) - Bug when setting columns of a ``DataFrame`` with duplicate column names (:issue:`12344`) +- Resolve ImportError in ``read_gbq`` which appears with oauthclient >= 2.0.0 (:issue:`12572`) diff --git a/pandas/io/gbq.py b/pandas/io/gbq.py index c7481a953e47b..e706434f29dc5 100644 --- a/pandas/io/gbq.py +++ b/pandas/io/gbq.py @@ -50,7 +50,6 @@ def _test_google_api_imports(): from apiclient.errors import HttpError # noqa from oauth2client.client import AccessTokenRefreshError # noqa from oauth2client.client import OAuth2WebServerFlow # noqa - from oauth2client.client import SignedJwtAssertionCredentials # noqa from oauth2client.file import Storage # noqa from oauth2client.tools import run_flow, argparser # noqa except ImportError as e: @@ -179,7 +178,30 @@ def get_user_account_credentials(self): return credentials def get_service_account_credentials(self): - from oauth2client.client import SignedJwtAssertionCredentials + # Bug fix for https://github.com/pydata/pandas/issues/12572 + # We need to know that a supported version of oauth2client is installed + # Test that either of the following is installed: + # - SignedJwtAssertionCredentials from oauth2client.client + # - ServiceAccountCredentials from oauth2client.service_account + # SignedJwtAssertionCredentials is available in oauthclient < 2.0.0 + # ServiceAccountCredentials is available in oauthclient >= 2.0.0 + oauth2client_v1 = True + oauth2client_v2 = True + + try: + from oauth2client.client import SignedJwtAssertionCredentials + except ImportError: + oauth2client_v1 = False + + try: + from oauth2client.service_account import ServiceAccountCredentials + except ImportError: + oauth2client_v2 = False + + if not oauth2client_v1 and not oauth2client_v2: + raise ImportError("Missing oauth2client required for BigQuery " + "service account support") + from os.path import isfile try: @@ -197,11 +219,16 @@ def get_service_account_credentials(self): json_key['private_key'] = bytes( json_key['private_key'], 'UTF-8') - return SignedJwtAssertionCredentials( - json_key['client_email'], - json_key['private_key'], - self.scope, - ) + if oauth2client_v1: + return SignedJwtAssertionCredentials( + json_key['client_email'], + json_key['private_key'], + self.scope, + ) + else: + return ServiceAccountCredentials.from_json_keyfile_dict( + json_key, + self.scope) except (KeyError, ValueError, TypeError, AttributeError): raise InvalidPrivateKeyFormat( "Private key is missing or invalid. It should be service " diff --git a/pandas/io/tests/test_gbq.py b/pandas/io/tests/test_gbq.py index 5a1c2d63af365..865b7e8d689c0 100644 --- a/pandas/io/tests/test_gbq.py +++ b/pandas/io/tests/test_gbq.py @@ -77,7 +77,6 @@ def _test_imports(): from oauth2client.client import OAuth2WebServerFlow # noqa from oauth2client.client import AccessTokenRefreshError # noqa - from oauth2client.client import SignedJwtAssertionCredentials # noqa from oauth2client.file import Storage # noqa from oauth2client.tools import run_flow # noqa @@ -115,6 +114,30 @@ def _test_imports(): raise ImportError( "pandas requires httplib2 for Google BigQuery support") + # Bug fix for https://github.com/pydata/pandas/issues/12572 + # We need to know that a supported version of oauth2client is installed + # Test that either of the following is installed: + # - SignedJwtAssertionCredentials from oauth2client.client + # - ServiceAccountCredentials from oauth2client.service_account + # SignedJwtAssertionCredentials is available in oauthclient < 2.0.0 + # ServiceAccountCredentials is available in oauthclient >= 2.0.0 + oauth2client_v1 = True + oauth2client_v2 = True + + try: + from oauth2client.client import SignedJwtAssertionCredentials # noqa + except ImportError: + oauth2client_v1 = False + + try: + from oauth2client.service_account import ServiceAccountCredentials # noqa + except ImportError: + oauth2client_v2 = False + + if not oauth2client_v1 and not oauth2client_v2: + raise ImportError("Missing oauth2client required for BigQuery " + "service account support") + def test_requirements(): try: