From 0b92e342e5f8193b5bf4686560e78ef23b868d1e Mon Sep 17 00:00:00 2001 From: IluaAir Date: Thu, 26 Mar 2026 20:10:05 +0300 Subject: [PATCH] Enhance error handling in OxiAPI and Node classes - Updated the `reload` method in the `OxiAPI` class to catch `HTTPError` exceptions and raise a custom `OxiAPIError` with context. - Improved the `__call__` method in the `Node` class to handle `HTTPError` exceptions similarly, providing context-specific error messages. - Introduced a new class method `from_http_error` in `OxiAPIError` for standardized error message generation based on HTTP status codes. --- oxi/core.py | 10 +++++++--- oxi/exception.py | 24 +++++++++++++++++++++++- oxi/node.py | 18 ++++++++++++------ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/oxi/core.py b/oxi/core.py index dc23219..5662c85 100644 --- a/oxi/core.py +++ b/oxi/core.py @@ -1,7 +1,8 @@ from typing import Optional -from requests import Session +from requests import HTTPError, Session from oxi.adapter import OxiAdapter +from oxi.exception import OxiAPIError from .node import Node @@ -42,6 +43,9 @@ class OxiAPI: return self._session.close() def reload(self): - reload_response = self._session.get(f"{self.base_url}/reload") - reload_response.raise_for_status() + try: + reload_response = self._session.get(f"{self.base_url}/reload") + reload_response.raise_for_status() + except HTTPError as e: + raise OxiAPIError.from_http_error(e, context="Reload Oxidized") from e return reload_response.status_code diff --git a/oxi/exception.py b/oxi/exception.py index 77f746b..614627d 100644 --- a/oxi/exception.py +++ b/oxi/exception.py @@ -1,4 +1,16 @@ -from typing import Optional +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from requests import HTTPError + +_STATUS_MESSAGES: dict[int, str] = { + 401: "Unauthorized", + 403: "Forbidden", + 500: "Internal Server Error", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", +} class OxiAPIError(Exception): @@ -10,3 +22,13 @@ class OxiAPIError(Exception): if self.status_code is not None: return f"OxiAPIError: {self.args[0]} (HTTP {self.status_code})" return f"OxiAPIError: {self.args[0]}" + + @classmethod + def from_http_error(cls, e: "HTTPError", context: str = "") -> "OxiAPIError": + status = e.response.status_code + if status == 404: + message = f"{context} not found" if context else "Not found" + else: + base = _STATUS_MESSAGES.get(status) or e.response.reason or f"HTTP {status}" + message = f"{context}: {base}" if context else base + return cls(message, status) diff --git a/oxi/node.py b/oxi/node.py index 0ea9b20..828970f 100644 --- a/oxi/node.py +++ b/oxi/node.py @@ -1,5 +1,9 @@ from typing import TYPE_CHECKING +from requests import HTTPError + +from oxi.exception import OxiAPIError + from .view import NodeView @@ -7,18 +11,20 @@ if TYPE_CHECKING: from requests import Session -# TODO: Add type hints class Node: def __init__(self, session: "Session", base_url: str): self._session = session self._base_url = base_url def __call__(self, name: str) -> NodeView: - url = f"{self._base_url}/node/show/{name}" - if not url.endswith(".json"): - url += ".json" - response = self._session.get(url) - response.raise_for_status() + try: + url = f"{self._base_url}/node/show/{name}" + if not url.endswith(".json"): + url += ".json" + response = self._session.get(url) + response.raise_for_status() + except HTTPError as e: + raise OxiAPIError.from_http_error(e, context=f"Node {name}") from e return NodeView( session=self._session, base_url=self._base_url, data=response.json() )