Skip to content

Commit

Permalink
Add text from 400 R2 responses to FilesError exception (#804)
Browse files Browse the repository at this point in the history
* Log XML errors on upload

* Adjust

* LINT

* move replacer
  • Loading branch information
ludeeus authored Feb 12, 2025
1 parent a7887c9 commit bfea2fb
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
12 changes: 12 additions & 0 deletions hass_nabucasa/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import base64
from collections.abc import AsyncIterator, Callable, Coroutine
import contextlib
from enum import StrEnum
import hashlib
import logging
Expand Down Expand Up @@ -134,6 +135,17 @@ async def upload(
)

self._do_log_response(response)
if response.status == 400:
# We can try to get some context.
error = await response.text()
if error and "<Message>" in error and "</Message>" in error:
with contextlib.suppress(AttributeError, IndexError):
# This is ugly but it's the best we can do, we have no control
# over the error message structure, so we try what we can.
error = error.split("<Message>")[1].split("</Message>")[0]
raise FilesError(
f"Failed to upload: (400) {error[:256].replace('\n', ' ')}"
)
response.raise_for_status()
except CloudApiError as err:
raise FilesError(err, orig_exc=err) from err
Expand Down
40 changes: 33 additions & 7 deletions tests/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,43 @@ async def test_upload_exceptions_while_getting_details(


@pytest.mark.parametrize(
"exception,msg",
"putmockargs,msg",
[
[TimeoutError, "Timeout reached while calling API"],
[ClientError, "Failed to fetch"],
[Exception, "Unexpected error while calling API"],
[{"exc": TimeoutError("Boom!")}, "Timeout reached while calling API"],
[{"exc": ClientError("Boom!")}, "Failed to fetch: Boom!"],
[{"exc": Exception("Boom!")}, "Unexpected error while calling API: Boom!"],
[{"status": 400}, "Failed to upload: (400) "],
[
{"status": 400, "text": "Unknown error structure"},
"Failed to upload: (400) Unknown error structure",
],
[
{
"status": 400,
"text": "<Message>Pretty error\nWith a linebreak</Message>",
},
"Failed to upload: (400) Pretty error With a linebreak",
],
[
{
"status": 400,
"text": "<Message>What is this?",
},
"Failed to upload: (400) <Message>What is this?",
],
[
{
"status": 400,
"text": f"{'a' * 512}",
},
f"Failed to upload: (400) {'a' * 256}",
],
],
)
async def test_upload_exceptions_while_uploading(
aioclient_mock: AiohttpClientMocker,
auth_cloud_mock: Cloud,
exception: Exception,
putmockargs: dict[str, Any],
msg: str,
):
"""Test handling exceptions during file upload."""
Expand All @@ -84,9 +110,9 @@ async def test_upload_exceptions_while_uploading(
json={"url": FILES_API_URL, "headers": {}},
)

aioclient_mock.put(FILES_API_URL, exc=exception("Boom!"))
aioclient_mock.put(FILES_API_URL, **putmockargs)

with pytest.raises(FilesError, match=msg):
with pytest.raises(FilesError, match=f"^{re.escape(msg)}$"):
await files.upload(
storage_type="test",
open_stream=AsyncMock(),
Expand Down

0 comments on commit bfea2fb

Please sign in to comment.