py.lib.aw_config

Yohn Y. 2024-05-14 Parent:26be458b26bb Child:75523df5b946

8:7026698c5937 Go to Latest

py.lib.aw_config/src/aw_config/file.py

Added tag 0.202405.12 for changeset 26be458b26bb

History
1 # coding: utf-8
2 """\
3 Функции, помогающие в разборе конфигурационного файла
4 """
5 import toml
6 from os.path import exists
7 from typing import Union, Any
9 from .error import Error
10 from .type_helpers import BaseTypeHelper
11 from ._lib import _UNDEFINED
14 class ConfigFileError(Error):
15 """\
16 Базовое исключение при обработке конфигурационного файла
17 """
20 class ConfigSectionNotFound(ConfigFileError):
21 """\
22 Отсутствие нужного раздела в конфигурации
23 """
26 class ConfigFileContent(object):
27 """\
28 Работа с содержимым файла конфигурации
29 """
30 def __init__(self, file_data, section_name=None):
31 """\
32 :param file_data: Разобранное в словарь содержимое файла конфигурации
33 :param section_name: Имя секции в конфигурации
34 """
35 self.d = file_data
36 self.section = section_name
38 def _format_err_msg(self, msg: str) -> str:
39 if self.section is not None:
40 return f'Раздел конфигурации "{self.section}": {msg}'
42 else:
43 return msg
45 def __enter__(self):
46 return self
48 def __exit__(self, exc_type, exc_val, exc_tb):
49 pass
51 def get_value(self, name: str,
52 val_type: Union[type, BaseTypeHelper] = str,
53 default: Any = _UNDEFINED,
54 mandatory: bool = True):
55 """\
56 Получить из текущего раздела конфигурации нужный элемент
57 :param name: имя параметра
58 :param val_type: тип параметра
59 :param default: значение параметра по умолчанию
60 :param mandatory: является ли параметр обязательным. Если ``False``, то в случае отсутствия
61 параметра будет использовано значение None
62 """
63 if name not in self.d:
64 if mandatory and default is _UNDEFINED:
65 raise ConfigFileError(self._format_err_msg(f'Параметр "{name}" в файле отсутствует'))
67 else:
68 return default
70 else:
71 _buf = self.d[name]
72 try:
73 return val_type(_buf)
75 except (ValueError, TypeError) as e:
76 raise ConfigFileError(self._format_err_msg(f'Не удалось привести значение "{_buf}" к типу '
77 f'{repr(val_type)}: {e}'))
79 def get_section(self, name: str, mandatory: bool = True):
80 """\
81 Получить раздел конфигурационного файла из текущего или корневого раздела
82 :param name: имя раздела
83 :param mandatory: является ли раздел обязательным или он может отсутствовать в конфигурации. Во втором
84 случае, будет создан пустой словарь и использован в качестве данных раздела.
85 :returns Экземпляр того-же класса, только для новой секции
86 """
87 if name not in self.d:
88 if mandatory:
89 raise ConfigSectionNotFound(self._format_err_msg(f'Раздел "{name}" не найден'))
91 else:
92 return ConfigFileContent(file_data={}, section_name=f'{self.section}.{name}')
94 else:
95 _val = self.d[name]
97 if not isinstance(_val, dict):
98 raise ConfigFileError(self._format_err_msg(f'Параметр конфигурации "{name}" не является разделом'))
100 else:
101 return ConfigFileContent(file_data=_val, section_name=f'{self.section}.{name}')
104 class ConfigFile(object):
105 """\
106 Работа с самим файлом конфигурации
107 """
108 def __init__(self, file_name: str):
109 if not exists(file_name):
110 raise ConfigFileError(f'Файл конфигурации "{file_name}" не существует')
112 self.file_name = file_name
114 def get(self):
115 """\
116 Производим разбор файла конфигурации и создаём корневой раздел конфигурации
117 """
118 try:
119 return ConfigFileContent(toml.load(self.file_name))
121 except OSError as e:
122 raise ConfigFileError(f'Ошибка чтения файла "{self.file_name}": {e}')
124 except toml.TomlDecodeError as e:
125 raise ConfigFileError(f'Ошибка в разборе файла конфигурации: {e}')
127 except ValueError as e:
128 raise ConfigFileError(f'Ошибка разбора файла конфигурации: {ConfigFileError.fmt_error(e)}')
130 def __exit__(self, exc_type, exc_val, exc_tb):
131 pass
133 def __enter__(self):
134 return self.get()