Интерполяция Python ConfigParser из иностранного раздела
С Python ConfigParser можно ли использовать интерполяцию по внешним разделам? Мой ум, кажется, говорит мне, что я видел, что это возможно где-то, но я не могу найти его при поиске.
Этот пример не работает, но он дает представление о том, что я пытаюсь сделать.
[section1]
root = /usr
[section2]
root = /usr/local
[section3]
dir1 = $(section1:root)/bin
dir2 = $(section2:root)/bin
Обратите внимание, что я использую Python 2.4.
Ответы
Ответ 1
В 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}
Ответ 2
У вас есть доступ к специальному разделу [ПО УМОЛЧАНИЮ]. Значения, определенные здесь, могут быть доступны через интерполяцию из других разделов даже для более старых версий Python.
Ответ 3
Если вы застряли с 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
Caveeats:
- В интерполяции нет рекурсии
- При анализе многих разделов вам нужно как-то угадать текущий раздел.
Ответ 4
Я столкнулся с этим в проекте, над которым я сейчас работаю, и я реализовал быстрое расширение класса 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