Интерполяция Python ConfigParser из иностранного раздела

Можно ли с помощью Python ConfigParser использовать интерполяцию между внешними разделами? Мой разум, кажется, говорит мне, что я где-то видел, что это возможно, но я не могу найти это при поиске.

Этот пример не работает, но он дает представление о том, что я пытаюсь сделать.

[section1]
root = /usr

[section2]
root = /usr/local

[section3]
dir1 = $(section1:root)/bin
dir2 = $(section2:root)/bin

Обратите внимание, что я использую Python 2.4.


person user16738    schedule 30.09.2011    source источник


Ответы (4)


В python 3.2 и выше это совершенно верно:

[Common]
home_dir: /Users
library_dir: /Library
system_dir: /System
macports_dir: /opt/local

[Frameworks]
Python: 3.2
path: ${Common:system_dir}/Library/Frameworks/

[Arthur]
nickname: Two Sheds
last_name: Jackson
my_dir: ${Common:home_dir}/twosheds
my_pictures: ${my_dir}/Pictures
python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}

Редактировать:

Я только что увидел, что вы используете python 2.4, поэтому нет, интерполяция разделов не может быть выполнена в python 2.4. Он был представлен в python 3.2см. раздел 13.2.5 - ConfigParser Интерполяция значений.

класс configparser.ExtendedInterpolation

Альтернативный обработчик интерполяции, который реализует более продвинутый синтаксис, используемый, например, в zc.buildout. Расширенная интерполяция использует ${section:option} для обозначения значения из чужого раздела. Интерполяция может охватывать несколько уровней. Для удобства, если секция: часть опущена, интерполяция по умолчанию используется для текущей секции (и, возможно, значения по умолчанию из специальной секции). Например, указанная выше конфигурация с базовой интерполяцией будет выглядеть так с расширенной интерполяцией:

   [Paths]
   home_dir: /Users
   my_dir: ${home_dir}/lumberjack
   my_pictures: ${my_dir}/Pictures

Также можно получить значения из других разделов:

   [Common]
   home_dir: /Users
   library_dir: /Library
   system_dir: /System
   macports_dir: /opt/local

   [Frameworks]
   Python: 3.2
   path: ${Common:system_dir}/Library/Frameworks/

   [Arthur]
   nickname: Two Sheds
   last_name: Jackson
   my_dir: ${Common:home_dir}/twosheds
   my_pictures: ${my_dir}/Pictures
   python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
person chown    schedule 30.09.2011
comment
Похоже, ваш синтаксис немного отличается от ума. Вы используете ${section:name} вместо того, что использовал я, %(section:name)s. Я пробовал это и не работал. - person user16738; 30.09.2011
comment
Ах, извините, я не понял, что вы имели в виду интерполяцию строк между разделами. Я полагаю, что это также было с 3.2, позвольте мне перепроверить. - person chown; 30.09.2011
comment
Я только что нашел то, что у вас есть здесь, в документах Python 3.2 (configparser.ExtendedInterpolation), но в нем не указано, когда это было добавлено. Когда я смотрю документы Python 2.4 (то, что я использую), это не отображается. Я предполагаю, что он был добавлен где-то между 2.4 и 3.2. - person user16738; 30.09.2011
comment
Да, я проверил документы каждой версии от 2.4 до 3.2 для ConfigParser, и первой, у которой был класс ExtendedInterpolation, была 3.2. - person chown; 30.09.2011
comment
Вероятно, им следует добавить в документацию New in Python 3.2. Это удобно. - person user16738; 30.09.2011
comment
Согласованный! И обычно они это делают; кажется, этот пропущен :/ - person chown; 30.09.2011

У вас есть доступ к специальному разделу [DEFAULT]. К значениям, определенным здесь, можно получить доступ через интерполяцию из других разделов даже для более старых версий Python.

person Papadeltasierra    schedule 01.07.2015
comment
Не могли бы вы уточнить немного больше? и, возможно, пример, пожалуйста. Или хотя бы ссылку на источник. - person Hamed; 15.07.2015
comment
Хамед, посмотри сюда. docs.python.org/2/library/configparser.html. По сути (и вы можете скачать и прочитать код), если вы попытаетесь прочитать «значение» для «имени» из определенного [раздела], но в этом [разделе] нет «имя = значение», тогда конфигурация Парсер ищет в разделе [DEFAULT] «имя = значение» и возвращает его, если он присутствует. - person Papadeltasierra; 24.09.2015

Если вы застряли с Python 2.7 и вам нужно выполнить интерполяцию поперечного сечения, достаточно легко сделать это вручную с помощью регулярных выражений.

Вот код:

INTERPOLATION_RE = re.compile(r"\$\{(?:(?P<section>[^:]+):)?(?P<key>[^}]+)\}")

def load_something_from_cp(cp, section="section"):
    result = []
    def interpolate_func(match):
        d = match.groupdict()
        section = d.get('section', section)
        key = d.get('key')
        return cp.get(section, key)
    for k, v in cp.items(section):
        v = re.sub(INTERPOLATION_RE, interpolate_func, v)
        result.append(
            (v, k)
        )
    return result

Предостережения:

  • В интерполяции нет рекурсии
  • При анализе многих разделов вам нужно как-то угадать текущий раздел.
person jb.    schedule 23.11.2014

Я столкнулся с этим в проекте, над которым сейчас работаю, и я реализовал быстрое расширение класса ConfigParser.SafeConfigParser, в котором перезаписал функцию get(). Я подумал, что кому-то это может пригодиться.

import re
import ConfigParser

class ExtParser(ConfigParser.SafeConfigParser):
     #implementing extended interpolation
     def __init__(self, *args, **kwargs):
         self.cur_depth = 0 
         ConfigParser.SafeConfigParser.__init__(self, *args, **kwargs)


     def get(self, section, option, raw=False, vars=None):
         r_opt = ConfigParser.SafeConfigParser.get(self, section, option, raw=True, vars=vars)
         if raw:
             return r_opt

         ret = r_opt
         re_oldintp = r'%\((\w*)\)s'
         re_newintp = r'\$\{(\w*):(\w*)\}'

         m_new = re.findall(re_newintp, r_opt)
         if m_new:
             for f_section, f_option in m_new:
                 self.cur_depth = self.cur_depth + 1 
                 if self.cur_depth < ConfigParser.MAX_INTERPOLATION_DEPTH:
                     sub = self.get(f_section, f_option, vars=vars)
                     ret = ret.replace('${{{0}:{1}}}'.format(f_section, f_option), sub)
                 else:
                     raise ConfigParser.InterpolationDepthError, (option, section, r_opt)



         m_old = re.findall(re_oldintp, r_opt)
         if m_old:
             for l_option in m_old:
                 self.cur_depth = self.cur_depth + 1 
                 if self.cur_depth < ConfigParser.MAX_INTERPOLATION_DEPTH:
                     sub = self.get(section, l_option, vars=vars)
                     ret = ret.replace('%({0})s'.format(l_option), sub)
                 else:
                     raise ConfigParser.InterpolationDepthError, (option, section, r_opt)

         self.cur_depth = self.cur_depth - 1 
         return ret 
person 0xcurb    schedule 08.03.2016