Kaydet (Commit) 0eebd5ce authored tarafından Fred Drake's avatar Fred Drake

Implement a safer and more predictable interpolation approach.

Closes SF bug #511737.
üst 98e3b29b
......@@ -59,6 +59,16 @@ appropriate for the \samp{\%()s} string interpolation. Note that
and will override any value provided in \var{defaults}.
\end{classdesc}
\begin{classdesc}{SafeConfigParser}{\optional{defaults}}
Derived class of \class{ConfigParser} that implements a more-sane
variant of the magical interpolation feature. This implementation is
more predictable as well.
% XXX Need to explain what's safer/more predictable about it.
New applications should prefer this version if they don't need to be
compatible with older versions of Python.
\versionadded{2.3}
\end{classdesc}
\begin{excdesc}{NoSectionError}
Exception raised when a specified section is not found.
\end{excdesc}
......
......@@ -538,3 +538,51 @@ class ConfigParser(RawConfigParser):
if value.find("%(") != -1:
raise InterpolationDepthError(option, section, rawval)
return value
class SafeConfigParser(ConfigParser):
def _interpolate(self, section, option, rawval, vars):
# do the string interpolation
L = []
self._interpolate_some(option, L, rawval, section, vars, 1)
return ''.join(L)
_interpvar_match = re.compile(r"%\(([^)]+)\)s").match
def _interpolate_some(self, option, accum, rest, section, map, depth):
if depth > MAX_INTERPOLATION_DEPTH:
raise InterpolationDepthError(option, section, rest)
while rest:
p = rest.find("%")
if p < 0:
accum.append(rest)
return
if p > 0:
accum.append(rest[:p])
rest = rest[p:]
# p is no longer used
c = rest[1:2]
if c == "%":
accum.append("%")
rest = rest[2:]
elif c == "(":
m = self._interpvar_match(rest)
if m is None:
raise InterpolationSyntaxError(
"bad interpolation variable syntax at: %r" % rest)
var = m.group(1)
rest = rest[m.end():]
try:
v = map[var]
except KeyError:
raise InterpolationError(
"no value found for %r" % var)
if "%" in v:
self._interpolate_some(option, accum, v,
section, map, depth + 1)
else:
accum.append(v)
else:
raise InterpolationSyntaxError(
"'%' must be followed by '%' or '('")
......@@ -289,10 +289,25 @@ class RawConfigParserTestCase(TestCaseBase):
('name', 'value')])
class SafeConfigParserTestCase(ConfigParserTestCase):
config_class = ConfigParser.SafeConfigParser
def test_safe_interpolation(self):
# See http://www.python.org/sf/511737
cf = self.fromstring("[section]\n"
"option1=xxx\n"
"option2=%(option1)s/xxx\n"
"ok=%(option1)s/%%s\n"
"not_ok=%(option2)s/%%s")
self.assertEqual(cf.get("section", "ok"), "xxx/%s")
self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
def test_main():
suite = unittest.TestSuite()
suite.addTests([unittest.makeSuite(ConfigParserTestCase),
unittest.makeSuite(RawConfigParserTestCase)])
unittest.makeSuite(RawConfigParserTestCase),
unittest.makeSuite(SafeConfigParserTestCase)])
test_support.run_suite(suite)
if __name__ == "__main__":
......
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