From cd8e783b4c823049f46fc2a1a838c497e5f96ba3 Mon Sep 17 00:00:00 2001 From: Jennings Zhang Date: Thu, 25 Jul 2024 14:15:43 -0400 Subject: [PATCH] Improve exception names and documentation --- src/aiochris/errors.py | 44 +++++++++++++++++++++++++++++++++---- src/aiochris/link/linked.py | 9 ++++---- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/aiochris/errors.py b/src/aiochris/errors.py index 625e209..2004b5e 100644 --- a/src/aiochris/errors.py +++ b/src/aiochris/errors.py @@ -1,4 +1,7 @@ +from typing import Optional, Any + import aiohttp +import yarl async def raise_for_status(res: aiohttp.ClientResponse) -> None: @@ -8,6 +11,8 @@ async def raise_for_status(res: aiohttp.ClientResponse) -> None: if res.status < 400: res.raise_for_status() return + if res.status == 401: + raise UnauthorizedError() exception = BadRequestError if res.status < 500 else InternalServerError try: raise exception(res.status, res.url, await res.json()) @@ -16,26 +21,57 @@ async def raise_for_status(res: aiohttp.ClientResponse) -> None: class BaseClientError(Exception): + """Base error raised by aiochris functions.""" + pass -class ResponseError(BaseClientError): +class StatusError(BaseClientError): + """Base exception for 4xx and 5xx HTTP codes.""" + + def __init__( + self, + status: int, + url: yarl.URL, + message: Optional[Any] = None, + request_data: Optional[Any] = None, + ): + super().__init__() + self.status = status + """HTTP status code""" + self.url = url + """URL where this error comes from""" + self.message = message + """Response body""" + self.request_data = request_data + """Request body""" + + +class BadRequestError(StatusError): + """Bad request error.""" + pass -class BadRequestError(ResponseError): +class InternalServerError(StatusError): + """Internal server error.""" + pass -class InternalServerError(ResponseError): +class UnauthorizedError(BaseClientError): + """Unauthorized request.""" + pass class IncorrectLoginError(BaseClientError): + """Failed HTTP basic auth with bad username or password.""" + pass -class NonsenseResponseError(ResponseError): +class NonsenseResponseError(BaseClientError): """CUBE returned data which does not make sense.""" pass diff --git a/src/aiochris/link/linked.py b/src/aiochris/link/linked.py index 7639ad6..5bb0282 100644 --- a/src/aiochris/link/linked.py +++ b/src/aiochris/link/linked.py @@ -16,7 +16,7 @@ import yarl import importlib -from aiochris.errors import raise_for_status, ResponseError +from aiochris.errors import raise_for_status, StatusError T = TypeVar("T") @@ -150,8 +150,9 @@ async def deserialize_res( async with sent_request as res: try: await raise_for_status(res) - except ResponseError as e: - raise e.__class__(*e.args, f"data={sent_data}") + except StatusError as e: + e.request_data = sent_data + raise e if return_type is type(None): # noqa return None sent_data = await res.json(content_type="application/json") @@ -175,4 +176,4 @@ def _beartype_workaround410(t): """ See https://github.com/beartype/beartype/issues/410#issuecomment-2249195428 """ - return getattr(t, '__type_beartype__', None) or t + return getattr(t, "__type_beartype__", None) or t