[Zope-Checkins] CVS: Zope/lib/python/ZConfig - Substitution.py:1.3.2.1 ApacheStyle.py:1.2.4.1 Config.py:1.3.4.1 Context.py:1.5.4.1 __init__.py:1.1.14.1 Interpolation.py:NONE

Andreas Jung andreas@andreas-jung.com
Sat, 9 Nov 2002 03:43:29 -0500


Update of /cvs-repository/Zope/lib/python/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv26094/lib/python/ZConfig

Modified Files:
      Tag: ajung-restructuredtext-integration-branch
	ApacheStyle.py Config.py Context.py __init__.py 
Added Files:
      Tag: ajung-restructuredtext-integration-branch
	Substitution.py 
Removed Files:
      Tag: ajung-restructuredtext-integration-branch
	Interpolation.py 
Log Message:
merge from trunk


=== Added File Zope/lib/python/ZConfig/Substitution.py ===
"""Substitution support for ZConfig values."""

class SubstitutionError(Exception):
    """Base exception for string substitution errors."""

    def __init__(self, msg, context):
        self.message = msg
        self.context = context

    def __str__(self):
        return self.message

class SubstitutionSyntaxError(SubstitutionError):
    """Raised when interpolation source text contains syntactical errors."""

    def __init__(self, msg, context):
        if context is not None:
            context = context[:]
        SubstitutionError.__init__(self, msg, context)

