archive_exports rework

This commit is contained in:
2025-07-11 16:29:20 +03:00
parent 5ff7c2aca9
commit d23eef096a
6 changed files with 443 additions and 37 deletions

View File

@@ -23,7 +23,24 @@ SearchResult = Dict[str, List[Dict[str, str]]]
SearchPattern = str
def setup_clients(logger: SupersetLogger):
"""Инициализация клиентов для разных окружений"""
# [FUNCTION] setup_clients
# [CONTRACT]
"""
Инициализация клиентов SupersetClient для разных окружений (dev, sbx, prod).
@pre:
- `logger` является инициализированным экземпляром SupersetLogger.
- Учетные данные для каждого окружения доступны через `keyring`.
@post:
- Возвращает словарь с инициализированными экземплярами SupersetClient для 'dev', 'sbx', 'prod'.
- Каждый клиент аутентифицирован.
@side_effects:
- Выполняет запросы к Superset API для аутентификации.
- Использует `keyring` для получения паролей.
- Логирует процесс инициализации и ошибки.
@raise:
- Exception: При ошибке инициализации клиента или аутентификации.
"""
# [ANCHOR] CLIENTS_INITIALIZATION
clients = {}
try:
@@ -82,18 +99,22 @@ def search_datasets(
search_fields: List[str] = None,
logger: Optional[SupersetLogger] = None
) -> Dict:
# [FUNCTION] search_datasets
"""[CONTRACT] Поиск строк в метаданных датасетов
@pre:
- `client` должен быть инициализированным SupersetClient
- `search_pattern` должен быть валидным regex-шаблоном
@post:
- Возвращает словарь с результатами поиска в формате:
{"dataset_id": [{"field": "table_name", "match": "found_string"}, ...]}
{"dataset_id": [{"field": "table_name", "match": "found_string", "value": "full_field_value"}, ...]}.
@raise:
- `re.error`: при невалидном regex-шаблоне
- `SupersetAPIError`: при ошибках API
- `AuthenticationError`: при ошибках аутентификации
- `NetworkError`: при сетевых ошибках
@side_effects:
- Выполняет запросы к Superset API через client.get_datasets()
- Выполняет запросы к Superset API через client.get_datasets().
- Логирует процесс поиска и ошибки.
"""
logger = logger or SupersetLogger(name="dataset_search")
@@ -125,7 +146,8 @@ def search_datasets(
matches.append({
"field": field,
"match": pattern.search(value).group(),
"value": value[:200] + "..." if len(value) > 200 else value
# Сохраняем полное значение поля, не усекаем
"value": value
})
if matches:
@@ -140,25 +162,99 @@ def search_datasets(
# [SECTION] Вспомогательные функции
def print_search_results(results: Dict) -> str:
"""Форматирование результатов для вывода в лог"""
def print_search_results(results: Dict, context_lines: int = 3) -> str:
# [FUNCTION] print_search_results
# [CONTRACT]
"""
Форматирует результаты поиска для вывода, показывая фрагмент кода с контекстом.
@pre:
- `results` является словарем в формате {"dataset_id": [{"field": "...", "match": "...", "value": "..."}, ...]}.
- `context_lines` является неотрицательным целым числом.
@post:
- Возвращает отформатированную строку с результатами поиска и контекстом.
- Функция не изменяет входные данные.
@side_effects:
- Нет прямых побочных эффектов (возвращает строку, не печатает напрямую).
"""
if not results:
return "Ничего не найдено"
output = []
for dataset_id, matches in results.items():
output.append(f"\nDataset ID: {dataset_id}")
for match in matches:
output.append(f" Поле: {match['field']}")
output.append(f" Совпадение: {match['match']}")
output.append(f" Значение: {match['value']}")
for match_info in matches:
field = match_info['field']
match_text = match_info['match']
full_value = match_info['value']
output.append(f" Поле: {field}")
output.append(f" Совпадение: '{match_text}'")
# Находим позицию совпадения в полном тексте
match_start_index = full_value.find(match_text)
if match_start_index == -1:
# Этого не должно произойти, если search_datasets работает правильно, но для надежности
output.append(" Не удалось найти совпадение в полном тексте.")
continue
# Разбиваем текст на строки
lines = full_value.splitlines()
# Находим номер строки, где находится совпадение
current_index = 0
match_line_index = -1
for i, line in enumerate(lines):
if current_index <= match_start_index < current_index + len(line) + 1: # +1 for newline character
match_line_index = i
break
current_index += len(line) + 1 # +1 for newline character
if match_line_index == -1:
output.append(" Не удалось определить строку совпадения.")
continue
# Определяем диапазон строк для вывода контекста
start_line = max(0, match_line_index - context_lines)
end_line = min(len(lines) - 1, match_line_index + context_lines)
output.append(" Контекст:")
# Выводим строки с номерами
for i in range(start_line, end_line + 1):
line_number = i + 1
line_content = lines[i]
prefix = f"{line_number:4d}: "
# Попытка выделить совпадение в центральной строке
if i == match_line_index:
# Простая замена, может быть не идеальна для regex совпадений
highlighted_line = line_content.replace(match_text, f">>>{match_text}<<<")
output.append(f"{prefix}{highlighted_line}")
else:
output.append(f"{prefix}{line_content}")
output.append("-" * 20) # Разделитель между совпадениями
return "\n".join(output)
# [COHERENCE_CHECK_PASSED] Модуль полностью соответствует контрактам
def inspect_datasets(client: SupersetClient):
"""Функция для проверки реальной структуры датасетов"""
# [FUNCTION] inspect_datasets
# [CONTRACT]
"""
Функция для проверки реальной структуры датасетов.
Предназначена в основном для отладки и исследования структуры данных.
@pre:
- `client` является инициализированным экземпляром SupersetClient.
@post:
- Выводит информацию о количестве датасетов и структуре первого датасета в консоль.
- Функция не изменяет состояние клиента.
@side_effects:
- Вызовы к Superset API через `client.get_datasets()`.
- Вывод в консоль.
- Логирует процесс инспекции и ошибки.
@raise:
- `SupersetAPIError`: при ошибках API
- `AuthenticationError`: при ошибках аутентификации
- `NetworkError`: при сетевых ошибках
"""
total, datasets = client.get_datasets()
print(f"Всего датасетов: {total}")