from __future__ import annotations from dataclasses import dataclass from typing import Optional @dataclass(frozen=True) class ApiError(Exception): """Raised when API call fails (network or non-2xx).""" message: str method: str url: str status_code: Optional[int] = None response_text: str = "" def __str__(self) -> str: code = f" ({self.status_code})" if self.status_code is not None else "" tail = f": {self.response_text}" if self.response_text else "" return f"{self.message}{code} [{self.method} {self.url}]{tail}"