64 lines
3.2 KiB
Python
64 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
||
import logging
|
||
import yaml
|
||
from typing import Optional, Dict # Для Python < 3.9 используйте Dict, для Python 3.9+ можно просто dict
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
class ConfigError(Exception):
|
||
"""Базовый класс для ошибок конфигурации."""
|
||
pass
|
||
|
||
class ConfigNotFoundError(ConfigError):
|
||
"""Файл конфигурации не найден."""
|
||
pass
|
||
|
||
class InvalidConfigFormatError(ConfigError):
|
||
"""Ошибка формата YAML в конфигурации."""
|
||
pass
|
||
|
||
|
||
def load_config(path: str) -> Optional[Dict]:
|
||
"""
|
||
Загрузка конфигурации из YAML файла.
|
||
Обрабатывает ошибки чтения файла и парсинга YAML.
|
||
|
||
:param path: Путь к файлу конфигурации.
|
||
:return: Словарь с конфигурацией или None в случае ошибки.
|
||
"""
|
||
logger.debug(f"Попытка загрузки конфигурации из файла: `{path}`")
|
||
try:
|
||
with open(path, "r", encoding="utf-8") as f:
|
||
config_data = yaml.safe_load(f)
|
||
|
||
# Проверим, что YAML действительно распарсился в словарь
|
||
if not isinstance(config_data, dict):
|
||
msg = f"Содержимое файла конфигурации `{path}` не является словарем. Тип: {type(config_data).__name__}."
|
||
logger.error(msg)
|
||
raise InvalidConfigFormatError(msg)
|
||
|
||
logger.info(msg=f"Конфигурация успешно загружена из `{path}`")
|
||
return config_data
|
||
|
||
except FileNotFoundError:
|
||
msg=f"Файл конфигурации не найден: `{path}`"
|
||
logger.error(msg)
|
||
raise ConfigNotFoundError(msg) from None # from None подавляет цепочку исключений
|
||
except yaml.YAMLError as e:
|
||
# YAMLError - базовый класс для ошибок PyYAML (ошибки сканера, парсера и т.п.)
|
||
msg = f"Ошибка парсинга YAML в файле `{path}`: {e}"
|
||
logger.error(msg)
|
||
raise InvalidConfigFormatError(msg) from e
|
||
except IOError as e:
|
||
# IOError или OSError для других проблем с доступом к файлу (например, права доступа)
|
||
msg = f"Ошибка ввода-вывода при чтении файла `{path}`: {e}"
|
||
logger.error(msg)
|
||
raise ConfigError(msg) from e # Общее исключение для других ошибок ввода-вывода
|
||
except Exception as e:
|
||
# Отлавливаем любые другие непредвиденные исключения
|
||
logger.critical(
|
||
msg=f"Непредвиденная ошибка при загрузке конфигурации из `{path}`: {e}",
|
||
exc_info=True # Добавляет трассировку стека в лог для лучшей диагностики
|
||
)
|
||
raise ConfigError(f"Непредвиденная ошибка: {e}") from e
|