Compare commits

...

2 Commits

Author SHA1 Message Date
IluaAir
0b92e342e5 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.
2026-03-26 20:10:05 +03:00
IluaAir
1cc225917e Add OxiApi create_session method for better view 2026-03-26 19:51:51 +03:00
3 changed files with 58 additions and 17 deletions

View File

@@ -1,7 +1,8 @@
from typing import Optional from typing import Optional
from requests import Session from requests import HTTPError, Session
from oxi.adapter import OxiAdapter from oxi.adapter import OxiAdapter
from oxi.exception import OxiAPIError
from .node import Node from .node import Node
@@ -14,15 +15,24 @@ class OxiAPI:
verify: bool = True, verify: bool = True,
): ):
self.base_url = url.rstrip("/") self.base_url = url.rstrip("/")
self._session = Session() self._session = self.__create_session(username, password, verify)
self._adapter = OxiAdapter(timeout=10, max_retries=3)
self._session.mount("https://", self._adapter)
self._session.mount("http://", self._adapter)
self._session.verify = verify
if username and password:
self._session.auth = (username, password)
self.node = Node(self._session, self.base_url) self.node = Node(self._session, self.base_url)
def __create_session(
self,
username: Optional[str] = None,
password: Optional[str] = None,
verify: bool = True,
) -> Session:
session = Session()
adapter = OxiAdapter(timeout=10, max_retries=3)
session.mount("https://", adapter)
session.mount("http://", adapter)
session.verify = verify
if username and password:
session.auth = (username, password)
return session
def __enter__(self): def __enter__(self):
return self return self
@@ -33,6 +43,9 @@ class OxiAPI:
return self._session.close() return self._session.close()
def reload(self): def reload(self):
reload_response = self._session.get(f"{self.base_url}/reload") try:
reload_response.raise_for_status() 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 return reload_response.status_code

View File

@@ -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): class OxiAPIError(Exception):
@@ -10,3 +22,13 @@ class OxiAPIError(Exception):
if self.status_code is not None: if self.status_code is not None:
return f"OxiAPIError: {self.args[0]} (HTTP {self.status_code})" return f"OxiAPIError: {self.args[0]} (HTTP {self.status_code})"
return f"OxiAPIError: {self.args[0]}" 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)

View File

@@ -1,5 +1,9 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from requests import HTTPError
from oxi.exception import OxiAPIError
from .view import NodeView from .view import NodeView
@@ -7,18 +11,20 @@ if TYPE_CHECKING:
from requests import Session from requests import Session
# TODO: Add type hints
class Node: class Node:
def __init__(self, session: "Session", base_url: str): def __init__(self, session: "Session", base_url: str):
self._session = session self._session = session
self._base_url = base_url self._base_url = base_url
def __call__(self, name: str) -> NodeView: def __call__(self, name: str) -> NodeView:
url = f"{self._base_url}/node/show/{name}" try:
if not url.endswith(".json"): url = f"{self._base_url}/node/show/{name}"
url += ".json" if not url.endswith(".json"):
response = self._session.get(url) url += ".json"
response.raise_for_status() 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( return NodeView(
session=self._session, base_url=self._base_url, data=response.json() session=self._session, base_url=self._base_url, data=response.json()
) )