Skip to content

Commit 7ce159a

Browse files
committed
Read project_id from JSON key file.
A JSON key file provided by Google contains project_id. Now project_id argument of get_client() is optional and read from the JSON key file if json_key or json_key_file is provided. I believe this improve usability of get_client().
1 parent 4042057 commit 7ce159a

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ client = get_client(project_id, service_account=service_account,
3131
# JSON key provided by Google
3232
json_key = 'key.json'
3333

34-
client = get_client(project_id, json_key_file=json_key, readonly=True)
34+
client = get_client(json_key_file=json_key, readonly=True)
3535

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

bigquery/client.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
logger = getLogger(__name__)
4646

4747

48-
def get_client(project_id, credentials=None,
48+
def get_client(project_id=None, credentials=None,
4949
service_url=None, service_account=None,
5050
private_key=None, private_key_file=None,
5151
json_key=None, json_key_file=None,
@@ -56,8 +56,8 @@ def get_client(project_id, credentials=None,
5656
5757
Parameters
5858
----------
59-
project_id : str
60-
The BigQuery project id
59+
project_id : str, optional
60+
The BigQuery project id, required unless json_key or json_key_file is provided.
6161
credentials : oauth2client.client.SignedJwtAssertionCredentials, optional
6262
AssertionCredentials instance to authenticate requests to BigQuery (optional,
6363
must provide `service_account` and (`private_key` or `private_key_file`) or
@@ -96,6 +96,10 @@ def get_client(project_id, credentials=None,
9696
json_key or json_key_file), \
9797
'Must provide AssertionCredentials or service account and P12 key or JSON key'
9898

99+
if not project_id:
100+
assert json_key or json_key_file, \
101+
'Must provide project_id unless json_key or json_key_file is provided'
102+
99103
if service_url is None:
100104
service_url = DISCOVERY_URI
101105

@@ -119,12 +123,14 @@ def get_client(project_id, credentials=None,
119123
scopes=scope)
120124

121125
if json_key_file:
122-
credentials = _credentials().from_json_keyfile_name(json_key_file,
123-
scopes=scope)
126+
with open(json_key_file, 'r') as key_file:
127+
json_key = json.load(key_file)
124128

125129
if json_key:
126130
credentials = _credentials().from_json_keyfile_dict(json_key,
127131
scopes=scope)
132+
if not project_id:
133+
project_id = json_key['project_id']
128134

129135
bq_service = _get_bq_service(credentials=credentials,
130136
service_url=service_url)

bigquery/tests/test_client.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,19 +143,23 @@ def test_initialize_key_file(self, mock_build, mock_return_cred):
143143

144144
@mock.patch('bigquery.client._credentials')
145145
@mock.patch('bigquery.client.build')
146-
def test_initialize_json_key_file(self, mock_build, mock_return_cred):
146+
@mock.patch('__builtin__.open' if six.PY2 else 'builtins.open')
147+
def test_initialize_json_key_file(self, mock_open, mock_build, mock_return_cred):
147148
"""Ensure that a BigQueryClient is initialized and returned with
148149
read/write permissions using a JSON key file.
149150
"""
150151
from bigquery.client import BIGQUERY_SCOPE
152+
import json
151153

152154
mock_cred = mock.Mock()
153155
mock_http = mock.Mock()
154156
mock_service_url = mock.Mock()
155-
mock_cred.from_json_keyfile_name.return_value.authorize.return_value = mock_http
157+
mock_cred.from_json_keyfile_dict.return_value.authorize.return_value = mock_http
156158
mock_bq = mock.Mock()
157159
mock_build.return_value = mock_bq
158160
json_key_file = 'key.json'
161+
json_key = {'client_email': 'mail', 'private_key': 'pkey'}
162+
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(json_key)
159163
project_id = 'project'
160164
mock_return_cred.return_value = mock_cred
161165

@@ -164,15 +168,51 @@ def test_initialize_json_key_file(self, mock_build, mock_return_cred):
164168
json_key_file=json_key_file, readonly=False)
165169

166170
mock_return_cred.assert_called_once_with()
167-
mock_cred.from_json_keyfile_name.assert_called_once_with(json_key_file,
171+
mock_cred.from_json_keyfile_dict.assert_called_once_with(json_key,
168172
scopes=BIGQUERY_SCOPE)
169173
self.assertTrue(
170-
mock_cred.from_json_keyfile_name.return_value.authorize.called)
174+
mock_cred.from_json_keyfile_dict.return_value.authorize.called)
171175
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http,
172176
discoveryServiceUrl=mock_service_url)
173177
self.assertEquals(mock_bq, bq_client.bigquery)
174178
self.assertEquals(project_id, bq_client.project_id)
175179

180+
@mock.patch('bigquery.client._credentials')
181+
@mock.patch('bigquery.client.build')
182+
@mock.patch('__builtin__.open' if six.PY2 else 'builtins.open')
183+
def test_initialize_json_key_file_without_project_id(self, mock_open, mock_build,
184+
mock_return_cred):
185+
"""Ensure that a BigQueryClient is initialized and returned with
186+
read/write permissions using a JSON key file without project_id.
187+
"""
188+
from bigquery.client import BIGQUERY_SCOPE
189+
import json
190+
191+
mock_cred = mock.Mock()
192+
mock_http = mock.Mock()
193+
mock_service_url = mock.Mock()
194+
mock_cred.from_json_keyfile_dict.return_value.authorize.return_value = mock_http
195+
mock_bq = mock.Mock()
196+
mock_build.return_value = mock_bq
197+
json_key_file = 'key.json'
198+
json_key = {'client_email': 'mail', 'private_key': 'pkey', 'project_id': 'project'}
199+
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(json_key)
200+
mock_return_cred.return_value = mock_cred
201+
202+
bq_client = client.get_client(
203+
service_url=mock_service_url, json_key_file=json_key_file, readonly=False)
204+
205+
mock_open.assert_called_once_with(json_key_file, 'r')
206+
mock_return_cred.assert_called_once_with()
207+
mock_cred.from_json_keyfile_dict.assert_called_once_with(json_key,
208+
scopes=BIGQUERY_SCOPE)
209+
self.assertTrue(
210+
mock_cred.from_json_keyfile_dict.return_value.authorize.called)
211+
mock_build.assert_called_once_with('bigquery', 'v2', http=mock_http,
212+
discoveryServiceUrl=mock_service_url)
213+
self.assertEquals(mock_bq, bq_client.bigquery)
214+
self.assertEquals(json_key['project_id'], bq_client.project_id)
215+
176216

177217
class TestQuery(unittest.TestCase):
178218

0 commit comments

Comments
 (0)