[Zodb-checkins] CVS: Packages/ZConfig - SectionMatcher.py:1.1.2.1 SchemaInfo.py:1.1.2.3 SchemaParser.py:1.1.4.2

Fred L. Drake, Jr. fred@zope.com
Mon, 9 Dec 2002 12:02:26 -0500


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

Modified Files:
      Tag: zconfig-schema-devel-branch
	SchemaInfo.py SchemaParser.py 
Added Files:
      Tag: zconfig-schema-devel-branch
	SectionMatcher.py 
Log Message:
Checkpoint: more progress.

=== Added File Packages/ZConfig/SectionMatcher.py ===
"""Utility that manages the binding of configuration data to a section."""

import ZConfig

class SectionMatcher:
    def __init__(self, info, name=None):
        if name is not None:
            self.name = info.nametype.convert(name)
            if not info.isAllowedName(self.name):
                raise ZConfig.ConfigurationError(
                    "%s is not an allowed name for %s sections"
                    % (`name`, `info.name`))
        elif info.allowUnnamed():
            self.name = None
        else:
            raise ZConfig.ConfigurationError(
                `info.name` + " sections may not be unnamed")
        self.info = info
        self._values = {}

    def addKeyValue(self, key, value):
        keyinfo = self.info.getinfo(key)
        if keyinfo.issection():
            if keyinfo.name:
                extra = " in %s sections" % `keyinfo.name`
            else:
                extra = ""
            raise ZConfig.ConfigurationError(
                "%s is not a valid key name%s" % (`key`, extra))
        L = self._values.get(key)
        if L is None:
            L = []
        if keyinfo.maxOccurs is None:
            L.append(value)
        elif len(L) = keyinfo.maxOccurs:
            raise ZConfig.ConfigurationError(
                "too many values for " + `name`)
        else:
            L.append(value)
        self._values[key] = L

    def finish(self):
        """Check the constraints of the section and convert to an application
        object."""
        values = {}
        for key in self.info.getchildnames():
            ci = self.info.getinfo(key)
            if self._values.has_key(key):
                L = self._values[key]
                if len(L) < ci.minOccurs:
                    raise ZConfig.ConfigurationError(
                        "not enough values for %s; %d found, %d required"
                        % (`key`, len(L), ci.minOccurs))
            else:
                L = ci.getdefault()

    def constuct(self):
        keys = self.info.getchildnames()
        values = [None] * len(keys)
        for i in range(len(keys)):
            name = keys[i]
            ci = self.info.getinfo(name)
            if self._values.has_key(name):
                L = self._values[key]
            elif ci.ismulti():
                L = ci.getdefault()
            else:
                L = [ci.getdefault()]
            if ci.ismulti():
                values[i] = [ci.datatype.convert(s) for s in L]
            else:
                assert len(L) == 1
                values[i] = ci.datatype.convert(L[0])
        v = SectionValue(keys, values)
        # XXX  Really should delay this until after all the
        # XXX  sibling SectionValue instances have been created and
        # XXX  we're ready to construct the parent.
        if self.info.handler:
            v = self.info.handler(v)
        return v


class SectionValue:
    def __init__(self, keys, values):
        self._keys = keys
        self._values = values

    def __len__(self):
        return len(self._keys)

    def __getitem__(self, index):
        if isinstance(index, slice):
            raise TypeError("SectionValue does not support slicing")
        return self._values[index]

    def __getattr__(self, name):
        try:
            i = self._keys.index(name)
        except ValueError:
            raise AttributeError, name
        return self._values[i]


=== Packages/ZConfig/SchemaInfo.py 1.1.2.2 => 1.1.2.3 ===
--- Packages/ZConfig/SchemaInfo.py:1.1.2.2	Fri Dec  6 21:37:46 2002
+++ Packages/ZConfig/SchemaInfo.py	Mon Dec  9 12:02:25 2002
@@ -5,10 +5,11 @@
     """Information about a single configuration key."""
 
     def __init__(self, name, datatype, minOccurs, maxOccurs, handler):
-        if maxOccurs < 1:
-            raise ValueError("maxOccurs must be at least 1")
-        if minOccurs < maxOccurs:
-            raise ValueError("minOccurs must be at least maxOccurs")
+        if maxOccurs is not None and maxOccurs < 1:
+            if maxOccurs < 1:
+                raise ValueError("maxOccurs must be at least 1")
+            if minOccurs is not None and minOccurs < maxOccurs:
+                raise ValueError("minOccurs must be at least maxOccurs")
         self.name = name
         self.datatype = datatype
         self.minOccurs = minOccurs
