add errors

This commit is contained in:
Volobuev Andrey
2025-04-24 18:10:02 +03:00
parent 625b50a6d2
commit 03731e2d77
4 changed files with 168 additions and 45 deletions

View File

@@ -9,7 +9,6 @@ from .exceptions import *
from .models import SupersetConfig
from .utils.logger import SupersetLogger
class SupersetClient:
def __init__(self, config: SupersetConfig):
self.config = config
@@ -238,22 +237,14 @@ class SupersetClient:
raise SupersetAPIError(f"Export failed: {str(e)}") from e
def import_dashboard(self, zip_path) -> Dict:
"""Импортирует дашборд в Superset из ZIP-архива.
"""Импортирует дашборд в Superset из ZIP-архива с детальной обработкой ошибок.
Параметры:
zip_path (Path): Путь к ZIP-файлу с дашбордом для импорта
zip_path (Union[str, Path]): Путь к ZIP-файлу с дашбордом
Возвращает:
dict: Ответ API в формате JSON с результатами импорта
Исключения:
RuntimeError: Вызывается при:
- Ошибках сети/соединения
- Невалидном формате ZIP-архива
- Конфликте прав доступа
- Ошибках сервера (status code >= 400)
- Попытке перезаписи без соответствующих прав
Пример использования:
result = client.import_dashboard(Path("my_dashboard.zip"))
print(f"Импортирован дашборд: {result['title']}")
@@ -269,36 +260,76 @@ class SupersetClient:
"""
url = f"{self.config.base_url}/dashboard/import/"
self.logger.debug(f"Импортируем дашборд ID {zip_path} на {url}...")
headers_without_content_type = {
k: v for k, v in self.headers.items() if k.lower() != 'content-type'}
zip_name = zip_path.name
# Подготавливаем данные для multipart/form-data
with open(zip_path, 'rb') as f:
files = {
'formData': (
zip_name, # Имя файла
f, # Файловый объект
'application/x-zip-compressed' # MIME-тип из curl
)
}
# Отправляем запрос
response = self.session.post(
url,
files=files,
data={'overwrite': 'true'},
headers=headers_without_content_type,
timeout=self.config.timeout * 2 # Longer timeout for imports
)
# Обрабатываем ответ
# Валидация входного файла
try:
response.raise_for_status()
self.logger.info(f"Дашборд импортирован успешно")
return response.json()
except requests.exceptions.HTTPError as e:
self.logger.error(f"Ошибка при импорте: {str(e)}", exc_info=True)
error_detail = f"{e.response.status_code} {e.response.reason}"
if e.response.text:
error_detail += f"\nТело ответа: {e.response.text}"
raise RuntimeError(f"Ошибка импорта: {error_detail}") from e
if not Path(zip_path).exists():
raise FileNotFoundError(f"Файл не найден: {zip_path}")
if not zipfile.is_zipfile(zip_path):
raise InvalidZipFormatError(f"Файл не является ZIP-архивом: {zip_path}")
# Дополнительная проверка содержимого архива
with zipfile.ZipFile(zip_path) as zf:
if not any(name.endswith('metadata.yaml') for name in zf.namelist()):
raise DashboardNotFoundError("Архив не содержит metadata.yaml")
except (FileNotFoundError, InvalidZipFormatError, DashboardNotFoundError) as e:
self.logger.error(f"Ошибка валидации архива: {str(e)}", exc_info=True)
raise
headers = {
k: v for k, v in self.headers.items()
if k.lower() != 'content-type'
}
try:
with open(zip_path, 'rb') as f:
files = {
'formData': (
Path(zip_path).name,
f,
'application/x-zip-compressed'
)
}
response = self.session.post(
url,
files=files,
data={'overwrite': 'true'},
headers=headers,
timeout=self.config.timeout * 2
)
# Обработка HTTP-ошибок
if response.status_code == 404:
raise DashboardNotFoundError("Эндпоинт импорта не найден")
elif response.status_code == 403:
raise PermissionDeniedError("Недостаточно прав для импорта")
elif response.status_code >= 500:
raise SupersetServerError(f"Ошибка сервера: {response.status_code}")
response.raise_for_status()
self.logger.info(f"Дашборд успешно импортирован из {zip_path}")
return response.json()
except requests.exceptions.ConnectionError as e:
error_msg = f"Ошибка соединения: {str(e)}"
self.logger.error(error_msg, exc_info=True)
raise NetworkError(error_msg) from e
except requests.exceptions.Timeout as e:
error_msg = f"Таймаут при импорте дашборда"
self.logger.error(error_msg, exc_info=True)
raise NetworkError(error_msg) from e
except requests.exceptions.RequestException as e:
error_msg = f"Ошибка при импорте: {str(e)}"
self.logger.error(error_msg, exc_info=True)
raise DashboardImportError(error_msg) from e
except Exception as e:
error_msg = f"Неожиданная ошибка: {str(e)}"
self.logger.critical(error_msg, exc_info=True)
raise DashboardImportError(error_msg) from e