Skip to content

Commit e8a7796

Browse files
committed
Add private_key_file kwarg on get_client
This kwarg allows you to pass the key file name and get_client handles reading it. The actual key string can still be passed in using private_key.
1 parent 4ac48f1 commit e8a7796

3 files changed

Lines changed: 54 additions & 9 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ project_id = 'project_id'
2121
service_account = '[email protected]'
2222

2323
# PKCS12 or PEM key provided by Google.
24-
key = 'secret_key'
24+
key = 'key.pem'
2525

26-
client = get_client(project_id, service_account=service_account, private_key=key, readonly=True)
26+
client = get_client(project_id, service_account=service_account,
27+
private_key_file=key, readonly=True)
2728

2829
# Submit an async query.
2930
job_id, _results = client.query('SELECT * FROM dataset.my_table LIMIT 1000')

bigquery/client.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646

4747

4848
def get_client(project_id, credentials=None, service_account=None,
49-
private_key=None, readonly=True, swallow_results=True):
49+
private_key=None, private_key_file=None, readonly=True,
50+
swallow_results=True):
5051
"""Return a singleton instance of BigQueryClient. Either
5152
AssertionCredentials or a service account and private key combination need
5253
to be provided in order to authenticate requests to BigQuery.
@@ -58,6 +59,9 @@ def get_client(project_id, credentials=None, service_account=None,
5859
service_account: the Google API service account name.
5960
private_key: the private key associated with the service account in
6061
PKCS12 or PEM format.
62+
private_key_file: the name of the file containing the private key
63+
associated with the service account in PKCS12 or PEM
64+
format.
6165
readonly: bool indicating if BigQuery access is read-only. Has no
6266
effect if credentials are provided.
6367
swallow_results: If set to false then return the actual response value
@@ -67,9 +71,13 @@ def get_client(project_id, credentials=None, service_account=None,
6771
an instance of BigQueryClient.
6872
"""
6973

70-
if not credentials and not (service_account and private_key):
71-
raise Exception('AssertionCredentials or service account and private'
72-
'key need to be provided')
74+
if not credentials:
75+
assert service_account and (private_key or private_key_file), \
76+
'Must provide AssertionCredentials or service account and key'
77+
78+
if private_key_file:
79+
with open(private_key_file, 'rb') as key_file:
80+
private_key = key_file.read()
7381

7482
bq_service = _get_bq_service(credentials=credentials,
7583
service_account=service_account,
@@ -83,7 +91,8 @@ def _get_bq_service(credentials=None, service_account=None, private_key=None,
8391
readonly=True):
8492
"""Construct an authorized BigQuery service object."""
8593

86-
assert credentials or (service_account and private_key)
94+
assert credentials or (service_account and private_key), \
95+
'Must provide AssertionCredentials or service account and key'
8796

8897
if not credentials:
8998
scope = BIGQUERY_SCOPE_READ_ONLY if readonly else BIGQUERY_SCOPE
@@ -820,7 +829,7 @@ def _get_all_tables(self, dataset_id, cache=False):
820829
projectId=self.project_id,
821830
datasetId=dataset_id,
822831
pageToken=page_token
823-
).execute()
832+
).execute()
824833
page_token = res.get('nextPageToken')
825834
result['tables'] += res.get('tables', [])
826835
self.cache[dataset_id] = (datetime.now(), result)

bigquery/tests/test_client.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def setUp(self):
3737
def test_no_credentials(self):
3838
"""Ensure an Exception is raised when no credentials are provided."""
3939

40-
self.assertRaises(Exception, client.get_client, 'foo', 'bar')
40+
self.assertRaises(AssertionError, client.get_client, 'foo')
4141

4242
@mock.patch('bigquery.client._credentials')
4343
@mock.patch('bigquery.client.build')
@@ -99,6 +99,41 @@ def test_initialize_read_write(self, mock_build, mock_return_cred):
9999
self.assertEquals(mock_bq, bq_client.bigquery)
100100
self.assertEquals(project_id, bq_client.project_id)
101101

102+
@mock.patch('bigquery.client._credentials')
103+
@mock.patch('bigquery.client.build')
104+
@mock.patch('__builtin__.open')
105+
def test_initialize_key_file(self, mock_open, mock_build,
106+
mock_return_cred):
107+
"""Ensure that a BigQueryClient is initialized and returned with
108+
read/write permissions using a private key file.
109+
"""
110+
from bigquery.client import BIGQUERY_SCOPE
111+
112+
mock_cred = mock.Mock()
113+
mock_http = mock.Mock()
114+
mock_cred.return_value.authorize.return_value = mock_http
115+
mock_bq = mock.Mock()
116+
mock_build.return_value = mock_bq
117+
key_file = 'key.pem'
118+
key = 'key'
119+
mock_open.return_value.__enter__.return_value.read.return_value = key
120+
service_account = 'account'
121+
project_id = 'project'
122+
mock_return_cred.return_value = mock_cred
123+
124+
bq_client = client.get_client(
125+
project_id, service_account=service_account,
126+
private_key_file=key_file, readonly=False)
127+
128+
mock_open.assert_called_once_with(key_file, 'rb')
129+
mock_return_cred.assert_called_once_with()
130+
mock_cred.assert_called_once_with(service_account, key,
131+
scope=BIGQUERY_SCOPE)
132+
mock_cred.authorize.assert_called_once()
133+
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http)
134+
self.assertEquals(mock_bq, bq_client.bigquery)
135+
self.assertEquals(project_id, bq_client.project_id)
136+
102137

103138
class TestQuery(unittest.TestCase):
104139

0 commit comments

Comments
 (0)