refactor 1st stage

This commit is contained in:
Volobuev Andrey
2025-06-27 17:05:33 +03:00
parent c0a6ca7769
commit 2b35038f73
7 changed files with 1306 additions and 632 deletions

View File

@@ -1,42 +1,77 @@
# [MODULE] Сущности данных конфигурации
# @desc: Определяет структуры данных для работы с Superset API
# @desc: Определяет структуры данных, используемые для конфигурации и трансформации в инструменте Superset.
# @contracts:
# - Проверка валидности URL
# - Валидация параметров аутентификации
# - Все модели наследуются от `pydantic.BaseModel` для автоматической валидации.
# - Валидация URL-адресов и параметров аутентификации.
# - Валидация структуры конфигурации БД для миграций.
# @coherence:
# - Все модели согласованы с API Superset v1
# - Совместимы с клиентскими методами
# - Все модели согласованы со схемой API Superset v1.
# - Совместимы с клиентскими методами `SupersetClient` и утилитами.
# [IMPORTS] Models
from typing import Optional, Dict, Any
from pydantic import BaseModel, validator,Field
# [IMPORTS] Pydantic и Typing
from typing import Optional, Dict, Any, Union
from pydantic import BaseModel, validator, Field, HttpUrl
# [COHERENCE_CHECK_PASSED] Все необходимые импорты для Pydantic моделей.
# [IMPORTS] Локальные модули
from .utils.logger import SupersetLogger
class SupersetConfig(BaseModel):
"""[CONFIG] Конфигурация подключения к Superset
@semantic: Основные параметры подключения к API
"""[CONFIG] Конфигурация подключения к Superset API.
@semantic: Инкапсулирует основные параметры, необходимые для инициализации `SupersetClient`.
@invariant:
- base_url должен содержать версию API (/v1/)
- auth должен содержать все обязательные поля
- `base_url` должен быть валидным HTTP(S) URL и содержать `/api/v1`.
- `auth` должен содержать обязательные поля для аутентификации по логину/паролю.
- `timeout` должен быть положительным числом.
"""
base_url: str = Field(..., regex=r'.*/api/v1.*')
auth: dict
verify_ssl: bool = True
timeout: int = 30
logger: Optional[SupersetLogger] = None
base_url: str = Field(..., description="Базовый URL Superset API, включая версию /api/v1.", regex=r'.*/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="Экземпляр логгера для логирования внутри клиента.")
# [VALIDATOR] Проверка параметров аутентификации
@validator('auth')
def validate_auth(cls, v):
def validate_auth(cls, v: Dict[str, str]) -> Dict[str, str]:
"""[CONTRACT_VALIDATOR] Валидация словаря `auth`.
@pre:
- `v` должен быть словарем.
@post:
- Возвращает `v` если все обязательные поля присутствуют.
@raise:
- `ValueError`: Если отсутствуют обязательные поля ('provider', 'username', 'password', 'refresh').
"""
required = {'provider', 'username', 'password', 'refresh'}
if not required.issubset(v.keys()):
raise ValueError(
f"[CONTRACT_VIOLATION] Auth must contain {required}"
f"[CONTRACT_VIOLATION] Словарь 'auth' должен содержать поля: {required}. "
f"Отсутствующие: {required - v.keys()}"
)
# [COHERENCE_CHECK_PASSED] Auth-конфигурация валидна.
return v
# [VALIDATOR] Проверка base_url
@validator('base_url')
def check_base_url_format(cls, v: str) -> str:
"""[CONTRACT_VALIDATOR] Валидация формата `base_url`.
@pre:
- `v` должна быть строкой.
@post:
- Возвращает `v` если это валидный URL.
@raise:
- `ValueError`: Если URL невалиден.
"""
try:
# Для Pydantic v2:
from pydantic import HttpUrl
HttpUrl(v, scheme="https") # Явное указание схемы
except ValueError:
# Для совместимости с Pydantic v1:
HttpUrl(v)
return v
class Config:
arbitrary_types_allowed = True
arbitrary_types_allowed = True # Разрешаем Pydantic обрабатывать произвольные типы (например, SupersetLogger)
json_schema_extra = {
"example": {
"base_url": "https://host/api/v1/",
@@ -45,28 +80,42 @@ class SupersetConfig(BaseModel):
"username": "user",
"password": "pass",
"refresh": True
}
},
"verify_ssl": True,
"timeout": 60
}
}
# [SEMANTIC-TYPE] Конфигурация БД для миграций
class DatabaseConfig(BaseModel):
"""[CONFIG] Параметры трансформации БД при миграции
@semantic: Содержит old/new состояние для преобразования
"""[CONFIG] Параметры трансформации баз данных при миграции дашбордов.
@semantic: Содержит `old` и `new` состояния конфигурации базы данных,
используемые для поиска и замены в YAML-файлах экспортированных дашбордов.
@invariant:
- Должны быть указаны оба состояния (old/new)
- UUID должен соответствовать формату
- `database_config` должен быть словарем с ключами 'old' и 'new'.
- Каждое из 'old' и 'new' должно быть словарем, содержащим метаданные БД Superset.
"""
database_config: Dict[str, Dict[str, Any]]
logger: Optional[SupersetLogger] = None
database_config: Dict[str, Dict[str, Any]] = Field(..., description="Словарь, содержащий 'old' и 'new' конфигурации базы данных.")
logger: Optional[SupersetLogger] = Field(None, description="Экземпляр логгера для логирования.")
@validator('database_config')
def validate_config(cls, v):
def validate_config(cls, v: Dict[str, Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
"""[CONTRACT_VALIDATOR] Валидация словаря `database_config`.
@pre:
- `v` должен быть словарем.
@post:
- Возвращает `v` если содержит ключи 'old' и 'new'.
@raise:
- `ValueError`: Если отсутствуют ключи 'old' или 'new'.
"""
if not {'old', 'new'}.issubset(v.keys()):
raise ValueError(
"[COHERENCE_ERROR] Config must contain both old/new states"
"[CONTRACT_VIOLATION] 'database_config' должен содержать ключи 'old' и 'new'."
)
# Дополнительно можно добавить проверку структуры `old` и `new` на наличие `uuid`, `database_name` и т.д.
# Для простоты пока ограничимся наличием ключей 'old' и 'new'.
# [COHERENCE_CHECK_PASSED] Конфигурация базы данных для миграции валидна.
return v
class Config: