Skip to content

Commit f47886c

Browse files
committed
ENH: Save BigQuery account credentials in a hidden user folder instead of cwd
1 parent dbfb4e9 commit f47886c

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

docs/source/changelog.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
Changelog
22
=========
33

4-
0.2.1 / 2017-??-??
4+
0.3.0 / 2017-??-??
55
------------------
66

77
- :func:`read_gbq` now raises ``QueryTimeout`` if the request exceeds the ``query.timeoutMs`` value specified in the BigQuery configuration. (:issue:`76`)
88
- Environment variable ``PANDAS_GBQ_CREDENTIALS_FILE`` can now be used to override the default location where the BigQuery user account credentials are stored. (:issue:`86`)
9-
9+
- BigQuery user account credentials are now stored in an application-specific hidden user folder on the operating system. (:issue:`41`)
1010

1111
0.2.0 / 2017-07-24
1212
------------------

docs/source/intro.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ is possible with either user or service account credentials.
3737
Authentication via user account credentials is as simple as following the prompts in a browser window
3838
which will automatically open for you. You authenticate to the specified
3939
``BigQuery`` account using the product name ``pandas GBQ``.
40-
The remote authentication is supported via specifying ``auth_local_webserver`` in ``read_gbq``.
40+
The remote authentication is supported via the ``auth_local_webserver`` in ``read_gbq``. By default,
41+
account credentials are stored in an application-specific hidden user folder on the operating system. You
42+
can override the default credentials location via the ``PANDAS_GBQ_CREDENTIALS_FILE`` environment variable.
4143
Additional information on the authentication mechanism can be found
4244
`here <https://developers.google.com/identity/protocols/OAuth2#clientside/>`__.
4345

pandas_gbq/gbq.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ def __init__(self, project_id, reauth=False, verbose=False,
208208
self.private_key = private_key
209209
self.auth_local_webserver = auth_local_webserver
210210
self.dialect = dialect
211+
self.credentials_path = _get_credentials_file()
211212
self.credentials = self.get_credentials()
212213
self.service = self.get_service()
213214

@@ -279,8 +280,21 @@ def load_user_account_credentials(self):
279280
from google_auth_httplib2 import Request
280281
from google.oauth2.credentials import Credentials
281282

283+
# Use the default credentials location under ~/.config and the
284+
# equivalent directory on windows if the user has not specified a
285+
# credentials path.
286+
if not self.credentials_path:
287+
self.credentials_path = self.get_default_credentials_path()
288+
289+
# Previously, pandas-gbq saved user account credentials in the
290+
# current working directory. If the bigquery_credentials.dat file
291+
# exists in the current working directory, move the credentials to
292+
# the new default location.
293+
if os.path.isfile('bigquery_credentials.dat'):
294+
os.rename('bigquery_credentials.dat', self.credentials_path)
295+
282296
try:
283-
with open(_get_credentials_file()) as credentials_file:
297+
with open(self.credentials_path) as credentials_file:
284298
credentials_json = json.load(credentials_file)
285299
except (IOError, ValueError):
286300
return None
@@ -301,14 +315,41 @@ def load_user_account_credentials(self):
301315

302316
return _try_credentials(self.project_id, credentials)
303317

318+
def get_default_credentials_path(self):
319+
"""
320+
Gets the default path to the BigQuery credentials
321+
322+
.. versionadded 0.3.0
323+
324+
Returns
325+
-------
326+
Path to the BigQuery credentials
327+
"""
328+
329+
import os
330+
331+
if os.name == 'nt':
332+
config_path = os.environ['APPDATA']
333+
else:
334+
config_path = os.path.join(os.path.expanduser('~'), '.config')
335+
336+
config_path = os.path.join(config_path, 'pandas_gbq')
337+
338+
# Create a pandas_gbq directory in an application-specific hidden
339+
# user folder on the operating system.
340+
if not os.path.exists(config_path):
341+
os.makedirs(config_path)
342+
343+
return os.path.join(config_path, 'bigquery_credentials.dat')
344+
304345
def save_user_account_credentials(self, credentials):
305346
"""
306347
Saves user account credentials to a local file.
307348
308349
.. versionadded 0.2.0
309350
"""
310351
try:
311-
with open(_get_credentials_file(), 'w') as credentials_file:
352+
with open(self.credentials_path, 'w') as credentials_file:
312353
credentials_json = {
313354
'refresh_token': credentials.refresh_token,
314355
'id_token': credentials.id_token,
@@ -1034,6 +1075,7 @@ def to_gbq(dataframe, destination_table, project_id, chunksize=10000,
10341075
.. [console flow]
10351076
http://google-auth-oauthlib.readthedocs.io/en/latest/reference/google_auth_oauthlib.flow.html#google_auth_oauthlib.flow.InstalledAppFlow.run_console
10361077
.. versionadded:: 0.2.0
1078+
10371079
"""
10381080

10391081
_test_google_api_imports()

pandas_gbq/tests/test_gbq.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,7 @@ def setup_method(self, method):
13881388
# put here any instruction you want to be run *BEFORE* *EVERY* test
13891389
# is executed.
13901390

1391+
gbq.GbqConnector(_get_project_id(), auth_local_webserver=True)
13911392
self.dataset_prefix = _get_dataset_prefix_random()
13921393
clean_gbq_environment(self.dataset_prefix)
13931394
self.destination_table = "{0}{1}.{2}".format(self.dataset_prefix, "2",

0 commit comments

Comments
 (0)