Skip to content

Commit 69f16fc

Browse files
authored
Preserve the message / args from an InvalidResponse. (googleapis#5492)
When raised by 'google.resumable_media' for responses without an error payload, the message and args are the only clue to the cause. Closes googleapis#4222.
1 parent f17bccb commit 69f16fc

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

storage/google/cloud/storage/blob.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,16 @@ def _raise_from_invalid_response(error):
18701870
:raises: :class:`~google.cloud.exceptions.GoogleCloudError` corresponding
18711871
to the failed status code
18721872
"""
1873-
raise exceptions.from_http_response(error.response)
1873+
response = error.response
1874+
error_message = str(error)
1875+
1876+
message = u'{method} {url}: {error}'.format(
1877+
method=response.request.method,
1878+
url=response.request.url,
1879+
error=error_message)
1880+
1881+
raise exceptions.from_http_status(
1882+
response.status_code, message, response=response)
18741883

18751884

18761885
def _add_query_parameters(base_url, name_value_pairs):

storage/tests/unit/test_blob.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,18 +1637,17 @@ def test_upload_from_file_failure(self):
16371637
from google.resumable_media import InvalidResponse
16381638
from google.cloud import exceptions
16391639

1640-
message = b'Someone is already in this spot.'
1640+
message = 'Someone is already in this spot.'
16411641
response = requests.Response()
1642-
response._content = message
16431642
response.status_code = http_client.CONFLICT
16441643
response.request = requests.Request(
16451644
'POST', 'http://example.com').prepare()
1646-
side_effect = InvalidResponse(response)
1645+
side_effect = InvalidResponse(response, message)
16471646

16481647
with self.assertRaises(exceptions.Conflict) as exc_info:
16491648
self._upload_from_file_helper(side_effect=side_effect)
16501649

1651-
self.assertIn(message.decode('utf-8'), exc_info.exception.message)
1650+
self.assertIn(message, exc_info.exception.message)
16521651
self.assertEqual(exc_info.exception.errors, [])
16531652

16541653
def _do_upload_mock_call_helper(self, blob, client, content_type, size):
@@ -1784,17 +1783,16 @@ def test_create_resumable_upload_session_with_failure(self):
17841783
from google.resumable_media import InvalidResponse
17851784
from google.cloud import exceptions
17861785

1787-
message = b'5-oh-3 woe is me.'
1786+
message = '5-oh-3 woe is me.'
17881787
response = self._mock_requests_response(
1789-
content=message, status_code=http_client.SERVICE_UNAVAILABLE,
1790-
headers={})
1791-
side_effect = InvalidResponse(response)
1788+
status_code=http_client.SERVICE_UNAVAILABLE, headers={})
1789+
side_effect = InvalidResponse(response, message)
17921790

17931791
with self.assertRaises(exceptions.ServiceUnavailable) as exc_info:
17941792
self._create_resumable_upload_session_helper(
17951793
side_effect=side_effect)
17961794

1797-
self.assertIn(message.decode('utf-8'), exc_info.exception.message)
1795+
self.assertIn(message, exc_info.exception.message)
17981796
self.assertEqual(exc_info.exception.errors, [])
17991797

18001798
def test_get_iam_policy(self):
@@ -2891,34 +2889,41 @@ def test_do_rewind(self):
28912889
class Test__raise_from_invalid_response(unittest.TestCase):
28922890

28932891
@staticmethod
2894-
def _call_fut(*args, **kwargs):
2892+
def _call_fut(error):
28952893
from google.cloud.storage.blob import _raise_from_invalid_response
28962894

2897-
return _raise_from_invalid_response(*args, **kwargs)
2895+
return _raise_from_invalid_response(error)
28982896

2899-
def _helper(self, message, **kwargs):
2897+
def _helper(self, message, code=http_client.BAD_REQUEST, args=()):
29002898
import requests
29012899

29022900
from google.resumable_media import InvalidResponse
2903-
from google.cloud import exceptions
2901+
from google.api_core import exceptions
29042902

29052903
response = requests.Response()
29062904
response.request = requests.Request(
29072905
'GET', 'http://example.com').prepare()
2908-
response.status_code = http_client.BAD_REQUEST
2909-
response._content = message
2910-
error = InvalidResponse(response)
2906+
response.status_code = code
2907+
error = InvalidResponse(response, message, *args)
29112908

2912-
with self.assertRaises(exceptions.BadRequest) as exc_info:
2913-
self._call_fut(error, **kwargs)
2909+
with self.assertRaises(exceptions.GoogleAPICallError) as exc_info:
2910+
self._call_fut(error)
29142911

29152912
return exc_info
29162913

29172914
def test_default(self):
2918-
message = b'Failure'
2915+
message = 'Failure'
29192916
exc_info = self._helper(message)
2920-
message_str = message.decode('utf-8')
2921-
expected = 'GET http://example.com/: {}'.format(message_str)
2917+
expected = 'GET http://example.com/: {}'.format(message)
2918+
self.assertEqual(exc_info.exception.message, expected)
2919+
self.assertEqual(exc_info.exception.errors, [])
2920+
2921+
def test_w_206_and_args(self):
2922+
message = 'Failure'
2923+
args = ('one', 'two')
2924+
exc_info = self._helper(
2925+
message, code=http_client.PARTIAL_CONTENT, args=args)
2926+
expected = 'GET http://example.com/: {}'.format((message,) + args)
29222927
self.assertEqual(exc_info.exception.message, expected)
29232928
self.assertEqual(exc_info.exception.errors, [])
29242929

0 commit comments

Comments
 (0)