[Zope-CVS] CVS: Packages/ZConfig - Interpolation.py:1.2

Fred L. Drake, Jr. fdrake@acm.org
Wed, 9 Oct 2002 12:30:32 -0400


Update of /cvs-repository/Packages/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv4882

Modified Files:
	Interpolation.py 
Log Message:
Proposed interface for nested interpolation.

=== Packages/ZConfig/Interpolation.py 1.1 => 1.2 ===
--- Packages/ZConfig/Interpolation.py:1.1	Wed Oct  9 11:33:53 2002
+++ Packages/ZConfig/Interpolation.py	Wed Oct  9 12:30:31 2002
@@ -3,23 +3,54 @@
 XXX document syntax here
 """
 
+class InterpolationError(Exception):
+    """Base exception for string interpolation errors."""
 
-class InterpolationSyntaxError(Exception):
+class InterpolationSyntaxError(InterpolationError):
     """Raised when interpolation source text contains syntactical errors."""
-    pass
+
+    def __init__(self, msg, context):
+        self.message = msg
+        if context is None:
+            self.context = context
+        else:
+            self.context = context[:]
+        InterpolationError.__init__(self, msg, self.context)
+
+class InterpolationRecursionError(InterpolationError):
+    """Raised when a nested interpolation is recursive."""
+
+    def __init__(self, name, context):
+        self.name = name
+        self.context = context[:]
+        self.message = ("recursion on %s; current context:\n%s"
+                        % (repr(name), ", ".join(context)))
+        InterpolationError.__init__(self, name, self.context)
+
+
+def get(section, name, default=None):
+    # XXX should this interpolate from default if that's what's used?
+    missing = []
+    s = section.get(name, missing)
+    if s is missing:
+        return default
+    if "$" in s:
+        accum = []
+        _interp(accum, s, section, [name])
+        s = ''.join(accum)
+    return s
 
 
 def interpolate(s, section):
     """Interpolate variables from `section` into `s`."""
     if '$' in s:
         accum = []
-        _interp(accum, s, section)
-        return ''.join(accum)
-    else:
-        return s
+        _interp(accum, s, section, None)
+        s = ''.join(accum)
+    return s
 
 
-def _interp(accum, rest, section):
+def _interp(accum, rest, section, context):
     while 1:
         i = rest.find("$")
         if i < 0:
@@ -28,7 +59,7 @@
         accum.append(rest[:i])
         rest = rest[i+1:]
         if not rest:
-            raise InterpolationSyntaxError("lone '$' at end of text")
+            raise InterpolationSyntaxError("lone '$' at end of text", context)
         if rest[0] == "$":
             accum.append("$")
             rest = rest[1:]
@@ -36,20 +67,34 @@
             rest = rest[1:]
             m = _name_match(rest[:])
             if not m:
-                raise InterpolationSyntaxError("'${' not followed by name")
+                raise InterpolationSyntaxError("'${' not followed by name",
+                                               context)
             name = m.group(0)
             length = len(name)
             if rest[length:length+1] != "}":
-                raise InterpolationSyntaxError("'${%s' not followed by '}'"
-                                               % name)
-            accum.append(section.get(name, ""))
+                raise InterpolationSyntaxError(
+                    "'${%s' not followed by '}'" % name, context)
+            v = section.get(name, "")
+            if "$" in v and context:
+                if name in context:
+                    raise InterpolationRecursionError(name, context)
+                _interp(accum, v, section, context + [name])
+            else:
+                accum.append(v)
             rest = rest[length+1:]
         else:
             m = _name_match(rest)
             if not m:
-                raise InterpolationSyntaxError("'$' not followed by name")
+                raise InterpolationSyntaxError("'$' not followed by name",
+                                               context)
             name = m.group(0)
-            accum.append(section.get(name, ""))
+            v = section.get(name, "")
+            if "$" in v and context:
+                if name in context:
+                    raise InterpolationRecursionError(name, context)
+                _interp(accum, v, section, context + [name])
+            else:
+                accum.append(v)
             rest = rest[len(name):]