Skip to content

Commit 107b21f

Browse files
committed
COMPAT: Add Google BigQuery support for python 3 #11094
1 parent 8ea8968 commit 107b21f

File tree

3 files changed

+51
-42
lines changed

3 files changed

+51
-42
lines changed

doc/source/whatsnew/v0.17.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ Google BigQuery Enhancements
332332
- Added ability to replace an existing table and schema when calling the :func:`pandas.io.gbq.to_gbq` function via the ``if_exists`` argument. See the :ref:`docs <io.bigquery>` for more details (:issue:`8325`).
333333
- ``InvalidColumnOrder`` and ``InvalidPageToken`` in the gbq module will raise ``ValueError`` instead of ``IOError``.
334334
- The ``generate_bq_schema()`` function is now deprecated and will be removed in a future version (:issue:`11121`)
335+
- Update the gbq module to support Python 3 (:issue:`11094`).
335336

336337
.. _whatsnew_0170.enhancements.other:
337338

pandas/io/gbq.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,26 @@
1313
from pandas.tools.merge import concat
1414
from pandas.core.common import PandasError
1515
from pandas.util.decorators import deprecate
16+
from pandas.compat import lzip, bytes_to_str
1617

1718
def _check_google_client_version():
18-
if compat.PY3:
19-
raise NotImplementedError("Google's libraries do not support Python 3 yet")
2019

2120
try:
2221
import pkg_resources
2322

2423
except ImportError:
2524
raise ImportError('Could not import pkg_resources (setuptools).')
2625

26+
if compat.PY3:
27+
google_api_minimum_version = '1.4.1'
28+
else:
29+
google_api_minimum_version = '1.2.0'
30+
2731
_GOOGLE_API_CLIENT_VERSION = pkg_resources.get_distribution('google-api-python-client').version
2832

29-
if StrictVersion(_GOOGLE_API_CLIENT_VERSION) < StrictVersion('1.2.0'):
30-
raise ImportError("pandas requires google-api-python-client >= 1.2.0 for Google "
31-
"BigQuery support, current version " + _GOOGLE_API_CLIENT_VERSION)
33+
if StrictVersion(_GOOGLE_API_CLIENT_VERSION) < StrictVersion(google_api_minimum_version):
34+
raise ImportError("pandas requires google-api-python-client >= {0} for Google BigQuery support, "
35+
"current version {1}".format(google_api_minimum_version, _GOOGLE_API_CLIENT_VERSION))
3236

3337
logger = logging.getLogger('pandas.io.gbq')
3438
logger.setLevel(logging.ERROR)
@@ -161,7 +165,7 @@ def get_service(credentials):
161165
def process_http_error(ex):
162166
# See `BigQuery Troubleshooting Errors <https://cloud.google.com/bigquery/troubleshooting-errors>`__
163167

164-
status = json.loads(ex.content)['error']
168+
status = json.loads(bytes_to_str(ex.content))['error']
165169
errors = status.get('errors', None)
166170

167171
if errors:
@@ -353,10 +357,10 @@ def _parse_data(schema, rows):
353357

354358
fields = schema['fields']
355359
col_types = [field['type'] for field in fields]
356-
col_names = [field['name'].encode('ascii', 'ignore') for field in fields]
360+
col_names = [str(field['name']) for field in fields]
357361
col_dtypes = [dtype_map.get(field['type'], object) for field in fields]
358362
page_array = np.zeros((len(rows),),
359-
dtype=zip(col_names, col_dtypes))
363+
dtype=lzip(col_names, col_dtypes))
360364

361365
for row_num, raw_row in enumerate(rows):
362366
entries = raw_row.get('f', [])

pandas/io/tests/test_gbq.py

+38-34
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,44 @@
3030

3131

3232
def _test_imports():
33-
if not compat.PY3:
33+
global _GOOGLE_API_CLIENT_INSTALLED, _GOOGLE_API_CLIENT_VALID_VERSION, \
34+
_HTTPLIB2_INSTALLED, _SETUPTOOLS_INSTALLED
3435

