cfg: support interpolation of config option from other groups

This patch adds support for config variable interpolation with values
coming form… other groups than the current/default one!

Change-Id: Iddd21aa2da71fe332868049d4b94b75b562b61cd
This commit is contained in:
Julien Danjou 2015-05-05 16:51:37 +02:00
parent 8d3c275352
commit a5afcc22aa
3 changed files with 29 additions and 18 deletions

View File

@ -240,12 +240,10 @@ Option values may reference other values using PEP 292 string substitution::
Interpolation can be avoided by using `$$`.
.. warning::
.. note::
Interpolation using the values of options in groups is not yet
supported. The interpolated option must be in the DEFAULT group
(i.e., ``"$state_path"`` works but ``"$database.state_path"`` does
not).
You can use `.` to delimit option from other groups, e.g.
${mygroup.myoption}.
Special Handling Instructions
-----------------------------
@ -2320,13 +2318,16 @@ class ConfigOpts(collections.Mapping):
# a bit more natural for users
if '\$' in value:
value = value.replace('\$', '$$')
tmpl = string.Template(value)
tmpl = self.Template(value)
ret = tmpl.safe_substitute(
self.StrSubWrapper(self, group=group, namespace=namespace))
return ret
else:
return value
class Template(string.Template):
idpattern = r'[_a-z][\._a-z0-9]*'
def _convert_value(self, value, opt):
"""Perform value type conversion.
@ -2591,10 +2592,16 @@ class ConfigOpts(collections.Mapping):
:param key: an opt name
:returns: an opt value
:raises: TemplateSubstitutionError if attribute is a group
"""
try:
value = self.conf._get(key, group=self.group,
group_name, option = key.split(".", 1)
except ValueError:
group = self.group
option = key
else:
group = OptGroup(name=group_name)
try:
value = self.conf._get(option, group=group,
namespace=self.namespace)
except NoSuchOptError:
value = self.conf._get(key, namespace=self.namespace)

View File

@ -2824,11 +2824,18 @@ class SadPathTestCase(BaseTestCase):
self.conf([])
self.assertFalse(hasattr(self.conf, 'bar'))
self.assertRaises(
AttributeError, getattr, self.conf, 'bar')
self.assertRaises(
cfg.TemplateSubstitutionError, self.conf._get, 'bar')
self.assertTrue(hasattr(self.conf, 'bar'))
self.assertEqual("blaa", self.conf.bar)
def test_str_sub_from_group_with_brace(self):
self.conf.register_group(cfg.OptGroup('f'))
self.conf.register_cli_opt(cfg.StrOpt('oo', default='blaa'), group='f')
self.conf.register_cli_opt(cfg.StrOpt('bar', default='${f.oo}'))
self.conf([])
self.assertTrue(hasattr(self.conf, 'bar'))
self.assertEqual("blaa", self.conf.bar)
def test_set_default_unknown_attr(self):
self.conf([])

View File

@ -2800,11 +2800,8 @@ class SadPathTestCase(BaseTestCase):
self.conf([])
self.assertFalse(hasattr(self.conf, 'bar'))
self.assertRaises(
AttributeError, getattr, self.conf, 'bar')
self.assertRaises(
cfg.TemplateSubstitutionError, self.conf._get, 'bar')
self.assertTrue(hasattr(self.conf, 'bar'))
self.assertEqual("blaa", self.conf.bar)
def test_set_default_unknown_attr(self):
self.conf([])