Source code for pylocal_akuvox.exceptions

# SPDX-FileCopyrightText: 2026 Andrew Grimberg <tykeal@bardicgrove.org>
# SPDX-License-Identifier: Apache-2.0

"""Exception hierarchy for Akuvox device communication errors."""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pylocal_akuvox._capability_types import Capability


[docs] class AkuvoxError(Exception): """Base exception for all Akuvox-related errors."""
[docs] class AkuvoxConnectionError(AkuvoxError): """Network or timeout failure communicating with the device."""
[docs] class AkuvoxAuthenticationError(AkuvoxError): """Authentication rejected by the device (HTTP 401)."""
[docs] class AkuvoxRequestError(AkuvoxError): """Invalid request parameters (HTTP 400)."""
[docs] class AkuvoxDeviceError(AkuvoxError): """Device-side error (HTTP 500 or non-zero retcode)."""
[docs] class AkuvoxParseError(AkuvoxError): """Non-JSON or malformed response from the device."""
[docs] class AkuvoxUnsupportedError(AkuvoxError): """Operation unsupported by the connected device. Carries optional structured fields when raised from the capability-aware surfacing layer (the per-method gate in :class:`pylocal_akuvox.AkuvoxDevice` and the relay-trigger adapter dispatch in :mod:`pylocal_akuvox.capability_adapters`); falls back to a message-only form when raised from the legacy HTTP-envelope classifier in :mod:`pylocal_akuvox._http` (for example when the device returns the well-known ``Api unsupported`` envelope). Backward compatibility is preserved: ``AkuvoxUnsupportedError(msg)`` still constructs an instance with ``.args == (msg,)``, ``str(exc) == msg``, and every structured field set to ``None``. Attributes: capability: The :class:`pylocal_akuvox.Capability` whose absence triggered this error, or ``None`` when raised from a layer without capability context. device_class: The detected device class string (e.g. ``"IT83"``), or ``None`` if unrecognised at the time of the raise. reason: Structured reason code drawn from the closed set ``{"capability_missing", "capability_unknown", "device_unrecognized", "adapter_missing", "envelope_unsupported", None}``. See ``specs/008-capability-matrix/contracts/unsupported-error.md`` for the full taxonomy. """
[docs] def __init__( self, message: str, *, capability: Capability | None = None, device_class: str | None = None, reason: str | None = None, ) -> None: """Construct an unsupported-operation error. Args: message: Human-readable description of the failure. capability: Optional :class:`Capability` that was rejected. device_class: Optional device-class string (e.g. ``"IT83"``). reason: Optional structured reason code; see class docstring for the closed set. """ super().__init__(message) self.capability = capability self.device_class = device_class self.reason = reason
[docs] class AkuvoxValidationError(AkuvoxError): """Local validation failure before sending request."""