35-
global _GOOGLE_API_CLIENT_INSTALLED, _GOOGLE_API_CLIENT_VALID_VERSION, \
36-
_HTTPLIB2_INSTALLED, _SETUPTOOLS_INSTALLED
37-
38-
try:
39-
import pkg_resources
40-
_SETUPTOOLS_INSTALLED = True
41-
except ImportError:
42-
_SETUPTOOLS_INSTALLED = False
43-
44-
if _SETUPTOOLS_INSTALLED:
45-
try:
46-
from apiclient.discovery import build
47-
from apiclient.errors import HttpError
36+
try:
37+
import pkg_resources
38+
_SETUPTOOLS_INSTALLED = True
39+
except ImportError:
40+
_SETUPTOOLS_INSTALLED = False
4841

49-
from oauth2client.client import OAuth2WebServerFlow
50-
from oauth2client.client import AccessTokenRefreshError
42+
if compat.PY3:
43+
google_api_minimum_version = '1.4.1'
44+
else:
45+
google_api_minimum_version = '1.2.0'
5146

52-
from oauth2client.file import Storage
53-
from oauth2client.tools import run_flow
54-
_GOOGLE_API_CLIENT_INSTALLED=True
55-
_GOOGLE_API_CLIENT_VERSION = pkg_resources.get_distribution('google-api-python-client').version
47+
if _SETUPTOOLS_INSTALLED:
48+
try:
49+
from apiclient.discovery import build
50+
from apiclient.errors import HttpError
5651

57-
if StrictVersion(_GOOGLE_API_CLIENT_VERSION) >= StrictVersion('1.2.0'):
58-
_GOOGLE_API_CLIENT_VALID_VERSION = True
52+
from oauth2client.client import OAuth2WebServerFlow
53+
from oauth2client.client import AccessTokenRefreshError
5954

60-
except ImportError:
61-
_GOOGLE_API_CLIENT_INSTALLED = False
55+
from oauth2client.file import Storage
56+
from oauth2client.tools import run_flow
57+
_GOOGLE_API_CLIENT_INSTALLED=True
58+
_GOOGLE_API_CLIENT_VERSION = pkg_resources.get_distribution('google-api-python-client').version
6259

60+
if StrictVersion(_GOOGLE_API_CLIENT_VERSION) >= StrictVersion(google_api_minimum_version):
61+
_GOOGLE_API_CLIENT_VALID_VERSION = True
6362

64-
try:
65-
import httplib2
66-
_HTTPLIB2_INSTALLED = True
67-
except ImportError:
68-
_HTTPLIB2_INSTALLED = False
63+
except ImportError:
64+
_GOOGLE_API_CLIENT_INSTALLED = False
6965

70-
if compat.PY3:
71-
raise NotImplementedError("Google's libraries do not support Python 3 yet")
66+
try:
67+
import httplib2
68+
_HTTPLIB2_INSTALLED = True
69+
except ImportError:
70+
_HTTPLIB2_INSTALLED = False
7271

7372
if not _SETUPTOOLS_INSTALLED:
7473
raise ImportError('Could not import pkg_resources (setuptools).')
@@ -77,8 +76,8 @@ def _test_imports():
7776
raise ImportError('Could not import Google API Client.')
7877

7978
if not _GOOGLE_API_CLIENT_VALID_VERSION:
80-
raise ImportError("pandas requires google-api-python-client >= 1.2.0 for Google "
81-
"BigQuery support, current version " + _GOOGLE_API_CLIENT_VERSION)
79+
raise ImportError("pandas requires google-api-python-client >= {0} for Google BigQuery support, "
80+
"current version {1}".format(google_api_minimum_version, _GOOGLE_API_CLIENT_VERSION))
8281

8382
if not _HTTPLIB2_INSTALLED:
8483
raise ImportError("pandas requires httplib2 for Google BigQuery support")
@@ -299,7 +298,12 @@ def test_unicode_string_conversion_and_normalization(self):
299298
{'UNICODE_STRING': [u("\xe9\xfc")]}
300299
)
301300

302-
query = 'SELECT "\xc3\xa9\xc3\xbc" as UNICODE_STRING'
301+
unicode_string = "\xc3\xa9\xc3\xbc"
302+
303+
if compat.PY3:
304+
unicode_string = unicode_string.encode('latin-1').decode('utf8')
305+
306+
query = 'SELECT "{0}" as UNICODE_STRING'.format(unicode_string)
303307

304308
df = gbq.read_gbq(query, project_id=PROJECT_ID)
305309
tm.assert_frame_equal(df, correct_test_datatype)

0 commit comments

Comments
 (0)