""" Исключения Kwork API. Все исключения предоставляют понятные сообщения для отладки. Иерархия исключений: KworkError (базовое) ├── KworkAuthError (ошибки аутентификации) ├── KworkApiError (HTTP ошибки API) │ ├── KworkNotFoundError (404) │ ├── KworkRateLimitError (429) │ └── KworkValidationError (400) └── KworkNetworkError (ошибки сети) """ from typing import Any, Optional class KworkError(Exception): """ Базовое исключение для всех ошибок Kwork API. Все остальные исключения наследуются от этого класса. Attributes: message: Сообщение об ошибке. response: Оригинальный HTTP response (если есть). Example: try: await client.catalog.get_list() except KworkError as e: print(f"Ошибка: {e.message}") """ def __init__(self, message: str, response: Optional[Any] = None): self.message = message self.response = response super().__init__(self.message) def __str__(self) -> str: return f"KworkError: {self.message}" class KworkAuthError(KworkError): """ Ошибка аутентификации/авторизации. Возникает при: - Неверном логине или пароле - Истёкшем или невалидном токене - Отсутствии прав доступа (403) Example: try: client = await KworkClient.login("user", "wrong_password") except KworkAuthError: print("Неверные учётные данные") """ def __init__(self, message: str = "Authentication failed", response: Optional[Any] = None): super().__init__(message, response) def __str__(self) -> str: return f"KworkAuthError: {self.message}" class KworkApiError(KworkError): """ Ошибка HTTP запроса к API (4xx, 5xx). Базовый класс для HTTP ошибок API. Содержит код статуса. Attributes: status_code: HTTP код ответа (400, 404, 500, etc.) Example: try: await client.catalog.get_details(999999) except KworkApiError as e: print(f"HTTP {e.status_code}: {e.message}") """ def __init__( self, message: str, status_code: Optional[int] = None, response: Optional[Any] = None, ): self.status_code = status_code super().__init__(message, response) def __str__(self) -> str: if self.status_code: return f"KworkApiError [{self.status_code}]: {self.message}" return f"KworkApiError: {self.message}" class KworkNotFoundError(KworkApiError): """ Ресурс не найден (404). Возникает при запросе несуществующего кворка, пользователя или другого ресурса. Example: try: await client.catalog.get_details(999999) except KworkNotFoundError: print("Кворк не найден") """ def __init__(self, resource: str, response: Optional[Any] = None): super().__init__(f"Resource not found: {resource}", 404, response) class KworkRateLimitError(KworkApiError): """ Превышен лимит запросов (429). Возникает при слишком частых запросах к API. Рекомендуется сделать паузу перед повторным запросом. Example: import asyncio try: await client.catalog.get_list() except KworkRateLimitError: await asyncio.sleep(5) # Пауза 5 секунд """ def __init__(self, message: str = "Rate limit exceeded", response: Optional[Any] = None): super().__init__(message, 429, response) class KworkValidationError(KworkApiError): """ Ошибка валидации (400). Возникает при некорректных данных запроса. Attributes: fields: Словарь ошибок по полям {field: [errors]}. Example: try: await client.catalog.get_list(page=-1) except KworkValidationError as e: if e.fields: for field, errors in e.fields.items(): print(f"{field}: {errors[0]}") """ def __init__( self, message: str = "Validation failed", fields: Optional[dict[str, list[str]]] = None, response: Optional[Any] = None, ): self.fields = fields or {} super().__init__(message, 400, response) def __str__(self) -> str: if self.fields: field_errors = ", ".join(f"{k}: {v[0]}" for k, v in self.fields.items()) return f"KworkValidationError: {field_errors}" return f"KworkValidationError: {self.message}" class KworkNetworkError(KworkError): """ Ошибка сети/подключения. Возникает при: - Отсутствии соединения - Таймауте запроса - Ошибке DNS - Проблемах с SSL Example: try: await client.catalog.get_list() except KworkNetworkError: print("Проверьте подключение к интернету") """ def __init__(self, message: str = "Network error", response: Optional[Any] = None): super().__init__(message, response) def __str__(self) -> str: return f"KworkNetworkError: {self.message}"