From e4d0e46edc27d3dbab6c434290d3f65e2ebd8c07 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Sun, 3 Jun 2018 12:03:33 -0400 Subject: [PATCH] Allow non-strings to be used for interpolation * Have the interpolation engine always use the string representation of a value when recursively processing the interpolation. --- src/configobj/__init__.py | 16 ++++++++++------ src/tests/test_configobj.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/configobj/__init__.py b/src/configobj/__init__.py index 3f6eac0..a46f6e6 100644 --- a/src/configobj/__init__.py +++ b/src/configobj/__init__.py @@ -281,7 +281,8 @@ def recursive_interpolate(key, value, section, backtrail): replacement = v else: # Further interpolation may be needed to obtain final value - replacement = recursive_interpolate(k, v, s, backtrail) + replacement = recursive_interpolate( + k, s.main._write_value(v), s, backtrail) # Replace the matched string with its final value start, end = match.span() value = ''.join((value[:start], replacement, value[end:])) @@ -1943,17 +1944,20 @@ def _set_configspec(self, section, copy): def _write_line(self, indent_string, entry, this_entry, comment): """Write an individual line, for the write method""" - # NOTE: the calls to self._quote here handles non-StringType values. - if not self.unrepr: - val = self._decode_element(self._quote(this_entry)) - else: - val = repr(this_entry) + val = self._write_value(this_entry) return '%s%s%s%s%s' % (indent_string, self._decode_element(self._quote(entry, multiline=False)), self._a_to_u(' = '), val, self._decode_element(comment)) + def _write_value(self, this_entry): + # NOTE: the calls to self._quote here handles non-StringType values. + if not self.unrepr: + val = self._decode_element(self._quote(this_entry)) + else: + val = repr(this_entry) + return val def _write_marker(self, indent_string, depth, entry, comment): """Write a section marker line""" diff --git a/src/tests/test_configobj.py b/src/tests/test_configobj.py index 6bc5813..f537ea6 100644 --- a/src/tests/test_configobj.py +++ b/src/tests/test_configobj.py @@ -916,7 +916,10 @@ def config_parser_cfg(self): 'b': 'goodbye', 'userdir': r'c:\\home', 'c': '%(d)s', - 'd': '%(c)s' + 'd': '%(c)s', + 'f': 45.5, + 'list1': [1, 2, 3], + 'list2': ['foo', 'bar', 'baz'] } cfg['section'] = { 'a': r'%(datadir)s\\some path\\file.py', @@ -924,6 +927,10 @@ def config_parser_cfg(self): 'c': 'Yo %(a)s', 'd': '%(not_here)s', 'e': '%(e)s', + 'ff': 'Some float: %(f)s', + 'report1': 'list 1: %(list1)s', + 'report2': '%(report1)s and list 2: %(list2)s', + 'listreference': '%(list1)s' } cfg['section']['DEFAULT'] = { 'datadir': r'c:\\silly_test', @@ -939,6 +946,10 @@ def template_cfg(self, cfg_contents): 'keyword 2' = 'value 2' reference = ${keyword1} foo = 123 + f = 45.5 + list1 = 1, 2, 3 + list2 = foo, bar, baz + [ section ] templatebare = $keyword1/foo @@ -950,6 +961,10 @@ def template_cfg(self, cfg_contents): with_several = $keyword1/$reference/$keyword1 configparsersample = %(keyword 2)sconfig deep = ${reference} + ff = Some float: ${f} + report1 = list 1: ${list1} + report2 = $report1 and list 2: $list2 + listreference = $list1 [[DEFAULT]] baz = $foo @@ -967,6 +982,12 @@ def test_interpolation(self, config_parser_cfg): assert test_section['a'] == r'c:\\silly_test\\some path\\file.py' assert test_section['b'] == r'c:\\home\\some path\\file.py' assert test_section['c'] == r'Yo c:\\silly_test\\some path\\file.py' + assert test_section['ff'] == r'Some float: 45.5' + assert test_section['report1'] == r'list 1: 1, 2, 3' + assert test_section['report2'] == r'list 1: 1, 2, 3 and list 2: foo, bar, baz' + # FIXME: Hmmm, what should this do, actually? + # Could be '1, 2, 3'? or ['1', '2', '3']? or something else? + assert test_section['listreference'] == '1, 2, 3' def test_interpolation_turned_off(self, config_parser_cfg): config_parser_cfg.interpolation = False @@ -1000,6 +1021,12 @@ def test_template_interpolation(self, template_cfg): assert test_sec['sub-section']['quux'] == '123 + $foo + 123' assert (test_sec['sub-section']['sub-sub-section']['convoluted'] == '$foo + 123 + 123 + $foo + 123 + $foo') + assert test_sec['ff'] == r'Some float: 45.5' + assert test_sec['report1'] == r'list 1: 1, 2, 3' + assert test_sec['report2'] == r'list 1: 1, 2, 3 and list 2: foo, bar, baz' + # FIXME: Hmmm, what should this do, actually? + # Could be '1, 2, 3'? or ['1', '2', '3']? or something else? + assert test_sec['listreference'] == '1, 2, 3' class TestQuotes(object):