Skip to content

Commit a1af7de

Browse files
committed
Merge pull request #91 from jasonab/google-credentials
Upgrade to latest OAuth library(2.0.2) and Google Python library (1.5.0)
2 parents 44e0b78 + bfbfde6 commit a1af7de

File tree

2 files changed

+67
-64
lines changed

2 files changed

+67
-64
lines changed

bigquery/client.py

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
from collections import defaultdict
55
from datetime import datetime, timedelta
66
from hashlib import sha256
7+
from io import StringIO
78
from time import sleep, time
89

9-
import httplib2
1010
import six
11-
from apiclient.discovery import build, DISCOVERY_URI
12-
from apiclient.errors import HttpError
13-
1411
from bigquery.errors import (BigQueryTimeoutException, JobExecutingException,
1512
JobInsertException, UnfinishedQueryException)
1613
from bigquery.schema_builder import schema_from_record
14+
from googleapiclient.discovery import build, DISCOVERY_URI
15+
from googleapiclient.errors import HttpError
16+
from httplib2 import Http
1717

18-
BIGQUERY_SCOPE = 'https://www.googleapis.com/auth/bigquery'
19-
BIGQUERY_SCOPE_READ_ONLY = 'https://www.googleapis.com/auth/bigquery.readonly'
18+
BIGQUERY_SCOPE = ['https://www.googleapis.com/auth/bigquery']
19+
BIGQUERY_SCOPE_READ_ONLY = ['https://www.googleapis.com/auth/bigquery.readonly']
2020

2121
CACHE_TIMEOUT = timedelta(seconds=30)
2222

@@ -90,56 +90,63 @@ def get_client(project_id, credentials=None,
9090
"""
9191

9292
if not credentials:
93-
assert (service_account and (private_key or private_key_file)) or (json_key or json_key_file), \
93+
assert (service_account and (private_key or private_key_file)) or (
94+
json_key or json_key_file), \
9495
'Must provide AssertionCredentials or service account and P12 key or JSON key'
9596

9697
if service_url is None:
9798
service_url = DISCOVERY_URI
9899

100+
scope = BIGQUERY_SCOPE_READ_ONLY if readonly else BIGQUERY_SCOPE
101+
99102
if private_key_file:
100-
with open(private_key_file, 'rb') as key_file:
101-
private_key = key_file.read()
103+
credentials = _credentials().from_p12_keyfile(service_account,
104+
private_key_file,
105+
scopes=scope)
106+
107+
if private_key:
108+
try:
109+
if isinstance(private_key, basestring):
110+
private_key = private_key.decode('utf-8')
111+
except NameError:
112+
# python3 -- private_key is already unicode
113+
pass
114+
credentials = _credentials().from_p12_keyfile_buffer(
115+
service_account,
116+
StringIO(private_key),
117+
scopes=scope)
102118

103119
if json_key_file:
104-
with open(json_key_file, 'r') as key_file:
105-
json_key = json.load(key_file)
120+
credentials = _credentials().from_json_keyfile_name(json_key_file,
121+
scopes=scope)
106122

107123
if json_key:
108-
service_account = json_key['client_email']
109-
private_key = json_key['private_key']
124+
credentials = _credentials().from_json_keyfile_dict(json_key,
125+
scopes=scope)
110126

111127
bq_service = _get_bq_service(credentials=credentials,
112-
service_url=service_url,
113-
service_account=service_account,
114-
private_key=private_key,
115-
readonly=readonly)
128+
service_url=service_url)
116129

117130
return BigQueryClient(bq_service, project_id, swallow_results)
118131

119132

120-
def _get_bq_service(credentials=None, service_url=None, service_account=None, private_key=None,
121-
readonly=True):
133+
def _get_bq_service(credentials=None, service_url=None):
122134
"""Construct an authorized BigQuery service object."""
123135

124-
assert credentials or (service_account and private_key), \
125-
'Must provide AssertionCredentials or service account and key'
126-
127-
if not credentials:
128-
scope = BIGQUERY_SCOPE_READ_ONLY if readonly else BIGQUERY_SCOPE
129-
credentials = _credentials()(service_account, private_key, scope=scope)
136+
assert credentials, 'Must provide ServiceAccountCredentials'
130137

131-
http = httplib2.Http()
132-
http = credentials.authorize(http)
133-
service = build('bigquery', 'v2', http=http, discoveryServiceUrl=service_url)
138+
http = credentials.authorize(Http())
139+
service = build('bigquery', 'v2', http=http,
140+
discoveryServiceUrl=service_url)
134141

135142
return service
136143

137144

138145
def _credentials():
139146
"""Import and return SignedJwtAssertionCredentials class"""
140-
from oauth2client.client import SignedJwtAssertionCredentials
147+
from oauth2client.service_account import ServiceAccountCredentials
141148

142-
return SignedJwtAssertionCredentials
149+
return ServiceAccountCredentials
143150

144151

145152
class BigQueryClient(object):

bigquery/tests/test_client.py

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@
22

33
import mock
44
import six
5-
from nose.tools import raises
6-
7-
from apiclient.errors import HttpError
85
from bigquery import client
96
from bigquery.errors import (
107
JobInsertException, JobExecutingException,
118
BigQueryTimeoutException
129
)
10+
from googleapiclient.errors import HttpError
11+
from nose.tools import raises
1312

1413

1514
class HttpResponse(object):
16-
1715
def __init__(self, status, reason='There was an error'):
1816
"""
1917
Args:
@@ -24,7 +22,6 @@ def __init__(self, status, reason='There was an error'):
2422

2523

2624
class TestGetClient(unittest.TestCase):
27-
2825
def setUp(self):
2926
client._bq_client = None
3027

@@ -51,7 +48,7 @@ def test_initialize_readonly(self, mock_build, mock_return_cred):
5148
mock_cred = mock.Mock()
5249
mock_http = mock.Mock()
5350
mock_service_url = mock.Mock()
54-
mock_cred.return_value.authorize.return_value = mock_http
51+
mock_cred.from_p12_keyfile_buffer.return_value.authorize.return_value = mock_http
5552
mock_bq = mock.Mock()
5653
mock_build.return_value = mock_bq
5754
key = 'key'
@@ -65,9 +62,11 @@ def test_initialize_readonly(self, mock_build, mock_return_cred):
6562
readonly=True)
6663

