From bc12b01d8349e185c8a52a0f2539e830dfae9adb Mon Sep 17 00:00:00 2001
From: Fred Drake <fdrake@acm.org>
Date: Tue, 18 May 2004 02:25:51 +0000
Subject: ConfigParser: - ensure that option names in interpolations are
 handled by   self.optionxform in the same way that other references to option
   names - add tests, documentation (closes SF bug #857881, patch #865455)

---
 Doc/lib/libcfgparser.tex   |  9 +++++++++
 Lib/ConfigParser.py        | 12 +++++++++++-
 Lib/test/test_cfgparser.py |  8 ++++----
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/Doc/lib/libcfgparser.tex b/Doc/lib/libcfgparser.tex
index ca9eb2d..a64ae53 100644
--- a/Doc/lib/libcfgparser.tex
+++ b/Doc/lib/libcfgparser.tex
@@ -62,6 +62,13 @@ and \method{items()} methods.  The values in \var{defaults} must be
 appropriate for the \samp{\%()s} string interpolation.  Note that
 \var{__name__} is an intrinsic default; its value is the section name,
 and will override any value provided in \var{defaults}.
+
+All option names used in interpolation will be passed through the
+\method{optionxform()} method just like any other option name
+reference.  For example, using the default implementation of
+\method{optionxform()} (which converts option names to lower case),
+the values \samp{foo \%(bar)s} and \samp{foo \%(BAR)s} are
+equivalent.
 \end{classdesc}
 
 \begin{classdesc}{SafeConfigParser}{\optional{defaults}}
@@ -271,6 +278,8 @@ option names case sensitive.
 
 The \class{ConfigParser} class extends some methods of the
 \class{RawConfigParser} interface, adding some optional arguments.
+The \class{SafeConfigParser} class implements the same extended
+interface.
 
 \begin{methoddesc}{get}{section, option\optional{, raw\optional{, vars}}}
 Get an \var{option} value for the named \var{section}.  All the
diff --git a/Lib/ConfigParser.py b/Lib/ConfigParser.py
index d32eae0..73acdd1 100644
--- a/Lib/ConfigParser.py
+++ b/Lib/ConfigParser.py
@@ -555,6 +555,7 @@ class ConfigParser(RawConfigParser):
         while depth:                    # Loop through this until it's done
             depth -= 1
             if "%(" in value:
+                value = self._KEYCRE.sub(self._interpolation_replace, value)
                 try:
                     value = value % vars
                 except KeyError, e:
@@ -566,6 +567,15 @@ class ConfigParser(RawConfigParser):
             raise InterpolationDepthError(option, section, rawval)
         return value
 
+    _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
+
+    def _interpolation_replace(self, match):
+        s = match.group(1)
+        if s is None:
+            return match.group()
+        else:
+            return "%%(%s)s" % self.optionxform(s)
+
 
 class SafeConfigParser(ConfigParser):
 
@@ -598,7 +608,7 @@ class SafeConfigParser(ConfigParser):
                 if m is None:
                     raise InterpolationSyntaxError(option, section,
                         "bad interpolation variable reference %r" % rest)
-                var = m.group(1)
+                var = self.optionxform(m.group(1))
                 rest = rest[m.end():]
                 try:
                     v = map[var]
diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py
index b1b495e..28063b5 100644
--- a/Lib/test/test_cfgparser.py
+++ b/Lib/test/test_cfgparser.py
@@ -222,11 +222,11 @@ class TestCaseBase(unittest.TestCase):
             "with11=%(with10)s\n"
             "with10=%(with9)s\n"
             "with9=%(with8)s\n"
-            "with8=%(with7)s\n"
-            "with7=%(with6)s\n"
+            "with8=%(With7)s\n"
+            "with7=%(WITH6)s\n"
             "with6=%(with5)s\n"
-            "with5=%(with4)s\n"
-            "with4=%(with3)s\n"
+            "With5=%(with4)s\n"
+            "WITH4=%(with3)s\n"
             "with3=%(with2)s\n"
             "with2=%(with1)s\n"
             "with1=with\n"
-- 
cgit v0.12

