Commit ac37ba07 authored by Robert Collins's avatar Robert Collins

Issue #21159: Improve message in configparser.InterpolationMissingOptionError.

Patch from Łukasz Langa.
parent 4ce4f974
...@@ -241,12 +241,9 @@ class InterpolationMissingOptionError(InterpolationError): ...@@ -241,12 +241,9 @@ class InterpolationMissingOptionError(InterpolationError):
"""A string substitution required a setting which was not available.""" """A string substitution required a setting which was not available."""
def __init__(self, option, section, rawval, reference): def __init__(self, option, section, rawval, reference):
msg = ("Bad value substitution:\n" msg = ("Bad value substitution: option {!r} in section {!r} contains "
"\tsection: [%s]\n" "an interpolation key {!r} which is not a valid option name. "
"\toption : %s\n" "Raw value: {!r}".format(option, section, reference, rawval))
"\tkey : %s\n"
"\trawval : %s\n"
% (section, option, reference, rawval))
InterpolationError.__init__(self, option, section, msg) InterpolationError.__init__(self, option, section, msg)
self.reference = reference self.reference = reference
self.args = (option, section, rawval, reference) self.args = (option, section, rawval, reference)
...@@ -264,11 +261,11 @@ class InterpolationDepthError(InterpolationError): ...@@ -264,11 +261,11 @@ class InterpolationDepthError(InterpolationError):
"""Raised when substitutions are nested too deeply.""" """Raised when substitutions are nested too deeply."""
def __init__(self, option, section, rawval): def __init__(self, option, section, rawval):
msg = ("Value interpolation too deeply recursive:\n" msg = ("Recursion limit exceeded in value substitution: option {!r} "
"\tsection: [%s]\n" "in section {!r} contains an interpolation key which "
"\toption : %s\n" "cannot be substituted in {} steps. Raw value: {!r}"
"\trawval : %s\n" "".format(option, section, MAX_INTERPOLATION_DEPTH,
% (section, option, rawval)) rawval))
InterpolationError.__init__(self, option, section, msg) InterpolationError.__init__(self, option, section, msg)
self.args = (option, section, rawval) self.args = (option, section, rawval)
...@@ -384,8 +381,9 @@ class BasicInterpolation(Interpolation): ...@@ -384,8 +381,9 @@ class BasicInterpolation(Interpolation):
def _interpolate_some(self, parser, option, accum, rest, section, map, def _interpolate_some(self, parser, option, accum, rest, section, map,
depth): depth):
rawval = parser.get(section, option, raw=True, fallback=rest)
if depth > MAX_INTERPOLATION_DEPTH: if depth > MAX_INTERPOLATION_DEPTH:
raise InterpolationDepthError(option, section, rest) raise InterpolationDepthError(option, section, rawval)
while rest: while rest:
p = rest.find("%") p = rest.find("%")
if p < 0: if p < 0:
...@@ -410,7 +408,7 @@ class BasicInterpolation(Interpolation): ...@@ -410,7 +408,7 @@ class BasicInterpolation(Interpolation):
v = map[var] v = map[var]
except KeyError: except KeyError:
raise InterpolationMissingOptionError( raise InterpolationMissingOptionError(
option, section, rest, var) option, section, rawval, var)
if "%" in v: if "%" in v:
self._interpolate_some(parser, option, accum, v, self._interpolate_some(parser, option, accum, v,
section, map, depth + 1) section, map, depth + 1)
...@@ -444,8 +442,9 @@ class ExtendedInterpolation(Interpolation): ...@@ -444,8 +442,9 @@ class ExtendedInterpolation(Interpolation):
def _interpolate_some(self, parser, option, accum, rest, section, map, def _interpolate_some(self, parser, option, accum, rest, section, map,
depth): depth):
rawval = parser.get(section, option, raw=True, fallback=rest)
if depth > MAX_INTERPOLATION_DEPTH: if depth > MAX_INTERPOLATION_DEPTH:
raise InterpolationDepthError(option, section, rest) raise InterpolationDepthError(option, section, rawval)
while rest: while rest:
p = rest.find("$") p = rest.find("$")
if p < 0: if p < 0:
...@@ -482,7 +481,7 @@ class ExtendedInterpolation(Interpolation): ...@@ -482,7 +481,7 @@ class ExtendedInterpolation(Interpolation):
"More than one ':' found: %r" % (rest,)) "More than one ':' found: %r" % (rest,))
except (KeyError, NoSectionError, NoOptionError): except (KeyError, NoSectionError, NoOptionError):
raise InterpolationMissingOptionError( raise InterpolationMissingOptionError(
option, section, rest, ":".join(path)) option, section, rawval, ":".join(path))
if "$" in v: if "$" in v:
self._interpolate_some(parser, opt, accum, v, sect, self._interpolate_some(parser, opt, accum, v, sect,
dict(parser.items(sect, raw=True)), dict(parser.items(sect, raw=True)),
......
...@@ -847,7 +847,8 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase): ...@@ -847,7 +847,8 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase):
"something with lots of interpolation (10 steps)") "something with lots of interpolation (10 steps)")
e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11") e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
if self.interpolation == configparser._UNSET: if self.interpolation == configparser._UNSET:
self.assertEqual(e.args, ("bar11", "Foo", "%(with1)s")) self.assertEqual(e.args, ("bar11", "Foo",
"something %(with11)s lots of interpolation (11 steps)"))
elif isinstance(self.interpolation, configparser.LegacyInterpolation): elif isinstance(self.interpolation, configparser.LegacyInterpolation):
self.assertEqual(e.args, ("bar11", "Foo", self.assertEqual(e.args, ("bar11", "Foo",
"something %(with11)s lots of interpolation (11 steps)")) "something %(with11)s lots of interpolation (11 steps)"))
...@@ -861,7 +862,7 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase): ...@@ -861,7 +862,7 @@ class ConfigParserTestCase(BasicTestCase, unittest.TestCase):
self.assertEqual(e.option, "name") self.assertEqual(e.option, "name")
if self.interpolation == configparser._UNSET: if self.interpolation == configparser._UNSET:
self.assertEqual(e.args, ('name', 'Interpolation Error', self.assertEqual(e.args, ('name', 'Interpolation Error',
'', 'reference')) '%(reference)s', 'reference'))
elif isinstance(self.interpolation, configparser.LegacyInterpolation): elif isinstance(self.interpolation, configparser.LegacyInterpolation):
self.assertEqual(e.args, ('name', 'Interpolation Error', self.assertEqual(e.args, ('name', 'Interpolation Error',
'%(reference)s', 'reference')) '%(reference)s', 'reference'))
...@@ -1177,7 +1178,7 @@ class ConfigParserTestCaseExtendedInterpolation(BasicTestCase, unittest.TestCase ...@@ -1177,7 +1178,7 @@ class ConfigParserTestCaseExtendedInterpolation(BasicTestCase, unittest.TestCase
with self.assertRaises(exception_class) as cm: with self.assertRaises(exception_class) as cm:
cf['interpolated']['$trying'] cf['interpolated']['$trying']
self.assertEqual(cm.exception.reference, 'dollars:${sick') self.assertEqual(cm.exception.reference, 'dollars:${sick')
self.assertEqual(cm.exception.args[2], '}') #rawval self.assertEqual(cm.exception.args[2], '${dollars:${sick}}') #rawval
def test_case_sensitivity_basic(self): def test_case_sensitivity_basic(self):
ini = textwrap.dedent(""" ini = textwrap.dedent("""
......
...@@ -75,6 +75,9 @@ Core and Builtins ...@@ -75,6 +75,9 @@ Core and Builtins
Library Library
------- -------
- Issue #21159: Improve message in configparser.InterpolationMissingOptionError.
Patch from Łukasz Langa.
- Issue #23888: Handle fractional time in cookie expiry. Patch by ssh. - Issue #23888: Handle fractional time in cookie expiry. Patch by ssh.
- Issue #23004: mock_open() now reads binary data correctly when the type of - Issue #23004: mock_open() now reads binary data correctly when the type of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment