diff --git a/googleapiclient/http.py b/googleapiclient/http.py index 5181badbeba..d22313f4783 100644 --- a/googleapiclient/http.py +++ b/googleapiclient/http.py @@ -1394,6 +1394,14 @@ def execute(self, http=None): if http is None: raise ValueError("Missing a valid http object.") + # Special case for OAuth2Credentials-style objects which have not yet been + # refreshed with an initial access_token. + if getattr(http.request, 'credentials', None) is not None: + creds = http.request.credentials + if not getattr(creds, 'access_token', None): + LOGGER.info('Attempting refresh to obtain initial access_token') + creds.refresh(http) + self._execute(http, self._order, self._requests) # Loop over all the requests and check for 401s. For each 401 request the diff --git a/tests/test_http.py b/tests/test_http.py index 08450473a69..1cca7c69db5 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -1072,6 +1072,34 @@ def test_execute_request_body(self): header = parts[1].splitlines()[1] self.assertEqual('Content-Type: application/http', header) + def test_execute_initial_refresh_oauth2(self): + batch = BatchHttpRequest() + callbacks = Callbacks() + cred = MockCredentials('Foo') + + # Pretend this is a OAuth2Credentials object + cred.access_token = None + + http = HttpMockSequence([ + ({'status': '200', + 'content-type': 'multipart/mixed; boundary="batch_foobarbaz"'}, + BATCH_SINGLE_RESPONSE), + ]) + + cred.authorize(http) + + batch.add(self.request1, callback=callbacks.f) + batch.execute(http=http) + + self.assertEqual({'foo': 42}, callbacks.responses['1']) + self.assertIsNone(callbacks.exceptions['1']) + + self.assertEqual(1, cred._refreshed) + + self.assertEqual(1, cred._authorized) + + self.assertEqual(1, cred._applied) + def test_execute_refresh_and_retry_on_401(self): batch = BatchHttpRequest() callbacks = Callbacks()