+скрипт поиска в датасетах
This commit is contained in:
@@ -151,7 +151,50 @@ class SupersetClient:
|
||||
# [REFACTORING_COMPLETE] Заголовки теперь управляются APIClient.
|
||||
return self.network.headers
|
||||
|
||||
# [SECTION] Основные операции с дашбордами
|
||||
# [SECTION] API для получения списка дашбордов или получения одного дашборда
|
||||
def get_dashboards(self, query: Optional[Dict] = None) -> Tuple[int, List[Dict]]:
|
||||
"""[CONTRACT] Получение списка дашбордов с пагинацией.
|
||||
@pre:
|
||||
- Клиент должен быть авторизован.
|
||||
- Параметры `query` (если предоставлены) должны быть валидны для API Superset.
|
||||
@post:
|
||||
- Возвращает кортеж: (общее_количество_дашбордов, список_метаданных_дашбордов).
|
||||
- Обходит пагинацию для получения всех доступных дашбордов.
|
||||
@invariant:
|
||||
- Всегда возвращает полный список (если `total_count` > 0).
|
||||
@raise:
|
||||
- `SupersetAPIError`: При ошибках API (например, неверный формат ответа).
|
||||
- `NetworkError`: При проблемах с сетью.
|
||||
- `ValueError`: При некорректных параметрах пагинации (внутренняя ошибка).
|
||||
"""
|
||||
self.logger.info("[INFO] Запрос списка всех дашбордов.")
|
||||
# [COHERENCE_CHECK] Валидация и нормализация параметров запроса
|
||||
validated_query = self._validate_query_params(query)
|
||||
self.logger.debug("[DEBUG] Параметры запроса списка дашбордов после валидации.", extra={"validated_query": validated_query})
|
||||
|
||||
try:
|
||||
# [ANCHOR] FETCH_TOTAL_COUNT
|
||||
total_count = self._fetch_total_object_count(endpoint="/dashboard/")
|
||||
self.logger.info(f"[INFO] Обнаружено {total_count} дашбордов в системе.")
|
||||
|
||||
# [ANCHOR] FETCH_ALL_PAGES
|
||||
paginated_data = self._fetch_all_pages(endpoint="/dashboard/",
|
||||
query=validated_query,
|
||||
total_count=total_count)
|
||||
|
||||
self.logger.info(
|
||||
f"[COHERENCE_CHECK_PASSED] Успешно получено {len(paginated_data)} дашбордов из {total_count}."
|
||||
)
|
||||
return total_count, paginated_data
|
||||
|
||||
except (SupersetAPIError, NetworkError, ValueError, PermissionDeniedError) as e:
|
||||
self.logger.error(f"[ERROR] Ошибка при получении списка дашбордов: {str(e)}", exc_info=True, extra=getattr(e, 'context', {}))
|
||||
raise
|
||||
except Exception as e:
|
||||
error_ctx = {"query": query, "error_type": type(e).__name__}
|
||||
self.logger.critical(f"[CRITICAL] Непредвиденная ошибка при получении списка дашбордов: {str(e)}", exc_info=True, extra=error_ctx)
|
||||
raise SupersetAPIError(f"Непредвиденная ошибка: {str(e)}", context=error_ctx) from e
|
||||
|
||||
def get_dashboard(self, dashboard_id_or_slug: str) -> dict:
|
||||
"""[CONTRACT] Получение метаданных дашборда по ID или SLUG.
|
||||
@pre:
|
||||
@@ -183,6 +226,91 @@ class SupersetClient:
|
||||
except Exception as e:
|
||||
self.logger.critical(f"[CRITICAL] Непредвиденная ошибка при получении дашборда '{dashboard_id_or_slug}': {str(e)}", exc_info=True)
|
||||
raise SupersetAPIError(f"Непредвиденная ошибка: {str(e)}", context={"dashboard_id_or_slug": dashboard_id_or_slug}) from e
|
||||
|
||||
# [SECTION] API для получения списка датасетов или получения одного датасета
|
||||
def get_datasets(self, query: Optional[Dict] = None) -> Tuple[int, List[Dict]]:
|
||||
"""[CONTRACT] Получение списка датасетов с пагинацией.
|
||||
@pre:
|
||||
- Клиент должен быть авторизован.
|
||||
- Параметры `query` (если предоставлены) должны быть валидны для API Superset.
|
||||
@post:
|
||||
- Возвращает кортеж: (общее_количество_датасетов, список_метаданных_датасетов).
|
||||
- Обходит пагинацию для получения всех доступных датасетов.
|
||||
@invariant:
|
||||
- Всегда возвращает полный список (если `total_count` > 0).
|
||||
@raise:
|
||||
- `SupersetAPIError`: При ошибках API (например, неверный формат ответа).
|
||||
- `NetworkError`: При проблемах с сетью.
|
||||
- `ValueError`: При некорректных параметрах пагинации (внутренняя ошибка).
|
||||
"""
|
||||
self.logger.info("[INFO] Запрос списка всех датасетов")
|
||||
|
||||
try:
|
||||
# Получаем общее количество датасетов
|
||||
total_count = self._fetch_total_object_count(endpoint="/dataset/")
|
||||
self.logger.info(f"[INFO] Обнаружено {total_count} датасетов в системе")
|
||||
|
||||
# Валидируем параметры запроса
|
||||
base_query = {
|
||||
"columns": ["id", "table_name", "sql", "database", "schema"],
|
||||
"page": 0,
|
||||
"page_size": 100
|
||||
}
|
||||
validated_query = {**base_query, **(query or {})}
|
||||
|
||||
# Получаем все страницы
|
||||
datasets = self._fetch_all_pages(
|
||||
endpoint="/dataset/",
|
||||
query=validated_query,
|
||||
total_count=total_count#,
|
||||
#results_field="result"
|
||||
)
|
||||
|
||||
self.logger.info(
|
||||
f"[COHERENCE_CHECK_PASSED] Успешно получено {len(datasets)} датасетов"
|
||||
)
|
||||
return total_count, datasets
|
||||
|
||||
except Exception as e:
|
||||
error_ctx = {"query": query, "error_type": type(e).__name__}
|
||||
self.logger.error(
|
||||
f"[ERROR] Ошибка получения списка датасетов: {str(e)}",
|
||||
exc_info=True,
|
||||
extra=error_ctx
|
||||
)
|
||||
raise
|
||||
|
||||
def get_dataset(self, dataset_id: str) -> dict:
|
||||
"""[CONTRACT] Получение метаданных датасета по ID.
|
||||
@pre:
|
||||
- `dataset_id` должен быть строкой (ID или slug).
|
||||
- Клиент должен быть аутентифицирован (токены актуальны).
|
||||
@post:
|
||||
- Возвращает `dict` с метаданными датасета.
|
||||
@raise:
|
||||
- `DashboardNotFoundError`: Если дашборд не найден (HTTP 404).
|
||||
- `SupersetAPIError`: При других ошибках API.
|
||||
- `NetworkError`: При проблемах с сетью.
|
||||
"""
|
||||
self.logger.info(f"[INFO] Запрос метаданных дашборда: {dataset_id}")
|
||||
try:
|
||||
response_data = self.network.request(
|
||||
method="GET",
|
||||
endpoint=f"/dataset/{dataset_id}",
|
||||
# headers=self.headers # [REFACTORING_NOTE] APIClient теперь сам добавляет заголовки
|
||||
)
|
||||
# [POSTCONDITION] Проверка структуры ответа
|
||||
if "result" not in response_data:
|
||||
self.logger.warning("[CONTRACT_VIOLATION] Ответ API не содержит поле 'result'", extra={"response": response_data})
|
||||
raise SupersetAPIError("Некорректный формат ответа API при получении дашборда")
|
||||
self.logger.debug(f"[DEBUG] Метаданные дашборда '{dataset_id}' успешно получены.")
|
||||
return response_data["result"]
|
||||
except (DashboardNotFoundError, SupersetAPIError, NetworkError, PermissionDeniedError) as e:
|
||||
self.logger.error(f"[ERROR] Не удалось получить дашборд '{dataset_id}': {str(e)}", exc_info=True, extra=getattr(e, 'context', {}))
|
||||
raise # Перевыброс уже типизированной ошибки
|
||||
except Exception as e:
|
||||
self.logger.critical(f"[CRITICAL] Непредвиденная ошибка при получении дашборда '{dataset_id}': {str(e)}", exc_info=True)
|
||||
raise SupersetAPIError(f"Непредвиденная ошибка: {str(e)}", context={"dashboard_id_or_slug": dataset_id}) from e
|
||||
|
||||
# [SECTION] EXPORT OPERATIONS
|
||||
def export_dashboard(self, dashboard_id: int) -> Tuple[bytes, str]:
|
||||
@@ -341,49 +469,8 @@ class SupersetClient:
|
||||
self.logger.critical(f"[CRITICAL] Непредвиденная ошибка при экспорте в файл: {str(e)}", exc_info=True, extra=error_ctx)
|
||||
raise ExportError(f"Непредвиденная ошибка экспорта в файл: {str(e)}", context=error_ctx) from e
|
||||
|
||||
# [SECTION] API для получения списка дашбордов
|
||||
def get_dashboards(self, query: Optional[Dict] = None) -> Tuple[int, List[Dict]]:
|
||||
"""[CONTRACT] Получение списка дашбордов с пагинацией.
|
||||
@pre:
|
||||
- Клиент должен быть авторизован.
|
||||
- Параметры `query` (если предоставлены) должны быть валидны для API Superset.
|
||||
@post:
|
||||
- Возвращает кортеж: (общее_количество_дашбордов, список_метаданных_дашбордов).
|
||||
- Обходит пагинацию для получения всех доступных дашбордов.
|
||||
@invariant:
|
||||
- Всегда возвращает полный список (если `total_count` > 0).
|
||||
@raise:
|
||||
- `SupersetAPIError`: При ошибках API (например, неверный формат ответа).
|
||||
- `NetworkError`: При проблемах с сетью.
|
||||
- `ValueError`: При некорректных параметрах пагинации (внутренняя ошибка).
|
||||
"""
|
||||
self.logger.info("[INFO] Запрос списка всех дашбордов.")
|
||||
# [COHERENCE_CHECK] Валидация и нормализация параметров запроса
|
||||
validated_query = self._validate_query_params(query)
|
||||
self.logger.debug("[DEBUG] Параметры запроса списка дашбордов после валидации.", extra={"validated_query": validated_query})
|
||||
|
||||
try:
|
||||
# [ANCHOR] FETCH_TOTAL_COUNT
|
||||
total_count = self._fetch_total_count()
|
||||
self.logger.info(f"[INFO] Обнаружено {total_count} дашбордов в системе.")
|
||||
|
||||
# [ANCHOR] FETCH_ALL_PAGES
|
||||
paginated_data = self._fetch_all_pages(validated_query, total_count)
|
||||
|
||||
self.logger.info(
|
||||
f"[COHERENCE_CHECK_PASSED] Успешно получено {len(paginated_data)} дашбордов из {total_count}."
|
||||
)
|
||||
return total_count, paginated_data
|
||||
|
||||
except (SupersetAPIError, NetworkError, ValueError, PermissionDeniedError) as e:
|
||||
self.logger.error(f"[ERROR] Ошибка при получении списка дашбордов: {str(e)}", exc_info=True, extra=getattr(e, 'context', {}))
|
||||
raise
|
||||
except Exception as e:
|
||||
error_ctx = {"query": query, "error_type": type(e).__name__}
|
||||
self.logger.critical(f"[CRITICAL] Непредвиденная ошибка при получении списка дашбордов: {str(e)}", exc_info=True, extra=error_ctx)
|
||||
raise SupersetAPIError(f"Непредвиденная ошибка: {str(e)}", context=error_ctx) from e
|
||||
|
||||
# [SECTION] Импорт
|
||||
# [SECTION] Импорт дашбордов
|
||||
def import_dashboard(self, file_name: Union[str, Path]) -> Dict:
|
||||
"""[CONTRACT] Импорт дашборда из ZIP-архива.
|
||||
@pre:
|
||||
@@ -451,8 +538,8 @@ class SupersetClient:
|
||||
# [COHERENCE_CHECK_PASSED] Параметры запроса сформированы корректно.
|
||||
return {**base_query, **(query or {})}
|
||||
|
||||
def _fetch_total_count(self) -> int:
|
||||
"""[CONTRACT][HELPER] Получение общего количества дашбордов в системе.
|
||||
def _fetch_total_object_count(self, endpoint:str) -> int:
|
||||
"""[CONTRACT][HELPER] Получение общего количества объектов (дашбордов, датасетов, чартов, баз данных) в системе.
|
||||
@delegates:
|
||||
- Сетевой запрос к `APIClient.fetch_paginated_count`.
|
||||
@pre:
|
||||
@@ -471,7 +558,7 @@ class SupersetClient:
|
||||
try:
|
||||
# [REFACTORING_COMPLETE] Использование self.network.fetch_paginated_count
|
||||
count = self.network.fetch_paginated_count(
|
||||
endpoint="/dashboard/",
|
||||
endpoint=endpoint,
|
||||
query_params=query_params_for_count,
|
||||
count_field="count"
|
||||
)
|
||||
@@ -485,13 +572,14 @@ class SupersetClient:
|
||||
self.logger.critical(f"[CRITICAL] Непредвиденная ошибка при получении общего количества: {str(e)}", exc_info=True, extra=error_ctx)
|
||||
raise SupersetAPIError(f"Непредвиденная ошибка при получении count: {str(e)}", context=error_ctx) from e
|
||||
|
||||
def _fetch_all_pages(self, query: Dict, total_count: int) -> List[Dict]:
|
||||
def _fetch_all_pages(self, endpoint:str, query: Dict, total_count: int) -> List[Dict]:
|
||||
"""[CONTRACT][HELPER] Обход всех страниц пагинированного API для получения всех данных.
|
||||
@delegates:
|
||||
- Сетевые запросы к `APIClient.fetch_paginated_data()`.
|
||||
@pre:
|
||||
- `query` должен содержать `page_size`.
|
||||
- `total_count` должен быть корректным общим количеством элементов.
|
||||
- `endpoint` должен содержать часть url запроса, например endpoint="/dashboard/".
|
||||
@post:
|
||||
- Возвращает список всех элементов, собранных со всех страниц.
|
||||
@raise:
|
||||
@@ -506,7 +594,7 @@ class SupersetClient:
|
||||
|
||||
# [REFACTORING_COMPLETE] Использование self.network.fetch_paginated_data
|
||||
all_data = self.network.fetch_paginated_data(
|
||||
endpoint="/dashboard/",
|
||||
endpoint=endpoint,
|
||||
base_query=query,
|
||||
total_count=total_count,
|
||||
results_field="result"
|
||||
|
||||
@@ -17,6 +17,7 @@ from typing import Any, Optional, Tuple, Dict, List, Literal, Union, BinaryIO, L
|
||||
from collections import defaultdict
|
||||
from datetime import date
|
||||
import glob
|
||||
import filecmp
|
||||
from contextlib import contextmanager
|
||||
|
||||
# [IMPORTS] Third-party
|
||||
|
||||
Reference in New Issue
Block a user