@@ -20,6 +21,11 @@
     def finish(self):
         if self._finished:
             raise ValueError("cannot finish KeyInfo more than once")
+        if self.minOccurs is None:
+            if self._default is not None:
+                self.minOccurs = 1
+            else:
+                self.minOccurs = 0
         self._finished = True
 
     def adddefault(self, value):
@@ -41,8 +47,12 @@
             raise ValueError("cannot get default value of key before KeyInfo"
                              " has been completely initialized")
         if self._default is None and self.maxOccurs > 1:
-            self._default = []
-        return self._default
+            return []
+        else:
+            return self._default
+
+    def hasdefault(self):
+        return self._default is not None
 
     def ismulti(self):
         return self.maxOccurs > 1
@@ -68,12 +78,12 @@
 
     def _add_child(self, thing):
         for c in self._children:
-            if name == c.name:
-                raise ValueError("child name %s already used" % name)
+            if thing.name == c.name:
+                raise ValueError("child name %s already used" % thing.name)
         self._children.append(thing)
 
     def addkey(self, keyinfo):
-        self._add_child(keyinfo.name, keyinfo)
+        self._add_child(keyinfo)
 
     def getinfo(self, name):
         for c in self._children:


=== Packages/ZConfig/SchemaParser.py 1.1.4.1 => 1.1.4.2 ===
--- Packages/ZConfig/SchemaParser.py:1.1.4.1	Fri Dec  6 18:54:03 2002
+++ Packages/ZConfig/SchemaParser.py	Mon Dec  9 12:02:25 2002
@@ -23,6 +23,22 @@
         self._cdata = None
         self._locator = None
         self._prefixes = []
+        self._schema = None
+        self._stack = []
+        self._sections = []
+
+    def parseFile(self, file):
+        if isinstance(file, str) or isinstance(file, unicode):
+            file = open(file, 'rU')
+        return self.parseStream(file)
+
+    def parseString(self, s):
+        xml.sax.parseString(s, self)
+        return self._schema
+
+    def parseStream(self, stream):
+        xml.sax.parse(stream, self)
+        return self._schema
 
     # SAX 2 ContentHandler methods
 
@@ -70,8 +86,6 @@
     def endDocument(self):
         if not self._schema:
             self.doSchemaError("no schema found")
-        self.checkClasses()
-        self.context.setSchema(self._schema)
 
     # schema loading logic
 
@@ -83,7 +97,7 @@
 
     def push_prefix(self, attrs):
         name = attrs.get("prefix")
-        self._prefixes.append(self.get_classname(name) or "")
+        self._prefixes.append(self.get_classname(name or ""))
 
     def start_schema(self, attrs):
         self.start_section(attrs)
@@ -119,18 +133,21 @@
         else:
             names = None
         maxOccurs, minOccurs, handler = self.get_common_info(attrs)
-        
+        section = SectionInfo(None, None, minOccurs, maxOccurs, handler,
+                              keytype, names)
+        self._stack.append(section)
+        self._sections.append(section)
 
     def end_section(self):
         del self._prefixes[-1]
-        self._stack[-1].finish()
+        del self._sections[-1]
+        self._stack.pop().finish()
 
     def start_sectiongroup(self, attrs):
         self.push_prefix(attrs)
 
     def end_sectiongroup(self):
         del self._prefixes[-1]
-        self._stack.pop().finish()
 
     def start_key(self, attrs):
         name = attrs.get("name")
@@ -149,12 +166,22 @@
 
     def get_common_info(self, attrs):
         maxOccurs = attrs.get("maxOccurs")
-        if maxOccurs:
-            maxOccurs = int(maxOccurs)
+        if maxOccurs is not None:
+            if maxOccurs == "unbounded":
+                maxOccurs = None
+            else:
+                maxOccurs = int(maxOccurs)
+        else:
+            maxOccurs = 1
         minOccurs = attrs.get("minOccurs")
         if minOccurs:
             minOccurs = int(minOccurs)
+        else:
+            minOccurs = None
         handler = attrs.get("handler")
         if handler:
             handler = self.get_classname(handler)
         return maxOccurs, minOccurs, handler
+
+    def doSchemaError(self, message):
+        raise ZConfig.ConfigurationError(message)