add errors
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user