@@ -162,6 +162,72 @@ class TableCreationError(ValueError):
162
162
pass
163
163
164
164
165
+ class Context (object ):
166
+ """Storage for objects to be used throughout a session.
167
+
168
+ A Context object is initialized when the ``pandas_gbq`` module is
169
+ imported, and can be found at :attr:`pandas_gbq.context`.
170
+ """
171
+
172
+ def __init__ (self ):
173
+ self ._credentials = None
174
+ self ._project = None
175
+
176
+ @property
177
+ def credentials (self ):
178
+ """google.auth.credentials.Credentials: Credentials to use for Google
179
+ APIs.
180
+
181
+ Note:
182
+ These credentials are automatically cached in memory by calls to
183
+ :func:`pandas_gbq.read_gbq` and :func:`pandas_gbq.to_gbq`. To
184
+ manually set the credentials, construct an
185
+ :class:`google.auth.credentials.Credentials` object and set it as
186
+ the context credentials as demonstrated in the example below. See
187
+ `auth docs`_ for more information on obtaining credentials.
188
+
189
+ Example:
190
+ Manually setting the context credentials:
191
+ >>> import pandas_gbq
192
+ >>> from google.oauth2 import service_account
193
+ >>> credentials = (service_account
194
+ ... .Credentials.from_service_account_file(
195
+ ... '/path/to/key.json'))
196
+ >>> pandas_gbq.context.credentials = credentials
197
+ .. _auth docs: http://google-auth.readthedocs.io
198
+ /en/latest/user-guide.html#obtaining-credentials
199
+ """
200
+ return self ._credentials
201
+
202
+ @credentials .setter
203
+ def credentials (self , value ):
204
+ self ._credentials = value
205
+
206
+ @property
207
+ def project (self ):
208
+ """str: Default project to use for calls to Google APIs.
209
+
210
+ Example:
211
+ Manually setting the context project:
212
+ >>> import pandas_gbq
213
+ >>> pandas_gbq.context.project = 'my-project'
214
+ """
215
+ return self ._project
216
+
217
+ @project .setter
218
+ def project (self , value ):
219
+ self ._project = value
220
+
221
+
222
+ # Create an empty context, used to cache credentials.
223
+ context = Context ()
224
+ """A :class:`pandas_gbq.Context` object used to cache credentials.
225
+
226
+ Credentials automatically are cached in-memory by :func:`pandas_gbq.read_gbq`
227
+ and :func:`pandas_gbq.to_gbq`.
228
+ """
229
+
230
+
165
231
class GbqConnector (object ):
166
232
def __init__ (
167
233
self ,
@@ -173,6 +239,7 @@ def __init__(
173
239
location = None ,
174
240
try_credentials = None ,
175
241
):
242
+ global context
176
243
from google .api_core .exceptions import GoogleAPIError
177
244
from google .api_core .exceptions import ClientError
178
245
from pandas_gbq import auth
@@ -185,13 +252,20 @@ def __init__(
185
252
self .auth_local_webserver = auth_local_webserver
186
253
self .dialect = dialect
187
254
self .credentials_path = _get_credentials_file ()
188
- self .credentials , default_project = auth .get_credentials (
189
- private_key = private_key ,
190
- project_id = project_id ,
191
- reauth = reauth ,
192
- auth_local_webserver = auth_local_webserver ,
193
- try_credentials = try_credentials ,
194
- )
255
+
256
+ # Load credentials from cache.
257
+ self .credentials = context .credentials
258
+ default_project = context .project
259
+
260
+ # Credentials were explicitly asked for, so don't use the cache.
261
+ if private_key or reauth or not self .credentials :
262
+ self .credentials , default_project = auth .get_credentials (
263
+ private_key = private_key ,
264
+ project_id = project_id ,
265
+ reauth = reauth ,
266
+ auth_local_webserver = auth_local_webserver ,
267
+ try_credentials = try_credentials ,
268
+ )
195
269
196
270
if self .project_id is None :
197
271
self .project_id = default_project
@@ -201,6 +275,12 @@ def __init__(
201
275
"Could not determine project ID and one was not supplied."
202
276
)
203
277
278
+ # Cache the credentials if they haven't been set yet.
279
+ if context .credentials is None :
280
+ context .credentials = self .credentials
281
+ if context .project is None :
282
+ context .project = self .project_id
283
+
204
284
self .client = self .get_client ()
205
285
206
286
# BQ Queries costs $5 per TB. First 1 TB per month is free
0 commit comments