Python ConfigParser interpolation from foreign section

折月煮酒 提交于 2019-12-03 06:01:12
chown

In python 3.2 and up this is perfectly valid:

[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}

Edit:

I just saw that you are using python 2.4, so no, section interpolation cannot be done in python 2.4. It was introduced in python 3.2 - See section 13.2.5 - ConfigParser Interpolation of values.

class configparser.ExtendedInterpolation

An alternative handler for interpolation which implements a more advanced syntax, used for instance in zc.buildout. Extended interpolation is using ${section:option} to denote a value from a foreign section. Interpolation can span multiple levels. For convenience, if the section: part is omitted, interpolation defaults to the current section (and possibly the default values from the special section). For example, the configuration specified above with basic interpolation, would look like this with extended interpolation:

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

Values from other sections can be fetched as well:

   [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}

You do have access to the special-case [DEFAULT] section. Values defined here can be accessed via interpolation from other sections even for older versions of Python.

If you're stuck with python 2.7 and you need to do cross-section interpolation it is easy enough to do this by hand using regexps.

Here is the code:

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:

  • There is no recursion in interpolation
  • When parsing many sections, youll need to somehow guess current section.

I have run into this in the project I'm working on right now, and I implemented a quick extension to the ConfigParser.SafeConfigParser class in which I have overwritten the get() function. I thought some may find it useful.

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 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!