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

Fred L. Drake, Jr. fred@zope.com
Mon, 9 Dec 2002 17:51:21 -0500


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

Modified Files:
      Tag: zconfig-schema-devel-branch
	SchemaInfo.py SchemaParser.py SectionMatcher.py 
Log Message:
Allow data binding to names other than the key names.

=== Packages/ZConfig/SchemaInfo.py 1.1.2.7 => 1.1.2.8 ===
--- Packages/ZConfig/SchemaInfo.py:1.1.2.7	Mon Dec  9 14:12:55 2002
+++ Packages/ZConfig/SchemaInfo.py	Mon Dec  9 17:51:20 2002
@@ -29,7 +29,8 @@
 class KeyInfo:
     """Information about a single configuration key."""
 
-    def __init__(self, name, datatype, minOccurs, maxOccurs, handler):
+    def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
+                 attribute):
         if maxOccurs is not None and maxOccurs < 1:
             if maxOccurs < 1:
                 raise ValueError("maxOccurs must be at least 1")
@@ -40,6 +41,7 @@
         self.minOccurs = minOccurs
         self.maxOccurs = maxOccurs
         self.handler = handler
+        self.attribute = attribute
         self._default = None
         self._finished = False
 
@@ -91,57 +93,55 @@
 
 class SectionInfo(KeyInfo):
     def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
-                 keytype, names, nametype):
+                 attribute, keytype, names, nametype):
         assert keytype is not None
         self.keytype = keytype
-        self.names = names
+        self.names = names   # '*', '+', or [name1, ...]
         self.nametype = nametype
-        self._children = []
-        self._keyindex = {}
+        self._children = []  # [(name, info), ...]
         KeyInfo.__init__(self, name, datatype, minOccurs, maxOccurs,
-                         handler)
+                         handler, attribute)
 
     def _add_child(self, name, thing):
-        if name in self._keyindex:
-            raise ValueError("child name %s already used" % name)
-        index = len(self._children)
-        self._children.append(thing)
-        self._keyindex[name] = index, thing
+        for n, info in self._children:
+            if name and n == name:
+                raise ValueError("child name %s already used" % name)
+            if info.attribute and info.attribute == thing.attribute:
+                raise ValueError("child attribute name %s already used"
+                                 % thing.attribute)
+        self._children.append((name, thing))
 
     def addkey(self, keyinfo):
         self._add_child(keyinfo.name, keyinfo)
 
     def addsection(self, name, sectinfo):
-        if name == "*" or name == "+":
-            raise NotImplementedError("sections without a specific name"
-                                      " are not yet supported")
+        assert name not in ("*", "+")
         self._add_child(name, sectinfo)
 
     def getinfo(self, name):
-        try:
-            index, thing = self._keyindex[name]
-        except KeyError:
+        if not name:
             return None
+        for n, info in self._children:
+            if n == name:
+                return info
         else:
-            return thing
+            return None
 
     def getchildnames(self):
-        L = [(i,n) for (n,(i,t)) in self._keyindex.iteritems()]
-        L.sort()
-        return [n for (i,n) in L]
+        return [n for (n,info) in self._children]
 
     def issection(self):
         return True
 
     def allowUnnamed(self):
-        return "*" in self.names
+        return self.names == "*"
 
     def isAllowedName(self, name):
         if name == "*" or name == "+":
             return False
-        elif "+" in self.names:
+        elif self.names == "+":
             return bool(name)
         elif not name:
-            return "*" in self.names
+            return self.names == "*"
         else:
             return name in self.names


=== Packages/ZConfig/SchemaParser.py 1.1.4.4 => 1.1.4.5 ===
--- Packages/ZConfig/SchemaParser.py:1.1.4.4	Mon Dec  9 14:12:55 2002
+++ Packages/ZConfig/SchemaParser.py	Mon Dec  9 17:51:20 2002
@@ -13,6 +13,8 @@
 default_key_type = ZConfig.DataTypes.get("basic-key")
 default_name_type = default_key_type
 
+_identifier = ZConfig.DataTypes.get("identifier").convert
+
 
 class SchemaParser(xml.sax.ContentHandler):
 
@@ -108,7 +110,7 @@
             keytype = ZConfig.DataTypes.get(attrs["keytype"])
         else:
             keytype = default_key_type
