Skip to content

Commit 272091a

Browse files
authored
[core] add non odatav4 error bodies to message (#21800)
1 parent e6bea2a commit 272091a

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

sdk/core/azure-core/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
### Bugs Fixed
1212

13+
- Add response body to string representation of `HttpResponseError` if we're not able to parse out information #21800
14+
1315
### Other Changes
1416

1517
## 1.20.1 (2021-11-08)

sdk/core/azure-core/azure/core/exceptions.py

+10
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,16 @@ def _parse_odata_body(error_format, response):
333333
pass
334334
return None
335335

336+
def __str__(self):
337+
retval = super(HttpResponseError, self).__str__()
338+
try:
339+
body = self.response.text()
340+
if body and not self.error:
341+
return "{}\nContent: {}".format(retval, body)[:2048]
342+
except Exception: # pylint: disable=broad-except
343+
pass
344+
return retval
345+
336346

337347
class DecodeError(HttpResponseError):
338348
"""Error raised during response deserialization."""

sdk/core/azure-core/tests/test_exceptions.py

+36-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from azure.core.pipeline.transport import RequestsTransportResponse
3838
from azure.core.pipeline.transport._base import _HttpResponseBase as PipelineTransportHttpResponseBase
3939
from azure.core.rest._http_response_impl import _HttpResponseBaseImpl as RestHttpResponseBase
40+
from utils import HTTP_REQUESTS
4041

4142
class PipelineTransportMockResponse(PipelineTransportHttpResponseBase):
4243
def __init__(self, json_body):
@@ -152,6 +153,8 @@ def test_deserialized_httpresponse_error_code(self, mock_response):
152153
assert error.error.error.code == "FakeErrorOne"
153154
assert error.error.error.message == "A fake error"
154155

156+
assert str(error) == "(FakeErrorOne) A fake error\nCode: FakeErrorOne\nMessage: A fake error"
157+
155158

156159
@pytest.mark.parametrize("mock_response", MOCK_RESPONSES)
157160
def test_deserialized_httpresponse_error_message(self, mock_response):
@@ -284,4 +287,36 @@ def test_null_odata_details(self, mock_response):
284287
}
285288
}
286289
exp = HttpResponseError(response=mock_response(json.dumps(message).encode("utf-8")))
287-
assert exp.error.code == "501"
290+
assert exp.error.code == "501"
291+
292+
@pytest.mark.parametrize("http_request", HTTP_REQUESTS)
293+
def test_non_odatav4_error_body(self, client, http_request):
294+
request = http_request("GET", "/errors/non-odatav4-body")
295+
response = client.send_request(request)
296+
with pytest.raises(HttpResponseError) as ex:
297+
response.raise_for_status()
298+
assert str(ex.value) == "Operation returned an invalid status 'BAD REQUEST'\nContent: {\"code\": 400, \"error\": {\"global\": [\"MY-ERROR-MESSAGE-THAT-IS-COMING-FROM-THE-API\"]}}"
299+
300+
@pytest.mark.parametrize("http_request", HTTP_REQUESTS)
301+
def test_malformed_json(self, client, http_request):
302+
request = http_request("GET", "/errors/malformed-json")
303+
response = client.send_request(request)
304+
with pytest.raises(HttpResponseError) as ex:
305+
response.raise_for_status()
306+
assert str(ex.value) == "Operation returned an invalid status 'BAD REQUEST'\nContent: {\"code\": 400, \"error\": {\"global\": [\"MY-ERROR-MESSAGE-THAT-IS-COMING-FROM-THE-API\"]"
307+
308+
@pytest.mark.parametrize("http_request", HTTP_REQUESTS)
309+
def test_text(self, client, http_request):
310+
request = http_request("GET", "/errors/text")
311+
response = client.send_request(request)
312+
with pytest.raises(HttpResponseError) as ex:
313+
response.raise_for_status()
314+
assert str(ex.value) == "Operation returned an invalid status 'BAD REQUEST'\nContent: I am throwing an error"
315+
316+
@pytest.mark.parametrize("http_request", HTTP_REQUESTS)
317+
def test_datav4_error(self, client, http_request):
318+
request = http_request("GET", "/errors/odatav4")
319+
response = client.send_request(request)
320+
with pytest.raises(HttpResponseError) as ex:
321+
response.raise_for_status()
322+
assert "Content: {\"" not in str(ex.value)

sdk/core/azure-core/tests/testserver_tests/coretestserver/coretestserver/test_routes/errors.py

+28
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,31 @@ def get_short_data():
3333
response.automatically_set_content_length = False
3434
response.headers["Content-Length"] = "8"
3535
return response
36+
37+
@errors_api.route('/non-odatav4-body', methods=['GET'])
38+
def get_non_odata_v4_response_body():
39+
return Response(
40+
'{"code": 400, "error": {"global": ["MY-ERROR-MESSAGE-THAT-IS-COMING-FROM-THE-API"]}}',
41+
status=400
42+
)
43+
44+
@errors_api.route('/malformed-json', methods=['GET'])
45+
def get_malformed_json():
46+
return Response(
47+
'{"code": 400, "error": {"global": ["MY-ERROR-MESSAGE-THAT-IS-COMING-FROM-THE-API"]',
48+
status=400
49+
)
50+
51+
@errors_api.route('/text', methods=['GET'])
52+
def get_text_body():
53+
return Response(
54+
'I am throwing an error',
55+
status=400
56+
)
57+
58+
@errors_api.route('/odatav4', methods=['GET'])
59+
def get_odatav4():
60+
return Response(
61+
'{"error": {"code": "501", "message": "Unsupported functionality", "target": "query", "details": [{"code": "301", "target": "$search", "message": "$search query option not supported"}], "innererror": {"trace": [], "context": {}}}}',
62+
status=400
63+
)

0 commit comments

Comments
 (0)