mapper + lint

This commit is contained in:
2025-10-06 18:49:40 +03:00
parent b550cb38ff
commit 74b7779e45
18 changed files with 4512 additions and 2250 deletions

View File

@@ -1,91 +1,82 @@
# pylint: disable=no-self-argument,too-few-public-methods
"""
[MODULE] Сущности данных конфигурации
@desc: Определяет структуры данных, используемые для конфигурации и трансформации в инструменте Superset.
"""
# <GRACE_MODULE id="superset_tool.models" name="models.py">
# @SEMANTICS: pydantic, model, config, validation, data-structure
# @PURPOSE: Определяет Pydantic-модели для конфигурации инструмента, обеспечивая валидацию данных.
# @DEPENDS_ON: pydantic -> Для создания моделей и валидации.
# @DEPENDS_ON: superset_tool.utils.logger -> Для логирования в процессе валидации.
# [IMPORTS] Pydantic и Typing
# <IMPORTS>
import re
from typing import Optional, Dict, Any
from pydantic import BaseModel, validator, Field, HttpUrl, VERSION
# [IMPORTS] Локальные модули
from pydantic import BaseModel, validator, Field
from .utils.logger import SupersetLogger
# </IMPORTS>
# --- Начало кода модуля ---
# <ANCHOR id="SupersetConfig" type="DataClass">
# @PURPOSE: Модель конфигурации для подключения к одному экземпляру Superset API.
# @INHERITS_FROM: pydantic.BaseModel
class SupersetConfig(BaseModel):
"""
[CONFIG] Конфигурация подключения к Superset API.
"""
env: str = Field(..., description="Название окружения (например, dev, prod).")
base_url: str = Field(..., description="Базовый URL Superset API, включая версию /api/v1.", pattern=r'.*/api/v1.*')
base_url: str = Field(..., description="Базовый URL Superset API, включая /api/v1.")
auth: Dict[str, str] = Field(..., description="Словарь с данными для аутентификации (provider, username, password, refresh).")
verify_ssl: bool = Field(True, description="Флаг для проверки SSL-сертификатов.")
timeout: int = Field(30, description="Таймаут в секундах для HTTP-запросов.")
logger: Optional[SupersetLogger] = Field(None, description="Экземпляр логгера для логирования внутри клиента.")
logger: Optional[SupersetLogger] = Field(None, description="Экземпляр логгера для логирования.")
# [ENTITY: Function('validate_auth')]
# CONTRACT:
# PURPOSE: Валидация словаря `auth`.
# PRECONDITIONS: `v` должен быть словарем.
# POSTCONDITIONS: Возвращает `v` если все обязательные поля присутствуют.
# <ANCHOR id="SupersetConfig.validate_auth" type="Function">
# @PURPOSE: Проверяет, что словарь `auth` содержит все необходимые для аутентификации поля.
# @PRE: `v` должен быть словарем.
# @POST: Возвращает `v`, если все обязательные поля (`provider`, `username`, `password`, `refresh`) присутствуют.
# @THROW: ValueError - Если отсутствуют обязательные поля.
@validator('auth')
def validate_auth(cls, v: Dict[str, str], values: dict) -> Dict[str, str]:
logger = values.get('logger') or SupersetLogger(name="SupersetConfig")
logger.debug("[DEBUG][SupersetConfig.validate_auth][ENTER] Validating auth.")
def validate_auth(cls, v: Dict[str, str]) -> Dict[str, str]:
required = {'provider', 'username', 'password', 'refresh'}
if not required.issubset(v.keys()):
logger.error("[ERROR][SupersetConfig.validate_auth][FAILURE] Missing required auth fields.")
raise ValueError(f"Словарь 'auth' должен содержать поля: {required}. Отсутствующие: {required - v.keys()}")
logger.debug("[DEBUG][SupersetConfig.validate_auth][SUCCESS] Auth validated.")
return v
# END_FUNCTION_validate_auth
# </ANCHOR>
# [ENTITY: Function('check_base_url_format')]
# CONTRACT:
# PURPOSE: Валидация формата `base_url`.
# PRECONDITIONS: `v` должна быть строкой.
# POSTCONDITIONS: Возвращает `v` если это валидный URL.
# <ANCHOR id="SupersetConfig.check_base_url_format" type="Function">
# @PURPOSE: Проверяет, что `base_url` соответствует формату URL и содержит `/api/v1`.
# @PRE: `v` должна быть строкой.
# @POST: Возвращает очищенный `v`, если формат корректен.
# @THROW: ValueError - Если формат URL невалиден.
@validator('base_url')
def check_base_url_format(cls, v: str, values: dict) -> str:
"""
Простейшая проверка:
- начинается с http/https,
- содержит «/api/v1»,
- не содержит пробельных символов в начале/конце.
"""
v = v.strip() # устраняем скрытые пробелы/переносы
def check_base_url_format(cls, v: str) -> str:
v = v.strip()
if not re.fullmatch(r'https?://.+/api/v1/?(?:.*)?', v):
raise ValueError(f"Invalid URL format: {v}")
raise ValueError(f"Invalid URL format: {v}. Must include '/api/v1'.")
return v
# END_FUNCTION_check_base_url_format
# </ANCHOR>
class Config:
"""Pydantic config"""
arbitrary_types_allowed = True
# </ANCHOR id="SupersetConfig">
# <ANCHOR id="DatabaseConfig" type="DataClass">
# @PURPOSE: Модель для параметров трансформации баз данных при миграции дашбордов.
# @INHERITS_FROM: pydantic.BaseModel
class DatabaseConfig(BaseModel):
"""
[CONFIG] Параметры трансформации баз данных при миграции дашбордов.
"""
database_config: Dict[str, Dict[str, Any]] = Field(..., description="Словарь, содержащий 'old' и 'new' конфигурации базы данных.")
logger: Optional[SupersetLogger] = Field(None, description="Экземпляр логгера для логирования.")
# [ENTITY: Function('validate_config')]
# CONTRACT:
# PURPOSE: Валидация словаря `database_config`.
# PRECONDITIONS: `v` должен быть словарем.
# POSTCONDITIONS: Возвращает `v` если содержит ключи 'old' и 'new'.
# <ANCHOR id="DatabaseConfig.validate_config" type="Function">
# @PURPOSE: Проверяет, что словарь `database_config` содержит ключи 'old' и 'new'.
# @PRE: `v` должен быть словарем.
# @POST: Возвращает `v`, если ключи 'old' и 'new' присутствуют.
# @THROW: ValueError - Если отсутствуют обязательные ключи.
@validator('database_config')
def validate_config(cls, v: Dict[str, Dict[str, Any]], values: dict) -> Dict[str, Dict[str, Any]]:
logger = values.get('logger') or SupersetLogger(name="DatabaseConfig")
logger.debug("[DEBUG][DatabaseConfig.validate_config][ENTER] Validating database_config.")
def validate_config(cls, v: Dict[str, Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
if not {'old', 'new'}.issubset(v.keys()):
logger.error("[ERROR][DatabaseConfig.validate_config][FAILURE] Missing 'old' or 'new' keys in database_config.")
raise ValueError("'database_config' должен содержать ключи 'old' и 'new'.")
logger.debug("[DEBUG][DatabaseConfig.validate_config][SUCCESS] database_config validated.")
return v
# END_FUNCTION_validate_config
# </ANCHOR>
class Config:
"""Pydantic config"""
arbitrary_types_allowed = True
# </ANCHOR id="DatabaseConfig">
# --- Конец кода модуля ---
# </GRACE_MODULE id="superset_tool.models">