Source code for gps_tracker.client.exceptions

"""Definition of exceptions possibly raised by the Client."""

from __future__ import annotations

import json
from typing import Any, Dict, List, Optional, Type, Union

_homepage: str = "https://gitlab.com/ezlo.picori/gps_tracker/-/issues"


[docs] class GpsTrackerException(Exception): """Base class for gps-tracker exceptions."""
[docs] class UnknownDeviceType(GpsTrackerException): """Exception raised when a device of unknown type is found.""" def __init__(self, device_data: Dict[str, Any]): """Store device data in exception.""" self.device_data = device_data super().__init__( f""" Device of type '{device_data["type"]}' are not supported. Please open an issue at {_homepage} with the following content: {json.dumps(device_data, indent=4)} Obfuscate any sensitive data by replacing letters by 'a' and digits by '0' if needed.""" )
[docs] class UnknownAnswerScheme(GpsTrackerException): """Exception raised when API answer cannot be interpreted.""" def __init__(self, json_data, message, cls): """Store json and error message.""" self.json_data = json_data self.message = message super().__init__( f""" It appears that one of your devices has fields which are not currently recognized. Please open an issue at {_homepage} with the following content: {json.dumps(json_data, indent=4)} {message} when instantiating {cls}. Obfuscate any sensitive data by replacing letters by 'a' and digits by '0' if needed.""" )
[docs] class ApiConnectionError(GpsTrackerException): """Exception raised if connection error occurs during API call."""
[docs] class HttpException(GpsTrackerException): """Base class for HTTP exceptions.""" _registry: Dict[int, Type[HttpException]] = {} _default: Optional[Type[HttpException]] = None def __init_subclass__(cls, code: Optional[int] = None, default: bool = False): """Register subclass with its associated HTTP code.""" if code is not None: if code not in HttpException._registry: HttpException._registry[code] = cls else: raise ValueError( f"Two subclasses defined for HttpException with {code=}." ) if default: HttpException._default = cls
[docs] @staticmethod def get(code: int) -> Optional[Type[HttpException]]: """ Return the subclass associated to code if it exists. :param code: HTTP code returned by the API call :type code: int :return: SubClass of HttpException with correct code if it exists :rtype: Type[HttpException] """ if code in HttpException._registry: return HttpException._registry[code] return None
[docs] @staticmethod def get_default() -> Optional[Type[HttpException]]: """Return the subclass declared as default.""" return HttpException._default
def _message(self) -> Optional[str]: # pylint: disable=no-self-use """Define a specific message for the subclass.""" return None def __init__( self, msg: Optional[str] = None, json_answer: Union[Dict, List, None] = None ): """Store json_answer if provided.""" self.json_answer: Union[Dict, List, None] = json_answer if msg is None: msg = self._message() # pylint: disable=assignment-from-none super().__init__(msg)
[docs] class UnauthorizedQuery(HttpException, code=401): """Exception raised if credentials are incorrect.""" def _message(self) -> Optional[str]: """Return the "detail" message if provided by the API.""" if ( isinstance(self.json_answer, dict) and "detail" in self.json_answer and isinstance(self.json_answer["detail"], str) ): return self.json_answer["detail"] return None
[docs] class ForbiddenQuery(HttpException, code=403): """Exception raised when an API query is forbidden with current credentials.""" def _message(self) -> Optional[str]: """Define message for forbidden queries.""" return "You are not allowed to perform the attempted query."
[docs] class NoContentQuery(HttpException, code=204): """Exception raised when API has no content to return.""" def _message(self) -> Optional[str]: """Define message for no-content queries.""" return "No content is associated to this query."
[docs] class FailedQuery(HttpException, default=True): """Exception raised for any erroneous status code.""" def _message(self) -> Optional[str]: """Define message for default exception.""" return "Query failed with unexpected exception."