refactor 1st stage
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user