6764
mock_return_cred.assert_called_once_with()
68-
mock_cred.assert_called_once_with(service_account, key,
69-
scope=BIGQUERY_SCOPE_READ_ONLY)
70-
self.assertTrue(mock_cred.return_value.authorize.called)
65+
mock_cred.from_p12_keyfile_buffer.assert_called_once_with(
66+
service_account, mock.ANY,
67+
scopes=BIGQUERY_SCOPE_READ_ONLY)
68+
self.assertTrue(
69+
mock_cred.from_p12_keyfile_buffer.return_value.authorize.called)
7170
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http,
7271
discoveryServiceUrl=mock_service_url)
7372
self.assertEquals(mock_bq, bq_client.bigquery)
@@ -84,7 +83,7 @@ def test_initialize_read_write(self, mock_build, mock_return_cred):
8483
mock_cred = mock.Mock()
8584
mock_http = mock.Mock()
8685
mock_service_url = mock.Mock()
87-
mock_cred.return_value.authorize.return_value = mock_http
86+
mock_cred.from_p12_keyfile_buffer.return_value.authorize.return_value = mock_http
8887
mock_bq = mock.Mock()
8988
mock_build.return_value = mock_bq
9089
key = 'key'
@@ -98,19 +97,18 @@ def test_initialize_read_write(self, mock_build, mock_return_cred):
9897
readonly=False)
9998

10099
mock_return_cred.assert_called_once_with()
101-
mock_cred.assert_called_once_with(service_account, key,
102-
scope=BIGQUERY_SCOPE)
103-
self.assertTrue(mock_cred.return_value.authorize.called)
100+
mock_cred.from_p12_keyfile_buffer.assert_called_once_with(
101+
service_account, mock.ANY, scopes=BIGQUERY_SCOPE)
102+
self.assertTrue(
103+
mock_cred.from_p12_keyfile_buffer.return_value.authorize.called)
104104
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http,
105105
discoveryServiceUrl=mock_service_url)
106106
self.assertEquals(mock_bq, bq_client.bigquery)
107107
self.assertEquals(project_id, bq_client.project_id)
108108

109109
@mock.patch('bigquery.client._credentials')
110110
@mock.patch('bigquery.client.build')
111-
@mock.patch('__builtin__.open' if six.PY2 else 'builtins.open')
112-
def test_initialize_key_file(self, mock_open, mock_build,
113-
mock_return_cred):
111+
def test_initialize_key_file(self, mock_build, mock_return_cred):
114112
"""Ensure that a BigQueryClient is initialized and returned with
115113
read/write permissions using a private key file.
116114
"""
@@ -119,12 +117,10 @@ def test_initialize_key_file(self, mock_open, mock_build,
119117
mock_cred = mock.Mock()
120118
mock_http = mock.Mock()
121119
mock_service_url = mock.Mock()
122-
mock_cred.return_value.authorize.return_value = mock_http
120+
mock_cred.from_p12_keyfile.return_value.authorize.return_value = mock_http
123121
mock_bq = mock.Mock()
124122
mock_build.return_value = mock_bq
125123
key_file = 'key.pem'
126-
key = 'key'
127-
mock_open.return_value.__enter__.return_value.read.return_value = key
128124
service_account = 'account'
129125
project_id = 'project'
130126
mock_return_cred.return_value = mock_cred
@@ -134,46 +130,46 @@ def test_initialize_key_file(self, mock_open, mock_build,
134130
service_account=service_account,
135131
private_key_file=key_file, readonly=False)
136132

137-
mock_open.assert_called_once_with(key_file, 'rb')
138133
mock_return_cred.assert_called_once_with()
139-
mock_cred.assert_called_once_with(service_account, key,
140-
scope=BIGQUERY_SCOPE)
141-
self.assertTrue(mock_cred.return_value.authorize.called)
134+
mock_cred.from_p12_keyfile.assert_called_once_with(service_account,
135+
key_file,
136+
scopes=BIGQUERY_SCOPE)
137+
self.assertTrue(
138+
mock_cred.from_p12_keyfile.return_value.authorize.called)
142139
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http,
143140
discoveryServiceUrl=mock_service_url)
144141
self.assertEquals(mock_bq, bq_client.bigquery)
145142
self.assertEquals(project_id, bq_client.project_id)
146143

147144
@mock.patch('bigquery.client._credentials')
148145
@mock.patch('bigquery.client.build')
149-
@mock.patch('__builtin__.open' if six.PY2 else 'builtins.open')
150-
def test_initialize_json_key_file(self, mock_open, mock_build, mock_return_cred):
146+
def test_initialize_json_key_file(self, mock_build, mock_return_cred):
151147
"""Ensure that a BigQueryClient is initialized and returned with
152148
read/write permissions using a JSON key file.
153149
"""
154150
from bigquery.client import BIGQUERY_SCOPE
155-
import json
156151

157152
mock_cred = mock.Mock()
158153
mock_http = mock.Mock()
159154
mock_service_url = mock.Mock()
160-
mock_cred.return_value.authorize.return_value = mock_http
155+
mock_cred.from_json_keyfile_name.return_value.authorize.return_value = mock_http
161156
mock_bq = mock.Mock()
162157
mock_build.return_value = mock_bq
163158
json_key_file = 'key.json'
164-
json_key = {'client_email': 'mail', 'private_key': 'pkey'}
165-
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(json_key)
166159
project_id = 'project'
167160
mock_return_cred.return_value = mock_cred
168161

169162
bq_client = client.get_client(
170-
project_id, service_url=mock_service_url, json_key_file=json_key_file, readonly=False)
163+
project_id, service_url=mock_service_url,
164+
json_key_file=json_key_file, readonly=False)
171165

172-
mock_open.assert_called_once_with(json_key_file, 'r')
173166
mock_return_cred.assert_called_once_with()
174-
mock_cred.assert_called_once_with(json_key['client_email'], json_key['private_key'], scope=BIGQUERY_SCOPE)
175-
self.assertTrue(mock_cred.return_value.authorize.called)
176-
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http, discoveryServiceUrl=mock_service_url)
167+
mock_cred.from_json_keyfile_name.assert_called_once_with(json_key_file,
168+
scopes=BIGQUERY_SCOPE)
169+
self.assertTrue(
170+
mock_cred.from_json_keyfile_name.return_value.authorize.called)
171+
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http,
172+
discoveryServiceUrl=mock_service_url)
177173
self.assertEquals(mock_bq, bq_client.bigquery)
178174
self.assertEquals(project_id, bq_client.project_id)
179175

0 commit comments

Comments
 (0)