py.lib.aw_config

Yohn Y. 2026-06-23 Parent:75523df5b946 Child:260bceaa2d62

15:ed99d4db56a7 Go to Latest

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

.. 0.202606.1 . Рефакторинг документирования функций в file.py . Создание служебных методов для упрощения последующего развития модуля + Возможность получить раздел по заданному пути в иерархии toml-файла + Работа с списками хэш-таблиц toml (возможность в конфигурации использовать массивы однотипных секций.

History
     1.1 --- a/src/aw_config/file.py	Wed Oct 30 15:07:14 2024 +0300
     1.2 +++ b/src/aw_config/file.py	Tue Jun 23 11:09:15 2026 +0300
     1.3 @@ -54,6 +54,7 @@
     1.4                    mandatory: bool = True):
     1.5          """\
     1.6          Получить из текущего раздела конфигурации нужный элемент
     1.7 +
     1.8          :param name: имя параметра
     1.9          :param val_type: тип параметра
    1.10          :param default: значение параметра по умолчанию
    1.11 @@ -79,29 +80,153 @@
    1.12                  raise ConfigFileError(self._format_err_msg(f'Не удалось привести значение "{_buf}" к типу '
    1.13                                                             f'{repr(val_type)}: {e}'))
    1.14  
    1.15 +    def _get_section_name(self, *names: str) -> str:
    1.16 +        """\
    1.17 +        Поучить имя текущего раздели или подраздела по заданному имени
    1.18 +
    1.19 +        :type names: str
    1.20 +        :param names: Последовательные имена подразделов для получения доступа к глубокой иерархии
    1.21 +        :returns: Имя подраздела
    1.22 +        """
    1.23 +        res = self.section if self.section is not None else ''
    1.24 +        if not names:
    1.25 +            return res
    1.26 +
    1.27 +        else:
    1.28 +            if res:
    1.29 +                res += '.'
    1.30 +
    1.31 +            return res + '.'.join(names)
    1.32 +
    1.33 +    def _get_part_by_path(self, *names: str):
    1.34 +        """\
    1.35 +        Получить конфигурационный элемент по заданному пути
    1.36 +        """
    1.37 +        if not names:
    1.38 +            raise ValueError(f'Не заданно имя запрашиваемого раздела')
    1.39 +
    1.40 +        upper_path = names[:-1]
    1.41 +        last_path_el = names[-1]
    1.42 +        cur_level = self.d
    1.43 +        cur_section = self._get_section_name()
    1.44 +
    1.45 +        for el in upper_path:
    1.46 +            cur_section = el if not cur_section else f'{cur_section}.{el}'
    1.47 +
    1.48 +            if el in cur_level:
    1.49 +                cur_level = cur_level[el]
    1.50 +
    1.51 +            else:
    1.52 +                raise ConfigSectionNotFound(f'Раздел "{cur_section}" не найден')
    1.53 +
    1.54 +        cur_section = last_path_el if not cur_section else f'{cur_section}.{last_path_el}'
    1.55 +        if last_path_el in cur_level:
    1.56 +            return cur_level[last_path_el]
    1.57 +
    1.58 +        else:
    1.59 +            raise ConfigSectionNotFound(f'Раздел "{cur_section}" не найден')
    1.60 +
    1.61 +
    1.62      def get_section(self, name: str, mandatory: bool = True):
    1.63          """\
    1.64          Получить раздел конфигурационного файла из текущего или корневого раздела
    1.65 +
    1.66          :param name: имя раздела
    1.67          :param mandatory: является ли раздел обязательным или он может отсутствовать в конфигурации. Во втором
    1.68                            случае, будет создан пустой словарь и использован в качестве данных раздела.
    1.69 -        :returns Экземпляр того-же класса, только для новой секции
    1.70 +        :returns: Экземпляр того-же класса, только для новой секции
    1.71          """
    1.72 -        if name not in self.d:
    1.73 +        section_name = self._get_section_name(name)
    1.74 +        try:
    1.75 +            section_val = self._get_part_by_path(name)
    1.76 +
    1.77 +            if not isinstance(section_val, dict):
    1.78 +                raise ConfigFileError(f'Параметр конфигурации "{section_name}" не является разделом')
    1.79 +
    1.80 +            else:
    1.81 +                return ConfigFileContent(file_data=section_val, section_name=f'{section_name}')
    1.82 +
    1.83 +        except ConfigSectionNotFound as e:
    1.84              if mandatory:
    1.85 -                raise ConfigSectionNotFound(self._format_err_msg(f'Раздел "{name}" не найден'))
    1.86 +                raise e
    1.87 +
    1.88 +            else:
    1.89 +                return ConfigFileContent(file_data={}, section_name=f'{section_name}')
    1.90 +
    1.91 +    def get_section_by_path(self, *names: str, mandatory: bool = True):
    1.92 +        """\
    1.93 +        Поучить секцию конфигурации по явно заданному пути
    1.94 +
    1.95 +        :type names: str
    1.96 +        :param names: Имя секции на текущем уровне. Можно задавать несколько
    1.97 +             для прохода по всей иерархии необходимой иерархии одним вызовом.
    1.98 +
    1.99 +        :type mandatory: bool
   1.100 +        :param mandatory: Является ли искомая секция обязательной?
   1.101 +
   1.102 +        :returns: Экземпляр того-же класса, только для новой секции
   1.103 +        """
   1.104 +        section_name = self._get_section_name(*names)
   1.105 +        try:
   1.106 +            section_val = self._get_part_by_path(*names)
   1.107 +
   1.108 +            if not isinstance(section_val, dict):
   1.109 +                raise ConfigFileError(f'Параметр конфигурации "{section_name}" не является разделом')
   1.110 +
   1.111 +            else:
   1.112 +                return ConfigFileContent(file_data=section_val, section_name=f'{section_name}')
   1.113 +
   1.114 +        except ConfigSectionNotFound as e:
   1.115 +            if mandatory:
   1.116 +                raise e
   1.117  
   1.118              else:
   1.119 -                return ConfigFileContent(file_data={}, section_name=f'{self.section}.{name}')
   1.120 +                return ConfigFileContent(file_data={}, section_name=f'{section_name}')
   1.121 +
   1.122 +    def get_list_section(self, name: str, mandatory: bool = True):
   1.123 +        """\
   1.124 +        Для случая, когда раздел конфигурации задан массивом toml ([[${! SOME_SECTION !}]])
   1.125 +
   1.126 +        :type name: str
   1.127 +        :param name: Имя раздела
   1.128 +
   1.129 +        :type mandatory: bool
   1.130 +        :param mandatory: Данный раздел обязателен и не может отсутствовать
   1.131  
   1.132 -        else:
   1.133 -            _val = self.d[name]
   1.134 +        :returns: Спискол из экземпляров данного класса, нацеленные на элементы массива хэш-таблиц файла toml
   1.135 +        """
   1.136 +        section_name = self._get_section_name(name)
   1.137 +        try:
   1.138 +            section_val = self._get_part_by_path(name)
   1.139  
   1.140 -            if not isinstance(_val, dict):
   1.141 -                raise ConfigFileError(self._format_err_msg(f'Параметр конфигурации "{name}" не является разделом'))
   1.142 +            if isinstance(section_val, (list, tuple)):
   1.143 +                res = []
   1.144 +                for el in section_val:
   1.145 +                    if isinstance(el, dict):
   1.146 +                        res.append(ConfigFileContent(file_data=el, section_name=f'{section_name}'))
   1.147 +
   1.148 +                    else:
   1.149 +                        raise ConfigFileError(f'Параметр конфигурации "{section_name}"'
   1.150 +                                              f' со значением "{el}"'
   1.151 +                                              f' не является разделом')
   1.152 +                return res
   1.153 +
   1.154 +            elif isinstance(section_val, dict):
   1.155 +                return [
   1.156 +                    ConfigFileContent(file_data=section_val, section_name=f'{section_name}')
   1.157 +                ]
   1.158  
   1.159              else:
   1.160 -                return ConfigFileContent(file_data=_val, section_name=f'{self.section}.{name}')
   1.161 +                raise ConfigFileError(f'Параметр конфигурации "{section_name}" не является разделом')
   1.162 +
   1.163 +        except ConfigSectionNotFound as e:
   1.164 +            if mandatory:
   1.165 +                raise e
   1.166 +
   1.167 +            else:
   1.168 +                return [
   1.169 +                    ConfigFileContent(file_data={}, section_name=f'{section_name}')
   1.170 +                ]
   1.171  
   1.172  
   1.173  class ConfigFile(object):