py.lib.aw_config
15:ed99d4db56a7 Browse Files
.. 0.202606.1 . Рефакторинг документирования функций в file.py . Создание служебных методов для упрощения последующего развития модуля + Возможность получить раздел по заданному пути в иерархии toml-файла + Работа с списками хэш-таблиц toml (возможность в конфигурации использовать массивы однотипных секций.
setup.py src/aw_config/file.py tools/make_pkg.sh
1.1 --- a/setup.py Wed Oct 30 15:07:14 2024 +0300 1.2 +++ b/setup.py Tue Jun 23 11:09:15 2026 +0300 1.3 @@ -3,7 +3,7 @@ 1.4 1.5 setup( 1.6 name='aw_config', 1.7 - version='0.202410.2', 1.8 + version='0.202606.1', 1.9 packages=['aw_config'], 1.10 package_dir={'aw_config': 'src/aw_config'}, 1.11 description='Модуль поддержки процесса конфигурирования приложения'
2.1 --- a/src/aw_config/file.py Wed Oct 30 15:07:14 2024 +0300 2.2 +++ b/src/aw_config/file.py Tue Jun 23 11:09:15 2026 +0300 2.3 @@ -54,6 +54,7 @@ 2.4 mandatory: bool = True): 2.5 """\ 2.6 Получить из текущего раздела конфигурации нужный элемент 2.7 + 2.8 :param name: имя параметра 2.9 :param val_type: тип параметра 2.10 :param default: значение параметра по умолчанию 2.11 @@ -79,29 +80,153 @@ 2.12 raise ConfigFileError(self._format_err_msg(f'Не удалось привести значение "{_buf}" к типу ' 2.13 f'{repr(val_type)}: {e}')) 2.14 2.15 + def _get_section_name(self, *names: str) -> str: 2.16 + """\ 2.17 + Поучить имя текущего раздели или подраздела по заданному имени 2.18 + 2.19 + :type names: str 2.20 + :param names: Последовательные имена подразделов для получения доступа к глубокой иерархии 2.21 + :returns: Имя подраздела 2.22 + """ 2.23 + res = self.section if self.section is not None else '' 2.24 + if not names: 2.25 + return res 2.26 + 2.27 + else: 2.28 + if res: 2.29 + res += '.' 2.30 + 2.31 + return res + '.'.join(names) 2.32 + 2.33 + def _get_part_by_path(self, *names: str): 2.34 + """\ 2.35 + Получить конфигурационный элемент по заданному пути 2.36 + """ 2.37 + if not names: 2.38 + raise ValueError(f'Не заданно имя запрашиваемого раздела') 2.39 + 2.40 + upper_path = names[:-1] 2.41 + last_path_el = names[-1] 2.42 + cur_level = self.d 2.43 + cur_section = self._get_section_name() 2.44 + 2.45 + for el in upper_path: 2.46 + cur_section = el if not cur_section else f'{cur_section}.{el}' 2.47 + 2.48 + if el in cur_level: 2.49 + cur_level = cur_level[el] 2.50 + 2.51 + else: 2.52 + raise ConfigSectionNotFound(f'Раздел "{cur_section}" не найден') 2.53 + 2.54 + cur_section = last_path_el if not cur_section else f'{cur_section}.{last_path_el}' 2.55 + if last_path_el in cur_level: 2.56 + return cur_level[last_path_el] 2.57 + 2.58 + else: 2.59 + raise ConfigSectionNotFound(f'Раздел "{cur_section}" не найден') 2.60 + 2.61 + 2.62 def get_section(self, name: str, mandatory: bool = True): 2.63 """\ 2.64 Получить раздел конфигурационного файла из текущего или корневого раздела 2.65 + 2.66 :param name: имя раздела 2.67 :param mandatory: является ли раздел обязательным или он может отсутствовать в конфигурации. Во втором 2.68 случае, будет создан пустой словарь и использован в качестве данных раздела. 2.69 - :returns Экземпляр того-же класса, только для новой секции 2.70 + :returns: Экземпляр того-же класса, только для новой секции 2.71 """ 2.72 - if name not in self.d: 2.73 + section_name = self._get_section_name(name) 2.74 + try: 2.75 + section_val = self._get_part_by_path(name) 2.76 + 2.77 + if not isinstance(section_val, dict): 2.78 + raise ConfigFileError(f'Параметр конфигурации "{section_name}" не является разделом') 2.79 + 2.80 + else: 2.81 + return ConfigFileContent(file_data=section_val, section_name=f'{section_name}') 2.82 + 2.83 + except ConfigSectionNotFound as e: 2.84 if mandatory: 2.85 - raise ConfigSectionNotFound(self._format_err_msg(f'Раздел "{name}" не найден')) 2.86 + raise e 2.87 + 2.88 + else: 2.89 + return ConfigFileContent(file_data={}, section_name=f'{section_name}') 2.90 + 2.91 + def get_section_by_path(self, *names: str, mandatory: bool = True): 2.92 + """\ 2.93 + Поучить секцию конфигурации по явно заданному пути 2.94 + 2.95 + :type names: str 2.96 + :param names: Имя секции на текущем уровне. Можно задавать несколько 2.97 + для прохода по всей иерархии необходимой иерархии одним вызовом. 2.98 + 2.99 + :type mandatory: bool 2.100 + :param mandatory: Является ли искомая секция обязательной? 2.101 + 2.102 + :returns: Экземпляр того-же класса, только для новой секции 2.103 + """ 2.104 + section_name = self._get_section_name(*names) 2.105 + try: 2.106 + section_val = self._get_part_by_path(*names) 2.107 + 2.108 + if not isinstance(section_val, dict): 2.109 + raise ConfigFileError(f'Параметр конфигурации "{section_name}" не является разделом') 2.110 + 2.111 + else: 2.112 + return ConfigFileContent(file_data=section_val, section_name=f'{section_name}') 2.113 + 2.114 + except ConfigSectionNotFound as e: 2.115 + if mandatory: 2.116 + raise e 2.117 2.118 else: 2.119 - return ConfigFileContent(file_data={}, section_name=f'{self.section}.{name}') 2.120 + return ConfigFileContent(file_data={}, section_name=f'{section_name}') 2.121 + 2.122 + def get_list_section(self, name: str, mandatory: bool = True): 2.123 + """\ 2.124 + Для случая, когда раздел конфигурации задан массивом toml ([[${! SOME_SECTION !}]]) 2.125 + 2.126 + :type name: str 2.127 + :param name: Имя раздела 2.128 + 2.129 + :type mandatory: bool 2.130 + :param mandatory: Данный раздел обязателен и не может отсутствовать 2.131 2.132 - else: 2.133 - _val = self.d[name] 2.134 + :returns: Спискол из экземпляров данного класса, нацеленные на элементы массива хэш-таблиц файла toml 2.135 + """ 2.136 + section_name = self._get_section_name(name) 2.137 + try: 2.138 + section_val = self._get_part_by_path(name) 2.139 2.140 - if not isinstance(_val, dict): 2.141 - raise ConfigFileError(self._format_err_msg(f'Параметр конфигурации "{name}" не является разделом')) 2.142 + if isinstance(section_val, (list, tuple)): 2.143 + res = [] 2.144 + for el in section_val: 2.145 + if isinstance(el, dict): 2.146 + res.append(ConfigFileContent(file_data=el, section_name=f'{section_name}')) 2.147 + 2.148 + else: 2.149 + raise ConfigFileError(f'Параметр конфигурации "{section_name}"' 2.150 + f' со значением "{el}"' 2.151 + f' не является разделом') 2.152 + return res 2.153 + 2.154 + elif isinstance(section_val, dict): 2.155 + return [ 2.156 + ConfigFileContent(file_data=section_val, section_name=f'{section_name}') 2.157 + ] 2.158 2.159 else: 2.160 - return ConfigFileContent(file_data=_val, section_name=f'{self.section}.{name}') 2.161 + raise ConfigFileError(f'Параметр конфигурации "{section_name}" не является разделом') 2.162 + 2.163 + except ConfigSectionNotFound as e: 2.164 + if mandatory: 2.165 + raise e 2.166 + 2.167 + else: 2.168 + return [ 2.169 + ConfigFileContent(file_data={}, section_name=f'{section_name}') 2.170 + ] 2.171 2.172 2.173 class ConfigFile(object):
3.1 --- a/tools/make_pkg.sh Wed Oct 30 15:07:14 2024 +0300 3.2 +++ b/tools/make_pkg.sh Tue Jun 23 11:09:15 2026 +0300 3.3 @@ -1,5 +1,5 @@ 3.4 #!/bin/sh 3.5 -# devel.a0fs.ru -- devel.python.tools:make_pkg.sh -- v0.r202405.2 3.6 +# devel.a0fs.ru -- devel.python.tools:make_pkg.sh -- v0.r202606.1 3.7 this_dir="$(dirname "$(readlink -f "$0")")" 3.8 this_pkg="$(dirname "$this_dir")" 3.9 3.10 @@ -8,4 +8,4 @@ 3.11 . "${this_pkg}/.e/bin/activate" 3.12 fi 3.13 3.14 -python3 setup.py bdist_wheel --build-number "$(date '+%d%H%M%S')" 3.15 +python3 setup.py bdist_wheel