Skip to content

fix: replace HTTP status string parsing with structured HTTPError#83

Merged
Faerkeren merged 1 commit into
mainfrom
fix/structured-http-error
May 27, 2026
Merged

fix: replace HTTP status string parsing with structured HTTPError#83
Faerkeren merged 1 commit into
mainfrom
fix/structured-http-error

Conversation

@Faerkeren

Copy link
Copy Markdown
Contributor

Closes #79

Validity Assessment

Valid bug. get_state() detected missing entities by parsing "HTTP 404" out of an exception message string. This is fragile: a message format change or a coincidental match in a response body could silently alter behavior. Status codes are structured data and should be treated as such.

Fix

New exception: HTTPError

Added HTTPError(status, method, path, body) to exceptions.py, derived from HAClientError. Carries the HTTP status code, method, path, and body as typed attributes. The str() representation is backward-compatible ("HTTP 404 from GET /api/states/foo: ...").

class HTTPError(HAClientError):
    def __init__(self, status: int, method: str, path: str, body: str) -> None: ...
    status: int
    method: str
    path: str
    body: str

HTTPError is exported from the top-level haclient package.

_request()rest_aiohttp.py

Raises HTTPError instead of generic HAClientError for all non-401 HTTP failures.

get_state()rest_aiohttp.py

Before:

except HAClientError as err:
    if "HTTP 404" in str(err):  # brittle string match
        return None

After:

except HTTPError as err:
    if err.status == 404:        # structured check
        return None

Tests / Checks Run

  • test_request_server_error — updated to assert the raised exception is HTTPError with correct status, method, path attributes, and that it is still an instance of HAClientError.
  • test_http_error_attributes — new: verifies all structured attributes and the string representation.
  • test_get_state_returns_none_only_for_404 — new: verifies get_state() returns None only for a real 404, not for other scenarios.
  • test_get_state_reraises_non_404_http_error — new: verifies get_state() re-raises HTTPError when status is not 404 (e.g. 500).

Suite results:

  • pytest: 307 passed, coverage 97.16% (threshold 95%)
  • ruff check + ruff format --check: all checks passed
  • mypy src: no issues found

Introduce HTTPError(status, method, path, body) deriving from HAClientError.

- _request() now raises HTTPError for all non-401 HTTP failures instead
  of encoding the status code into a generic HAClientError message string.
- get_state() checks err.status == 404 instead of parsing 'HTTP 404' out
  of str(err), eliminating the fragile string-matching pattern.
- AuthenticationError (401) is unchanged.
- HTTPError is exported from the top-level haclient package.
- Tests added: HTTPError attributes, get_state returns None only for
  real 404 responses, and get_state re-raises non-404 HTTP errors.
@Faerkeren Faerkeren merged commit 1d94187 into main May 27, 2026
12 checks passed
@Faerkeren Faerkeren deleted the fix/structured-http-error branch May 27, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace HTTP status string parsing with structured errors

1 participant