diff --git a/ci/requirements-3.5-0.18.1.pip b/ci/requirements-3.5-0.18.1.pip index 5fcc2d61..68ac370d 100644 --- a/ci/requirements-3.5-0.18.1.pip +++ b/ci/requirements-3.5-0.18.1.pip @@ -1,4 +1,4 @@ google-auth==1.4.1 google-auth-oauthlib==0.0.1 mock -google-cloud-bigquery==0.32.0 +google-cloud-bigquery==0.29.0 diff --git a/pandas_gbq/_query.py b/pandas_gbq/_query.py new file mode 100644 index 00000000..b8abc6cf --- /dev/null +++ b/pandas_gbq/_query.py @@ -0,0 +1,13 @@ + +import pkg_resources +from google.cloud import bigquery + + +# Version with query config breaking change. +BIGQUERY_CONFIG_VERSION = pkg_resources.parse_version('0.32.0.dev1') + + +def query_config(resource, installed_version): + if installed_version < BIGQUERY_CONFIG_VERSION: + return bigquery.QueryJobConfig.from_api_repr(resource.get('query', {})) + return bigquery.QueryJobConfig.from_api_repr(resource) diff --git a/pandas_gbq/gbq.py b/pandas_gbq/gbq.py index 3b13a8de..f8a9aa63 100644 --- a/pandas_gbq/gbq.py +++ b/pandas_gbq/gbq.py @@ -13,7 +13,11 @@ logger = logging.getLogger(__name__) +BIGQUERY_INSTALLED_VERSION = None + + def _check_google_client_version(): + global BIGQUERY_INSTALLED_VERSION try: import pkg_resources @@ -22,15 +26,15 @@ def _check_google_client_version(): raise ImportError('Could not import pkg_resources (setuptools).') # https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/bigquery/CHANGELOG.md - bigquery_minimum_version = pkg_resources.parse_version('0.32.0.dev1') - bigquery_installed_version = pkg_resources.get_distribution( + bigquery_minimum_version = pkg_resources.parse_version('0.29.0') + BIGQUERY_INSTALLED_VERSION = pkg_resources.get_distribution( 'google-cloud-bigquery').parsed_version - if bigquery_installed_version < bigquery_minimum_version: + if BIGQUERY_INSTALLED_VERSION < bigquery_minimum_version: raise ImportError( 'pandas-gbq requires google-cloud-bigquery >= {0}, ' 'current version {1}'.format( - bigquery_minimum_version, bigquery_installed_version)) + bigquery_minimum_version, BIGQUERY_INSTALLED_VERSION)) def _test_google_api_imports(): @@ -444,8 +448,8 @@ def process_http_error(ex): def run_query(self, query, **kwargs): from google.auth.exceptions import RefreshError - from google.cloud.bigquery import QueryJobConfig from concurrent.futures import TimeoutError + from pandas_gbq import _query job_config = { 'query': { @@ -467,12 +471,11 @@ def run_query(self, query, **kwargs): del config['query']['query'] self._start_timer() - try: + try: logger.info('Requesting query... ') query_reply = self.client.query( - query, - job_config=QueryJobConfig.from_api_repr(job_config)) + query, job_config=_query.query_config(job_config)) logger.info('ok.\nQuery running...') except (RefreshError, ValueError): if self.private_key: diff --git a/pandas_gbq/tests/test__query.py b/pandas_gbq/tests/test__query.py new file mode 100644 index 00000000..43ab00f3 --- /dev/null +++ b/pandas_gbq/tests/test__query.py @@ -0,0 +1,57 @@ + +import pkg_resources + +import mock + + +@mock.patch('google.cloud.bigquery.QueryJobConfig') +def test_query_config_w_old_bq_version(mock_config): + from pandas_gbq._query import query_config + + old_version = pkg_resources.parse_version('0.29.0') + query_config({'query': {'useLegacySql': False}}, old_version) + mock_config.from_api_repr.assert_called_once_with({'useLegacySql': False}) + + +@mock.patch('google.cloud.bigquery.QueryJobConfig') +def test_query_config_w_dev_bq_version(mock_config): + from pandas_gbq._query import query_config + + dev_version = pkg_resources.parse_version('0.32.0.dev1') + query_config( + { + 'query': { + 'useLegacySql': False, + }, + 'labels': {'key': 'value'}, + }, + dev_version) + mock_config.from_api_repr.assert_called_once_with( + { + 'query': { + 'useLegacySql': False, + }, + 'labels': {'key': 'value'}, + }) + + +@mock.patch('google.cloud.bigquery.QueryJobConfig') +def test_query_config_w_new_bq_version(mock_config): + from pandas_gbq._query import query_config + + dev_version = pkg_resources.parse_version('1.0.0') + query_config( + { + 'query': { + 'useLegacySql': False, + }, + 'labels': {'key': 'value'}, + }, + dev_version) + mock_config.from_api_repr.assert_called_once_with( + { + 'query': { + 'useLegacySql': False, + }, + 'labels': {'key': 'value'}, + })