diff --git a/gcloud/datastore/test_connection.py b/gcloud/datastore/test_connection.py index c748d258968e..f91ae06b7482 100644 --- a/gcloud/datastore/test_connection.py +++ b/gcloud/datastore/test_connection.py @@ -152,7 +152,7 @@ def test__request_not_200(self): METHOD = 'METHOD' DATA = 'DATA' conn = self._makeOne() - conn._http = Http({'status': '400'}, 'Entity value is indexed.') + conn._http = Http({'status': '400'}, b'Entity value is indexed.') with self.assertRaises(BadRequest) as e: conn._request(DATASET_ID, METHOD, DATA) expected_message = '400 Entity value is indexed.' diff --git a/gcloud/exceptions.py b/gcloud/exceptions.py index 78f641118031..781c13d1c4fd 100644 --- a/gcloud/exceptions.py +++ b/gcloud/exceptions.py @@ -18,6 +18,7 @@ """ import json +import six _HTTP_CODE_TO_EXCEPTION = {} # populated at end of module @@ -171,18 +172,18 @@ def make_exception(response, content, use_json=True): :rtype: instance of :class:`GCloudError`, or a concrete subclass. :returns: Exception specific to the error response. """ - message = content - errors = () - - if isinstance(content, str): + if isinstance(content, six.binary_type): + content_decoded = content.decode('utf-8') if use_json: - payload = json.loads(content) + payload = json.loads(content_decoded) else: - payload = {} + payload = { + 'message': content_decoded + } else: payload = content - message = payload.get('message', message) + message = payload.get('message', '') errors = payload.get('error', {}).get('errors', ()) try: diff --git a/gcloud/storage/connection.py b/gcloud/storage/connection.py index 036e0663bf0a..f646feb148c4 100644 --- a/gcloud/storage/connection.py +++ b/gcloud/storage/connection.py @@ -16,6 +16,7 @@ import json +import six from six.moves.urllib.parse import urlencode # pylint: disable=F0401 from gcloud import connection as base_connection @@ -231,10 +232,13 @@ def api_request(self, method, path, query_params=None, if not 200 <= response.status < 300: raise make_exception(response, content) + if not isinstance(content, six.binary_type): + raise TypeError('Expected binary type, got %s' % type(content)) + if content and expect_json: content_type = response.get('content-type', '') if not content_type.startswith('application/json'): raise TypeError('Expected JSON, got %s' % content_type) - return json.loads(content) + return json.loads(content.decode('utf-8')) return content diff --git a/gcloud/storage/test_api.py b/gcloud/storage/test_api.py index e09f0d51b1fe..19e803fcdcfc 100644 --- a/gcloud/storage/test_api.py +++ b/gcloud/storage/test_api.py @@ -35,7 +35,7 @@ def test_miss(self): ]) http = conn._http = Http( {'status': '404', 'content-type': 'application/json'}, - '{}', + b'{}', ) bucket = self._callFUT(NONESUCH, connection=conn) self.assertEqual(bucket, None) @@ -58,7 +58,7 @@ def _lookup_bucket_hit_helper(self, use_default=False): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{"name": "%s"}' % BLOB_NAME, + '{{"name": "{0}"}}'.format(BLOB_NAME).encode('utf-8'), ) if use_default: @@ -98,7 +98,7 @@ def test_empty(self): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{}', + b'{}', ) buckets = list(self._callFUT(conn)) self.assertEqual(len(buckets), 0) @@ -119,7 +119,8 @@ def _get_all_buckets_non_empty_helper(self, use_default=False): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{"items": [{"name": "%s"}]}' % BUCKET_NAME, + '{{"items": [{{"name": "{0}"}}]}}'.format(BUCKET_NAME) + .encode('utf-8'), ) if use_default: @@ -161,7 +162,7 @@ def test_miss(self): ]) http = conn._http = Http( {'status': '404', 'content-type': 'application/json'}, - '{}', + b'{}', ) self.assertRaises(NotFound, self._callFUT, NONESUCH, connection=conn) self.assertEqual(http._called_with['method'], 'GET') @@ -183,7 +184,7 @@ def _get_bucket_hit_helper(self, use_default=False): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{"name": "%s"}' % BLOB_NAME, + '{{"name": "{0}"}}'.format(BLOB_NAME).encode('utf-8'), ) if use_default: @@ -226,7 +227,7 @@ def _create_bucket_success_helper(self, use_default=False): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{"name": "%s"}' % BLOB_NAME, + '{{"name": "{0}"}}'.format(BLOB_NAME).encode('utf-8'), ) if use_default: diff --git a/gcloud/storage/test_connection.py b/gcloud/storage/test_connection.py index fc5aa6615f52..3de6d7e5700c 100644 --- a/gcloud/storage/test_connection.py +++ b/gcloud/storage/test_connection.py @@ -106,12 +106,12 @@ def test__make_request_no_data_no_content_type_no_headers(self): URI = 'http://example.com/test' http = conn._http = Http( {'status': '200', 'content-type': 'text/plain'}, - '', + b'', ) headers, content = conn._make_request('GET', URI) self.assertEqual(headers['status'], '200') self.assertEqual(headers['content-type'], 'text/plain') - self.assertEqual(content, '') + self.assertEqual(content, b'') self.assertEqual(http._called_with['method'], 'GET') self.assertEqual(http._called_with['uri'], URI) self.assertEqual(http._called_with['body'], None) @@ -128,7 +128,7 @@ def test__make_request_w_data_no_extra_headers(self): URI = 'http://example.com/test' http = conn._http = Http( {'status': '200', 'content-type': 'text/plain'}, - '', + b'', ) conn._make_request('GET', URI, {}, 'application/json') self.assertEqual(http._called_with['method'], 'GET') @@ -148,7 +148,7 @@ def test__make_request_w_extra_headers(self): URI = 'http://example.com/test' http = conn._http = Http( {'status': '200', 'content-type': 'text/plain'}, - '', + b'', ) conn._make_request('GET', URI, headers={'X-Foo': 'foo'}) self.assertEqual(http._called_with['method'], 'GET') @@ -173,7 +173,7 @@ def test_api_request_defaults(self): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{}', + b'{}', ) self.assertEqual(conn.api_request('GET', PATH), {}) self.assertEqual(http._called_with['method'], 'GET') @@ -191,7 +191,7 @@ def test_api_request_w_non_json_response(self): conn = self._makeOne(PROJECT) conn._http = Http( {'status': '200', 'content-type': 'text/plain'}, - 'CONTENT', + b'CONTENT', ) self.assertRaises(TypeError, conn.api_request, 'GET', '/') @@ -201,10 +201,10 @@ def test_api_request_wo_json_expected(self): conn = self._makeOne(PROJECT) conn._http = Http( {'status': '200', 'content-type': 'text/plain'}, - 'CONTENT', + b'CONTENT', ) self.assertEqual(conn.api_request('GET', '/', expect_json=False), - 'CONTENT') + b'CONTENT') def test_api_request_w_query_params(self): from six.moves.urllib.parse import parse_qsl @@ -213,7 +213,7 @@ def test_api_request_w_query_params(self): conn = self._makeOne(PROJECT) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{}', + b'{}', ) self.assertEqual(conn.api_request('GET', '/', {'foo': 'bar'}), {}) self.assertEqual(http._called_with['method'], 'GET') @@ -247,7 +247,7 @@ def test_api_request_w_data(self): ]) http = conn._http = Http( {'status': '200', 'content-type': 'application/json'}, - '{}', + b'{}', ) self.assertEqual(conn.api_request('POST', '/', data=DATA), {}) self.assertEqual(http._called_with['method'], 'POST') @@ -267,7 +267,7 @@ def test_api_request_w_404(self): conn = self._makeOne(PROJECT) conn._http = Http( {'status': '404', 'content-type': 'text/plain'}, - '{}' + b'{}', ) self.assertRaises(NotFound, conn.api_request, 'GET', '/') @@ -277,10 +277,19 @@ def test_api_request_w_500(self): conn = self._makeOne(PROJECT) conn._http = Http( {'status': '500', 'content-type': 'text/plain'}, - '{}', + b'{}', ) self.assertRaises(InternalServerError, conn.api_request, 'GET', '/') + def test_api_request_non_binary_response(self): + PROJECT = 'project' + conn = self._makeOne(PROJECT) + conn._http = Http( + {'status': '200', 'content-type': 'application/json'}, + u'CONTENT', + ) + self.assertRaises(TypeError, conn.api_request, 'GET', '/') + class Http(object): diff --git a/gcloud/test_exceptions.py b/gcloud/test_exceptions.py index ad7f89798660..b2d0ec2f7b0b 100644 --- a/gcloud/test_exceptions.py +++ b/gcloud/test_exceptions.py @@ -55,7 +55,7 @@ def _callFUT(self, response, content): def test_hit_w_content_as_str(self): from gcloud.exceptions import NotFound response = _Response(404) - content = '{"message": "Not Found"}' + content = b'{"message": "Not Found"}' exception = self._callFUT(response, content) self.assertTrue(isinstance(exception, NotFound)) self.assertEqual(exception.message, 'Not Found')