mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-14 15:18:04 +00:00
test(web): cover the error and response builders, and stop dropping empty values
errors.py and error_handler.py's response builders had no direct tests,
though every API response passes through them. Two bugs surfaced.
WebInterfaceError set suggested_fixes with `or`, so a caller passing []
to mean "I have no suggestions for this one" got the default list
instead. Only None should fall back.
create_success_response gated `data` on `is not None` but `message` and
`metadata` on truthiness, so an explicitly-passed "" or {} vanished from
the response while 0 and False survived — the response shape depended on
the value. api_helpers.success_response() then re-gated metadata the same
way, which is the path every api_v3 endpoint actually calls, so fixing
only the inner function would have changed nothing observable. Both now
use `is not None`.
That wrapper also merged request timing into the caller's own metadata
dict in place. A caller reusing a dict across requests would accumulate
previous responses' timings; it now copies before adding.
79 tests: category inference for every error code, mapped vs fallback
suggestions, the JSON shape including which keys are omitted when empty,
exception-to-code inference, and the success/error builders end to end.
Two behaviours are pinned as deliberate rather than fixed: an empty
context stays out of the response body, and from_exception's `message`
is the fixed per-code string, never the raw exception text.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NohXi78cwsAKtN1sCfxjUh
This commit is contained in:
@@ -29,18 +29,16 @@ def success_response(
|
||||
Flask jsonify response
|
||||
"""
|
||||
response_data = create_success_response(data, message, metadata)
|
||||
|
||||
# Add request metadata if available
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
|
||||
# Add timing if request start time is available
|
||||
|
||||
# Timing is merged into whatever the caller passed, without inventing a
|
||||
# metadata block for responses that have neither.
|
||||
enriched = dict(metadata) if metadata is not None else {}
|
||||
if hasattr(request, 'start_time'):
|
||||
metadata['response_time_ms'] = int((time.time() - request.start_time) * 1000)
|
||||
|
||||
if metadata:
|
||||
response_data['metadata'] = metadata
|
||||
|
||||
enriched['response_time_ms'] = int((time.time() - request.start_time) * 1000)
|
||||
|
||||
if metadata is not None or enriched:
|
||||
response_data['metadata'] = enriched
|
||||
|
||||
return jsonify(response_data)
|
||||
|
||||
|
||||
|
||||
@@ -142,14 +142,17 @@ def create_success_response(
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
# All three use `is not None` rather than truthiness: "" and {} are
|
||||
# values a caller chose to send, and dropping them silently would make
|
||||
# the response shape depend on the data.
|
||||
if data is not None:
|
||||
response["data"] = data
|
||||
|
||||
if message:
|
||||
|
||||
if message is not None:
|
||||
response["message"] = message
|
||||
|
||||
if metadata:
|
||||
|
||||
if metadata is not None:
|
||||
response["metadata"] = metadata
|
||||
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -89,7 +89,11 @@ class WebInterfaceError:
|
||||
self.category = category or self._infer_category(error_code)
|
||||
self.details = details
|
||||
self.context = context or {}
|
||||
self.suggested_fixes = suggested_fixes or self._get_default_suggestions(error_code)
|
||||
# `is None`, not truthiness: an explicit [] means "this caller has
|
||||
# no suggestions to offer", which the default list would override.
|
||||
self.suggested_fixes = (
|
||||
suggested_fixes if suggested_fixes is not None
|
||||
else self._get_default_suggestions(error_code))
|
||||
self.original_error = original_error
|
||||
|
||||
def _infer_category(self, error_code: ErrorCode) -> ErrorCategory:
|
||||
|
||||
Reference in New Issue
Block a user