class SubstitutionRecursionError(SubstitutionError):
    """Raised when a nested interpolation is recursive."""

    def __init__(self, name, context):
        self.name = name
        msg = ("recursion on %s; current context:\n%s"
               % (repr(name), ", ".join(context)))
        SubstitutionError.__init__(self, msg, 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 substitute(s, section):
    """Interpolate variables from `section` into `s`."""
    if '$' in s:
        accum = []
        _interp(accum, s, section, None)
        s = ''.join(accum)
    return s


def _interp(accum, rest, section, context):
    while 1:
        i = rest.find("$")
        if i < 0:
            accum.append(rest)
            break
        accum.append(rest[:i])
        rest = rest[i+1:]
        if not rest:
            accum.append("$")
            break
        if rest[0] == "$":
            accum.append("$")
            rest = rest[1:]
        elif rest[0] == "{":
            rest = rest[1:]
            m = _name_match(rest[:])
            if not m:
                raise SubstitutionSyntaxError("'${' not followed by name",
                                              context)
            name = m.group(0)
            length = len(name)
            if rest[length:length+1] != "}":
                raise SubstitutionSyntaxError(
                    "'${%s' not followed by '}'" % name, context)
            v = section.get(name)
            if v is None:
                parent = getattr(section, "container", None)
                while parent is not None:
                    v = parent.get(name)
                    if v is not None:
                        break
                    parent = getattr(parent, "container", None)
                else:
                    v = ""
            if "$" in v and context:
                if name in context:
                    raise SubstitutionRecursionError(name, context)
                _interp(accum, v, section, context + [name])
            else:
                accum.append(v)
            rest = rest[length+1:]
        else:
            m = _name_match(rest)
            if not m:
                accum.append("$")
                continue
            name = m.group(0)
            v = section.get(name, "")
            if "$" in v and context:
                if name in context:
                    raise SubstitutionRecursionError(name, context)
                _interp(accum, v, section, context + [name])
            else:
                accum.append(v)
            rest = rest[len(name):]


import re
_name_match = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*").match
del re


=== Zope/lib/python/ZConfig/ApacheStyle.py 1.2 => 1.2.4.1 ===
--- Zope/lib/python/ZConfig/ApacheStyle.py:1.2	Mon Oct 21 14:40:09 2002
+++ Zope/lib/python/ZConfig/ApacheStyle.py	Sat Nov  9 03:42:58 2002
@@ -32,6 +32,7 @@
             if type.lower() != section.type:
                 raise ConfigurationSyntaxError(
                     "unbalanced section end", url, lineno)
+            section.finish()
             section = stack.pop()
             continue
         if line[0] == "<":


=== Zope/lib/python/ZConfig/Config.py 1.3 => 1.3.4.1 ===
--- Zope/lib/python/ZConfig/Config.py:1.3	Mon Oct 21 14:59:54 2002
+++ Zope/lib/python/ZConfig/Config.py	Sat Nov  9 03:42:58 2002
@@ -3,7 +3,8 @@
 from Common import *
 
 class Configuration:
-    def __init__(self, type, name, url):
+    def __init__(self, container, type, name, url):
+        self.container = container
         self.type = type
         self.name = name or None
         self.delegate = None
@@ -25,6 +26,9 @@
         else:
             return "<%s at 0x%x>" % (classname, id(self))
 
+    def finish(self):
+        pass
+
     def setDelegate(self, section):
         if self.delegate is not None:
             raise ConfigurationError("cannot modify delegation")
@@ -198,9 +202,9 @@
 
 
 class ImportingConfiguration(Configuration):
-    def __init__(self, *args):
+    def __init__(self, url):
         self._imports = []
-        Configuration.__init__(self, *args)
+        Configuration.__init__(self, None, None, None, url)
 
     def addImport(self, section):
         self._imports.append(section)


=== Zope/lib/python/ZConfig/Context.py 1.5 => 1.5.4.1 ===
--- Zope/lib/python/ZConfig/Context.py:1.5	Wed Oct 16 17:12:50 2002
+++ Zope/lib/python/ZConfig/Context.py	Sat Nov  9 03:42:58 2002
@@ -17,19 +17,20 @@
         self._named_sections = {}  # name -> Configuration
         self._needed_names = {}    # name -> [needy Configuration, ...]
         self._current_imports = []
+        self._all_sections = []
 
     # subclass-support API
 
     def createImportedSection(self, section, url):
-        return ImportingConfiguration(None, None, url)
+        return ImportingConfiguration(url)
 
     def createNestedSection(self, section, type, name, delegatename):
         if name:
             name = name.lower()
-        return Configuration(type.lower(), name, section.url)
+        return Configuration(section, type.lower(), name, section.url)
 
     def createToplevelSection(self, url):
-        return ImportingConfiguration(None, None, url)
+        return ImportingConfiguration(url)
 
     def getDelegateType(self, type):
         # Applications must provide delegation typing information by
@@ -47,11 +48,29 @@
         if os.path.exists(url):
             url = "file://" + urllib.pathname2url(os.path.abspath(url))
         top = self.createToplevelSection(url)
+        self._all_sections.append(top)
         self._imports = [top]
         self._parse_url(url, top)
         self._finish()
         return top
 
+    def loadfile(self, file, url=None):
+        if not url:
+            name = getattr(file, "name", None)
+            if name and name[0] != "<" and name[-1] != ">":
+                url = "file://" + urllib.pathname2url(os.path.abspath(name))
+        top = self.createToplevelSection(url)
+        self._all_sections.append(top)
+        self._imports = [top]
+        self._current_imports.append(top)
+        try:
+            self.parse(file, top, url)
+        finally:
+            del self._current_imports[-1]
+        self._finish()
+        return top
+
+
     # interface for parser
 
     def importConfiguration(self, section, url):
@@ -59,6 +78,7 @@
             if config.url == url:
                 return config
         newsect = self.createImportedSection(section, url)
+        self._all_sections.append(newsect)
         self._imports.append(newsect)
         section.addImport(newsect)
         self._parse_url(url, newsect)
@@ -88,6 +108,7 @@
                 raise ConfigurationError(
                     "named section cannot change type")
         newsect = self.createNestedSection(section, type, name, delegatename)
+        self._all_sections.append(newsect)
         if delegatename:
             # The knitting together of the delegation graph needs this.
             try:
@@ -144,3 +165,17 @@
                         referrer.type, type)
                 referrer.setDelegate(section)
         self._needed_names = None
+        # Now "finish" the sections, making sure we close inner
+        # sections before outer sections.  We really should order
+        # these better, but for now, "finish" all sections that have
+        # no delegates first, then those that have them.  This is not
+        # enough to guarantee that delegates are finished before their
+        # users.
+        self._all_sections.reverse()
+        for sect in self._all_sections:
+            if sect.delegate is None:
+                sect.finish()
+        for sect in self._all_sections:
+            if sect.delegate is not None:
+                sect.finish()
+        self._all_sections = None


=== Zope/lib/python/ZConfig/__init__.py 1.1 => 1.1.14.1 ===
--- Zope/lib/python/ZConfig/__init__.py:1.1	Tue Oct  8 17:42:17 2002
+++ Zope/lib/python/ZConfig/__init__.py	Sat Nov  9 03:42:58 2002
@@ -19,3 +19,7 @@
 def load(url):
     import Context
     return Context.Context().load(url)
+
+def loadfile(file, url=None):
+    import Context
+    return Context.Context().loadfile(file, url)

=== Removed File Zope/lib/python/ZConfig/Interpolation.py ===