semantic checker script update
This commit is contained in:
@@ -29,7 +29,7 @@ from superset_tool.utils.network import APIClient
|
||||
# @RELATION: CREATES_INSTANCE_OF -> APIClient
|
||||
# @RELATION: USES -> SupersetConfig
|
||||
class SupersetClient:
|
||||
# [DEF:SupersetClient.__init__:Function]
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Инициализирует клиент, проверяет конфигурацию и создает сетевой клиент.
|
||||
# @PRE: `config` должен быть валидным объектом SupersetConfig.
|
||||
# @POST: Атрибуты `logger`, `config`, и `network` созданы и готовы к работе.
|
||||
@@ -48,9 +48,9 @@ class SupersetClient:
|
||||
)
|
||||
self.delete_before_reimport: bool = False
|
||||
self.logger.info("[SupersetClient.__init__][Exit] SupersetClient initialized.")
|
||||
# [/DEF:SupersetClient.__init__:Function]
|
||||
# [/DEF:__init__:Function]
|
||||
|
||||
# [DEF:SupersetClient._validate_config:Function]
|
||||
# [DEF:_validate_config:Function]
|
||||
# @PURPOSE: Проверяет, что переданный объект конфигурации имеет корректный тип.
|
||||
# @PRE: `config` должен быть передан.
|
||||
# @POST: Если проверка пройдена, выполнение продолжается.
|
||||
@@ -60,18 +60,18 @@ class SupersetClient:
|
||||
self.logger.debug("[_validate_config][Enter] Validating SupersetConfig.")
|
||||
assert isinstance(config, SupersetConfig), "Конфигурация должна быть экземпляром SupersetConfig"
|
||||
self.logger.debug("[_validate_config][Exit] Config is valid.")
|
||||
# [/DEF:SupersetClient._validate_config:Function]
|
||||
# [/DEF:_validate_config:Function]
|
||||
|
||||
@property
|
||||
def headers(self) -> dict:
|
||||
# [DEF:SupersetClient.headers:Function]
|
||||
# [DEF:headers:Function]
|
||||
# @PURPOSE: Возвращает базовые HTTP-заголовки, используемые сетевым клиентом.
|
||||
# @PRE: self.network должен быть инициализирован.
|
||||
# @POST: Возвращаемый словарь содержит актуальные заголовки, включая токен авторизации.
|
||||
return self.network.headers
|
||||
# [/DEF:SupersetClient.headers:Function]
|
||||
# [/DEF:headers:Function]
|
||||
|
||||
# [DEF:SupersetClient.get_dashboards:Function]
|
||||
# [DEF:get_dashboards:Function]
|
||||
# @PURPOSE: Получает полный список дашбордов, автоматически обрабатывая пагинацию.
|
||||
# @RELATION: CALLS -> self._fetch_total_object_count
|
||||
# @RELATION: CALLS -> self._fetch_all_pages
|
||||
@@ -93,9 +93,9 @@ class SupersetClient:
|
||||
)
|
||||
self.logger.info("[get_dashboards][Exit] Found %d dashboards.", total_count)
|
||||
return total_count, paginated_data
|
||||
# [/DEF:SupersetClient.get_dashboards:Function]
|
||||
# [/DEF:get_dashboards:Function]
|
||||
|
||||
# [DEF:SupersetClient.export_dashboard:Function]
|
||||
# [DEF:export_dashboard:Function]
|
||||
# @PURPOSE: Экспортирует дашборд в виде ZIP-архива.
|
||||
# @RELATION: CALLS -> self.network.request
|
||||
# @PRE: dashboard_id должен быть положительным целым числом.
|
||||
@@ -118,9 +118,9 @@ class SupersetClient:
|
||||
filename = self._resolve_export_filename(response, dashboard_id)
|
||||
self.logger.info("[export_dashboard][Exit] Exported dashboard %s to %s.", dashboard_id, filename)
|
||||
return response.content, filename
|
||||
# [/DEF:SupersetClient.export_dashboard:Function]
|
||||
# [/DEF:export_dashboard:Function]
|
||||
|
||||
# [DEF:SupersetClient.import_dashboard:Function]
|
||||
# [DEF:import_dashboard:Function]
|
||||
# @PURPOSE: Импортирует дашборд из ZIP-файла с возможностью автоматического удаления и повторной попытки при ошибке.
|
||||
# @RELATION: CALLS -> self._do_import
|
||||
# @RELATION: CALLS -> self.delete_dashboard
|
||||
@@ -152,9 +152,9 @@ class SupersetClient:
|
||||
self.delete_dashboard(target_id)
|
||||
self.logger.info("[import_dashboard][State] Deleted dashboard ID %s, retrying import.", target_id)
|
||||
return self._do_import(file_path)
|
||||
# [/DEF:SupersetClient.import_dashboard:Function]
|
||||
# [/DEF:import_dashboard:Function]
|
||||
|
||||
# [DEF:SupersetClient._resolve_target_id_for_delete:Function]
|
||||
# [DEF:_resolve_target_id_for_delete:Function]
|
||||
# @PURPOSE: Определяет ID дашборда для удаления, используя ID или slug.
|
||||
# @PARAM: dash_id (Optional[int]) - ID дашборда.
|
||||
# @PARAM: dash_slug (Optional[str]) - Slug дашборда.
|
||||
@@ -177,9 +177,9 @@ class SupersetClient:
|
||||
except Exception as e:
|
||||
self.logger.warning("[_resolve_target_id_for_delete][Warning] Could not resolve slug '%s' to ID: %s", dash_slug, e)
|
||||
return None
|
||||
# [/DEF:SupersetClient._resolve_target_id_for_delete:Function]
|
||||
# [/DEF:_resolve_target_id_for_delete:Function]
|
||||
|
||||
# [DEF:SupersetClient._do_import:Function]
|
||||
# [DEF:_do_import:Function]
|
||||
# @PURPOSE: Выполняет один запрос на импорт без обработки исключений.
|
||||
# @PRE: Файл должен существовать.
|
||||
# @POST: Файл успешно загружен, возвращен ответ API.
|
||||
@@ -200,9 +200,9 @@ class SupersetClient:
|
||||
extra_data={"overwrite": "true"},
|
||||
timeout=self.config.timeout * 2,
|
||||
)
|
||||
# [/DEF:SupersetClient._do_import:Function]
|
||||
# [/DEF:_do_import:Function]
|
||||
|
||||
# [DEF:SupersetClient.delete_dashboard:Function]
|
||||
# [DEF:delete_dashboard:Function]
|
||||
# @PURPOSE: Удаляет дашборд по его ID или slug.
|
||||
# @RELATION: CALLS -> self.network.request
|
||||
# @PRE: dashboard_id должен быть предоставлен.
|
||||
@@ -218,9 +218,9 @@ class SupersetClient:
|
||||
self.logger.info("[delete_dashboard][Success] Dashboard %s deleted.", dashboard_id)
|
||||
else:
|
||||
self.logger.warning("[delete_dashboard][Warning] Unexpected response while deleting %s: %s", dashboard_id, response)
|
||||
# [/DEF:SupersetClient.delete_dashboard:Function]
|
||||
# [/DEF:delete_dashboard:Function]
|
||||
|
||||
# [DEF:SupersetClient._extract_dashboard_id_from_zip:Function]
|
||||
# [DEF:_extract_dashboard_id_from_zip:Function]
|
||||
# @PURPOSE: Извлекает ID дашборда из `metadata.yaml` внутри ZIP-архива.
|
||||
# @PARAM: file_name (Union[str, Path]) - Путь к ZIP-файлу.
|
||||
# @PRE: Файл, указанный в `file_name`, должен быть валидным ZIP-архивом.
|
||||
@@ -241,9 +241,9 @@ class SupersetClient:
|
||||
except Exception as exc:
|
||||
self.logger.error("[_extract_dashboard_id_from_zip][Failure] %s", exc, exc_info=True)
|
||||
return None
|
||||
# [/DEF:SupersetClient._extract_dashboard_id_from_zip:Function]
|
||||
# [/DEF:_extract_dashboard_id_from_zip:Function]
|
||||
|
||||
# [DEF:SupersetClient._extract_dashboard_slug_from_zip:Function]
|
||||
# [DEF:_extract_dashboard_slug_from_zip:Function]
|
||||
# @PURPOSE: Извлекает slug дашборда из `metadata.yaml` внутри ZIP-архива.
|
||||
# @PARAM: file_name (Union[str, Path]) - Путь к ZIP-файлу.
|
||||
# @PRE: Файл, указанный в `file_name`, должен быть валидным ZIP-архивом.
|
||||
@@ -264,9 +264,9 @@ class SupersetClient:
|
||||
except Exception as exc:
|
||||
self.logger.error("[_extract_dashboard_slug_from_zip][Failure] %s", exc, exc_info=True)
|
||||
return None
|
||||
# [/DEF:SupersetClient._extract_dashboard_slug_from_zip:Function]
|
||||
# [/DEF:_extract_dashboard_slug_from_zip:Function]
|
||||
|
||||
# [DEF:SupersetClient._validate_export_response:Function]
|
||||
# [DEF:_validate_export_response:Function]
|
||||
# @PURPOSE: Проверяет, что HTTP-ответ на экспорт является валидным ZIP-архивом.
|
||||
# @PRE: response должен быть объектом requests.Response.
|
||||
# @POST: Проверка пройдена, если ответ является непустым ZIP-архивом.
|
||||
@@ -280,9 +280,9 @@ class SupersetClient:
|
||||
raise ExportError(f"Получен не ZIP-архив (Content-Type: {content_type})")
|
||||
if not response.content:
|
||||
raise ExportError("Получены пустые данные при экспорте")
|
||||
# [/DEF:SupersetClient._validate_export_response:Function]
|
||||
# [/DEF:_validate_export_response:Function]
|
||||
|
||||
# [DEF:SupersetClient._resolve_export_filename:Function]
|
||||
# [DEF:_resolve_export_filename:Function]
|
||||
# @PURPOSE: Определяет имя файла для экспорта из заголовков или генерирует его.
|
||||
# @PRE: response должен быть объектом requests.Response.
|
||||
# @POST: Возвращает непустое имя файла.
|
||||
@@ -298,9 +298,9 @@ class SupersetClient:
|
||||
filename = f"dashboard_export_{dashboard_id}_{timestamp}.zip"
|
||||
self.logger.warning("[_resolve_export_filename][Warning] Generated filename: %s", filename)
|
||||
return filename
|
||||
# [/DEF:SupersetClient._resolve_export_filename:Function]
|
||||
# [/DEF:_resolve_export_filename:Function]
|
||||
|
||||
# [DEF:SupersetClient._validate_query_params:Function]
|
||||
# [DEF:_validate_query_params:Function]
|
||||
# @PURPOSE: Формирует корректный набор параметров запроса с пагинацией.
|
||||
# @PARAM: query (Optional[Dict]) - Исходные параметры.
|
||||
# @PRE: query, если предоставлен, должен быть словарем.
|
||||
@@ -310,9 +310,9 @@ class SupersetClient:
|
||||
assert query is None or isinstance(query, dict), "[_validate_query_params][PRE] query must be a dictionary or None."
|
||||
base_query = {"page": 0, "page_size": 1000}
|
||||
return {**base_query, **(query or {})}
|
||||
# [/DEF:SupersetClient._validate_query_params:Function]
|
||||
# [/DEF:_validate_query_params:Function]
|
||||
|
||||
# [DEF:SupersetClient._fetch_total_object_count:Function]
|
||||
# [DEF:_fetch_total_object_count:Function]
|
||||
# @PURPOSE: Получает общее количество объектов по указанному эндпоинту для пагинации.
|
||||
# @PARAM: endpoint (str) - API эндпоинт.
|
||||
# @PRE: endpoint должен быть непустой строкой.
|
||||
@@ -326,9 +326,9 @@ class SupersetClient:
|
||||
query_params={"page": 0, "page_size": 1},
|
||||
count_field="count",
|
||||
)
|
||||
# [/DEF:SupersetClient._fetch_total_object_count:Function]
|
||||
# [/DEF:_fetch_total_object_count:Function]
|
||||
|
||||
# [DEF:SupersetClient._fetch_all_pages:Function]
|
||||
# [DEF:_fetch_all_pages:Function]
|
||||
# @PURPOSE: Итерируется по всем страницам пагинированного API и собирает все данные.
|
||||
# @PARAM: endpoint (str) - API эндпоинт.
|
||||
# @PARAM: pagination_options (Dict) - Опции пагинации.
|
||||
@@ -340,9 +340,9 @@ class SupersetClient:
|
||||
assert endpoint and isinstance(endpoint, str), "[_fetch_all_pages][PRE] endpoint must be a non-empty string."
|
||||
assert isinstance(pagination_options, dict), "[_fetch_all_pages][PRE] pagination_options must be a dictionary."
|
||||
return self.network.fetch_paginated_data(endpoint=endpoint, pagination_options=pagination_options)
|
||||
# [/DEF:SupersetClient._fetch_all_pages:Function]
|
||||
# [/DEF:_fetch_all_pages:Function]
|
||||
|
||||
# [DEF:SupersetClient._validate_import_file:Function]
|
||||
# [DEF:_validate_import_file:Function]
|
||||
# @PURPOSE: Проверяет, что файл существует, является ZIP-архивом и содержит `metadata.yaml`.
|
||||
# @PRE: zip_path должен быть предоставлен.
|
||||
# @POST: Проверка пройдена, если файл существует, является ZIP и содержит `metadata.yaml`.
|
||||
@@ -356,9 +356,9 @@ class SupersetClient:
|
||||
assert zipfile.is_zipfile(path), f"Файл {zip_path} не является ZIP-архивом"
|
||||
with zipfile.ZipFile(path, "r") as zf:
|
||||
assert any(n.endswith("metadata.yaml") for n in zf.namelist()), f"Архив {zip_path} не содержит 'metadata.yaml'"
|
||||
# [/DEF:SupersetClient._validate_import_file:Function]
|
||||
# [/DEF:_validate_import_file:Function]
|
||||
|
||||
# [DEF:SupersetClient.get_datasets:Function]
|
||||
# [DEF:get_datasets:Function]
|
||||
# @PURPOSE: Получает полный список датасетов, автоматически обрабатывая пагинацию.
|
||||
# @RELATION: CALLS -> self._fetch_total_object_count
|
||||
# @RELATION: CALLS -> self._fetch_all_pages
|
||||
@@ -379,9 +379,9 @@ class SupersetClient:
|
||||
)
|
||||
self.logger.info("[get_datasets][Exit] Found %d datasets.", total_count)
|
||||
return total_count, paginated_data
|
||||
# [/DEF:SupersetClient.get_datasets:Function]
|
||||
# [/DEF:get_datasets:Function]
|
||||
|
||||
# [DEF:SupersetClient.get_databases:Function]
|
||||
# [DEF:get_databases:Function]
|
||||
# @PURPOSE: Получает полный список баз данных, автоматически обрабатывая пагинацию.
|
||||
# @RELATION: CALLS -> self._fetch_total_object_count
|
||||
# @RELATION: CALLS -> self._fetch_all_pages
|
||||
@@ -403,9 +403,9 @@ class SupersetClient:
|
||||
)
|
||||
self.logger.info("[get_databases][Exit] Found %d databases.", total_count)
|
||||
return total_count, paginated_data
|
||||
# [/DEF:SupersetClient.get_databases:Function]
|
||||
# [/DEF:get_databases:Function]
|
||||
|
||||
# [DEF:SupersetClient.get_dataset:Function]
|
||||
# [DEF:get_dataset:Function]
|
||||
# @PURPOSE: Получает информацию о конкретном датасете по его ID.
|
||||
# @RELATION: CALLS -> self.network.request
|
||||
# @PARAM: dataset_id (int) - ID датасета.
|
||||
@@ -420,9 +420,9 @@ class SupersetClient:
|
||||
response = cast(Dict, response)
|
||||
self.logger.info("[get_dataset][Exit] Got dataset %s.", dataset_id)
|
||||
return response
|
||||
# [/DEF:SupersetClient.get_dataset:Function]
|
||||
# [/DEF:get_dataset:Function]
|
||||
|
||||
# [DEF:SupersetClient.get_database:Function]
|
||||
# [DEF:get_database:Function]
|
||||
# @PURPOSE: Получает информацию о конкретной базе данных по её ID.
|
||||
# @RELATION: CALLS -> self.network.request
|
||||
# @PARAM: database_id (int) - ID базы данных.
|
||||
@@ -437,9 +437,9 @@ class SupersetClient:
|
||||
response = cast(Dict, response)
|
||||
self.logger.info("[get_database][Exit] Got database %s.", database_id)
|
||||
return response
|
||||
# [/DEF:SupersetClient.get_database:Function]
|
||||
# [/DEF:get_database:Function]
|
||||
|
||||
# [DEF:SupersetClient.update_dataset:Function]
|
||||
# [DEF:update_dataset:Function]
|
||||
# @PURPOSE: Обновляет данные датасета по его ID.
|
||||
# @RELATION: CALLS -> self.network.request
|
||||
# @PARAM: dataset_id (int) - ID датасета.
|
||||
@@ -461,7 +461,7 @@ class SupersetClient:
|
||||
response = cast(Dict, response)
|
||||
self.logger.info("[update_dataset][Exit] Updated dataset %s.", dataset_id)
|
||||
return response
|
||||
# [/DEF:SupersetClient.update_dataset:Function]
|
||||
# [/DEF:update_dataset:Function]
|
||||
|
||||
# [/DEF:SupersetClient:Class]
|
||||
|
||||
|
||||
@@ -14,9 +14,14 @@ from typing import Optional, Dict, Any, Union
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Optional[Dict[str, Any]]) - Дополнительный контекст ошибки.
|
||||
class SupersetToolError(Exception):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes the base tool error.
|
||||
# @PRE: message is a string, context is optional dict.
|
||||
# @POST: Error is initialized with combined message and context.
|
||||
def __init__(self, message: str, context: Optional[Dict[str, Any]] = None):
|
||||
self.context = context or {}
|
||||
super().__init__(f"{message} | Context: {self.context}")
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:SupersetToolError:Class]
|
||||
|
||||
# [DEF:AuthenticationError:Class]
|
||||
@@ -25,8 +30,13 @@ class SupersetToolError(Exception):
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class AuthenticationError(SupersetToolError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes an authentication error.
|
||||
# @PRE: Optional message and context.
|
||||
# @POST: Error is initialized with authentication context.
|
||||
def __init__(self, message: str = "Authentication failed", **context: Any):
|
||||
super().__init__(f"[AUTH_FAILURE] {message}", context={"type": "authentication", **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:AuthenticationError:Class]
|
||||
|
||||
# [DEF:PermissionDeniedError:Class]
|
||||
@@ -36,9 +46,14 @@ class AuthenticationError(SupersetToolError):
|
||||
# @PARAM: required_permission (Optional[str]) - Требуемое разрешение.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class PermissionDeniedError(AuthenticationError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes a permission denied error.
|
||||
# @PRE: Optional message, permission string, and context.
|
||||
# @POST: Error is initialized with permission details.
|
||||
def __init__(self, message: str = "Permission denied", required_permission: Optional[str] = None, **context: Any):
|
||||
full_message = f"Permission denied: {required_permission}" if required_permission else message
|
||||
super().__init__(full_message, context={"required_permission": required_permission, **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:PermissionDeniedError:Class]
|
||||
|
||||
# [DEF:SupersetAPIError:Class]
|
||||
@@ -47,8 +62,13 @@ class PermissionDeniedError(AuthenticationError):
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class SupersetAPIError(SupersetToolError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes a Superset API error.
|
||||
# @PRE: Optional message and context.
|
||||
# @POST: Error is initialized with API failure context.
|
||||
def __init__(self, message: str = "Superset API error", **context: Any):
|
||||
super().__init__(f"[API_FAILURE] {message}", context={"type": "api_call", **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:SupersetAPIError:Class]
|
||||
|
||||
# [DEF:ExportError:Class]
|
||||
@@ -57,8 +77,13 @@ class SupersetAPIError(SupersetToolError):
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class ExportError(SupersetAPIError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes an export error.
|
||||
# @PRE: Optional message and context.
|
||||
# @POST: Error is initialized with export failure subtype.
|
||||
def __init__(self, message: str = "Dashboard export failed", **context: Any):
|
||||
super().__init__(f"[EXPORT_FAILURE] {message}", context={"subtype": "export", **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:ExportError:Class]
|
||||
|
||||
# [DEF:DashboardNotFoundError:Class]
|
||||
@@ -68,8 +93,13 @@ class ExportError(SupersetAPIError):
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class DashboardNotFoundError(SupersetAPIError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes a dashboard not found error.
|
||||
# @PRE: dashboard_id_or_slug is provided.
|
||||
# @POST: Error is initialized with resource identification.
|
||||
def __init__(self, dashboard_id_or_slug: Union[int, str], message: str = "Dashboard not found", **context: Any):
|
||||
super().__init__(f"[NOT_FOUND] Dashboard '{dashboard_id_or_slug}' {message}", context={"subtype": "not_found", "resource_id": dashboard_id_or_slug, **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:DashboardNotFoundError:Class]
|
||||
|
||||
# [DEF:DatasetNotFoundError:Class]
|
||||
@@ -79,8 +109,13 @@ class DashboardNotFoundError(SupersetAPIError):
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class DatasetNotFoundError(SupersetAPIError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes a dataset not found error.
|
||||
# @PRE: dataset_id_or_slug is provided.
|
||||
# @POST: Error is initialized with resource identification.
|
||||
def __init__(self, dataset_id_or_slug: Union[int, str], message: str = "Dataset not found", **context: Any):
|
||||
super().__init__(f"[NOT_FOUND] Dataset '{dataset_id_or_slug}' {message}", context={"subtype": "not_found", "resource_id": dataset_id_or_slug, **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:DatasetNotFoundError:Class]
|
||||
|
||||
# [DEF:InvalidZipFormatError:Class]
|
||||
@@ -90,8 +125,13 @@ class DatasetNotFoundError(SupersetAPIError):
|
||||
# @PARAM: file_path (Optional[Union[str, Path]]) - Путь к файлу.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class InvalidZipFormatError(SupersetToolError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes an invalid ZIP format error.
|
||||
# @PRE: Optional message, file path, and context.
|
||||
# @POST: Error is initialized with file validation context.
|
||||
def __init__(self, message: str = "Invalid ZIP format or content", file_path: Optional[Union[str, Path]] = None, **context: Any):
|
||||
super().__init__(f"[FILE_ERROR] {message}", context={"type": "file_validation", "file_path": str(file_path) if file_path else "N/A", **context})
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:InvalidZipFormatError:Class]
|
||||
|
||||
# [DEF:NetworkError:Class]
|
||||
@@ -100,6 +140,10 @@ class InvalidZipFormatError(SupersetToolError):
|
||||
# @PARAM: message (str) - Сообщение об ошибке.
|
||||
# @PARAM: context (Any) - Дополнительный контекст ошибки.
|
||||
class NetworkError(SupersetToolError):
|
||||
# [DEF:__init__:Function]
|
||||
# @PURPOSE: Initializes a network error.
|
||||
# @PRE: Optional message and context.
|
||||
# @POST: Error is initialized with network failure context.
|
||||
def __init__(self, message: str = "Network connection failed", **context: Any):
|
||||
super().__init__(f"[NETWORK_FAILURE] {message}", context={"type": "network", **context})
|
||||
# [/DEF:NetworkError:Class]
|
||||
|
||||
@@ -25,7 +25,7 @@ class SupersetConfig(BaseModel):
|
||||
timeout: int = Field(30, description="Таймаут в секундах для HTTP-запросов.")
|
||||
logger: Optional[SupersetLogger] = Field(None, description="Экземпляр логгера для логирования.")
|
||||
|
||||
# [DEF:SupersetConfig.validate_auth:Function]
|
||||
# [DEF:validate_auth:Function]
|
||||
# @PURPOSE: Проверяет, что словарь `auth` содержит все необходимые для аутентификации поля.
|
||||
# @PRE: `v` должен быть словарем.
|
||||
# @POST: Возвращает `v`, если все обязательные поля (`provider`, `username`, `password`, `refresh`) присутствуют.
|
||||
@@ -37,9 +37,9 @@ class SupersetConfig(BaseModel):
|
||||
if not required.issubset(v.keys()):
|
||||
raise ValueError(f"Словарь 'auth' должен содержать поля: {required}. Отсутствующие: {required - v.keys()}")
|
||||
return v
|
||||
# [/DEF:SupersetConfig.validate_auth:Function]
|
||||
# [/DEF:validate_auth:Function]
|
||||
|
||||
# [DEF:SupersetConfig.normalize_base_url:Function]
|
||||
# [DEF:normalize_base_url:Function]
|
||||
# @PURPOSE: Нормализует `base_url`, добавляя `/api/v1`, если он отсутствует.
|
||||
# @PRE: `v` должна быть строкой.
|
||||
# @POST: Возвращает нормализованный `v`.
|
||||
@@ -54,7 +54,7 @@ class SupersetConfig(BaseModel):
|
||||
if '/api/v1' not in v:
|
||||
v = f"{v.rstrip('/')}/api/v1"
|
||||
return v
|
||||
# [/DEF:SupersetConfig.normalize_base_url:Function]
|
||||
# [/DEF:normalize_base_url:Function]
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
@@ -67,7 +67,7 @@ class DatabaseConfig(BaseModel):
|
||||
database_config: Dict[str, Dict[str, Any]] = Field(..., description="Словарь, содержащий 'old' и 'new' конфигурации базы данных.")
|
||||
logger: Optional[SupersetLogger] = Field(None, description="Экземпляр логгера для логирования.")
|
||||
|
||||
# [DEF:DatabaseConfig.validate_config:Function]
|
||||
# [DEF:validate_config:Function]
|
||||
# @PURPOSE: Проверяет, что словарь `database_config` содержит ключи 'old' и 'new'.
|
||||
# @PRE: `v` должен быть словарем.
|
||||
# @POST: Возвращает `v`, если ключи 'old' и 'new' присутствуют.
|
||||
@@ -78,7 +78,7 @@ class DatabaseConfig(BaseModel):
|
||||
if not {'old', 'new'}.issubset(v.keys()):
|
||||
raise ValueError("'database_config' должен содержать ключи 'old' и 'new'.")
|
||||
return v
|
||||
# [/DEF:DatabaseConfig.validate_config:Function]
|
||||
# [/DEF:validate_config:Function]
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
Reference in New Issue
Block a user