-        self._schema = SectionInfo(None, None, 1, 1, handler,
+        self._schema = SectionInfo(None, None, 1, 1, handler, None,
                                    keytype, (), None)
         self._sections = [self._schema]
         self._stack = [self._schema]
@@ -121,6 +123,9 @@
 
     def start_section(self, attrs):
         self.push_prefix(attrs)
+        type = attrs.get("type")
+        if not type:
+            self.doSchemaError("section does not specify type")
         if attrs.has_key("keytype"):
             keytype = ZConfig.DataTypes.get(attrs["keytype"])
         else:
@@ -129,46 +134,19 @@
             nametype = ZConfig.DataTypes.get(attrs["nametype"])
         else:
             nametype = default_name_type
-        anyname = anyornoname = False
-        names = []
-        name = None
-        if attrs.has_key("names"):
-            for s in attrs["names"].split("|"):
-                s = s.strip()
-                if not s:
-                    self.doSchemaError("empty section name not allowed")
-                if s == "*":
-                    if anyname:
-                        self.doSchemaError("cannot specify both '+' and '*'"
-                                           " naming for a section")
-                    if anyornoname:
-                        self.doSchemaError("can specify '*' only once")
-                    anyornoname = True
-                elif s == "+":
-                    if anyornoname:
-                        self.doSchemaError("cannot specify both '*' and '+'"
-                                           " naming for a section")
-                    if anyname:
-                        self.doSchemaError("can specify '+' only once")
-                    anyname = True
-                else:
-                    s = nametype.convert(s)
-                    if s == "*" or s == "+":
-                        self.doSchemaError("nametypes may not convert to"
-                                           " '*' or '+'")
-                    name = name or s
-                names.append(s)
-        else:
-            names = "*",
         maxOccurs, minOccurs, handler = self.get_common_info(attrs)
+        any, names, attribute = self.get_names_info(attrs, nametype)
         if self._stack:
             parent = self._stack[-1]
         else:
             parent = self._schema
-        section = SectionInfo(name, None, minOccurs, maxOccurs, handler,
-                              keytype, names, nametype)
-        for n in names:
-            parent.addsection(n, section)
+        section = SectionInfo(None, None, minOccurs, maxOccurs, handler,
+                              attribute, keytype, names, nametype)
+        if any:
+            parent.addsection(None, section)
+        else:
+            for n in names:
+                parent.addsection(n, section)
         self._stack.append(section)
         self._sections.append(section)
 
@@ -179,6 +157,9 @@
 
     def start_sectiongroup(self, attrs):
         self.push_prefix(attrs)
+        name = attrs.get("name")
+        if not name:
+            self.doSchemaError("section group must be named")
 
     def end_sectiongroup(self):
         del self._prefixes[-1]
@@ -191,7 +172,13 @@
         name = self._stack[-1].keytype.convert(name)
         datatype = ZConfig.DataTypes.get(attrs.get("type"))
         maxOccurs, minOccurs, handler = self.get_common_info(attrs)
-        key = KeyInfo(name, datatype, minOccurs, maxOccurs, handler)
+        attribute = attrs.get("attribute")
+        if attribute:
+            attribute = _identifier(attribute)
+        else:
+            attribute = _identifier(name.replace("-", "_"))
+        key = KeyInfo(name, datatype, minOccurs, maxOccurs, handler,
+                      attribute)
         self._sections[-1].addkey(key)
         self._stack.append(key)
 
@@ -218,6 +205,45 @@
         if handler:
             handler = self.get_classname(handler)
         return maxOccurs, minOccurs, handler
+
+    def get_names_info(self, attrs, nametype):
+        if not attrs.get("names"):
+            self.doSchemaError("allowed section names must be specified")
+        anyname = None
+        names = []
+        s = attrs["names"]
+        if s in ("*", "+"):
+            aname = attrs.get("attribute")
+            if not aname:
+                self.doSchemaError(
+                    "container attribute must be specified when using"
+                    " '*' or '+' for section names")
+            return s, (), _identifier(aname)
+
+        for s in s.split("|"):
+            s = s.strip()
+            if not s:
+                self.doSchemaError("empty section name not allowed")
+            if s in ("*", "+"):
+                self.doSchemaError(
+                    "'+' and '*' cannot be combined with other names")
+            else:
+                s = nametype.convert(s)
+                if s in ("*", "+"):
+                    self.doSchemaError("nametypes may not convert to"
+                                       " '*' or '+'")
+                names.append(s)
+
+        if attrs.has_key("attribute"):
+            if len(names) > 1:
+                self.doSchemaError(
+                    "cannot give target attribute name with"
+                    " multiple named sections")
+            aname = _identifier(attrs["attribute"])
+        else:
+            aname = None
+
+        return None, tuple(names), aname
 
     def doSchemaError(self, message):
         raise ZConfig.ConfigurationError(message)


=== Packages/ZConfig/SectionMatcher.py 1.1.2.2 => 1.1.2.3 ===
--- Packages/ZConfig/SectionMatcher.py:1.1.2.2	Mon Dec  9 12:58:12 2002
+++ Packages/ZConfig/SectionMatcher.py	Mon Dec  9 17:51:20 2002
@@ -60,6 +60,7 @@
         for i in range(len(keys)):
             name = keys[i]
             ci = self.info.getinfo(name)
+            keys[i] = ci.attribute
             if self._values.has_key(name):
                 L = self._values[key]
             elif ci.ismulti():