[Zope3-checkins] CVS: Packages/ZConfig - info.py:1.1.2.4 matcher.py:1.1.2.5 schema.py:1.1.2.3

Fred L. Drake, Jr. fred@zope.com
Wed, 11 Dec 2002 01:10:37 -0500


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

Modified Files:
      Tag: zconfig-schema-devel-branch
	info.py matcher.py schema.py 
Log Message:
Basic nested sections work!  Not very clean, but working.
Needs refactoring/cleanup, lots of unit tests.


=== Packages/ZConfig/info.py 1.1.2.3 => 1.1.2.4 ===
--- Packages/ZConfig/info.py:1.1.2.3	Tue Dec 10 18:25:01 2002
+++ Packages/ZConfig/info.py	Wed Dec 11 01:10:36 2002
@@ -106,51 +106,75 @@
         assert keytype is not None
         self.typename = typename
         self.keytype = keytype
-        self.names = names   # '*', '+', or [name1, ...]
+        self.names = names     # '*', '+', or [name1, ...]
         self.nametype = nametype
-        self._children = []  # [(name, info), ...]
-        self._attrmap = {}   # {attribute: index, ...}
+        self._children = []    # [info, ...]
+        self._attrmap = {}     # {attribute: index, ...}
+        self._keymap = {}      # {key: index, ...}
+        self._secttypemap = {} # {section type: info, ...}
+        if datatype is None:
+            datatype = _null_conversion
         KeyInfo.__init__(self, None, datatype, minOccurs, maxOccurs,
                          handler, attribute)
 
-    def _add_child(self, name, 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 __len__(self):
+        return len(self._children)
+
+    def __getitem__(self, index):
+        return self._children[index]
+
+    def _add_child(self, key, info):
+        # check naming constraints
+        assert key or info.attribute
+        if key and self._keymap.has_key(key):
+            raise ValueError("child name %s already used" % key)
+        if info.attribute and self._attrmap.has_key(info.attribute):
+            raise ValueError("child attribute name %s already used"
+                             % info.attribute)
+        # a-ok, add the item to the appropriate maps
+        if info.attribute:
+            self._attrmap[info.attribute] = len(self._children)
+        if key:
+            self._keymap[key] = len(self._children)
+        self._children.append((key, info))
 
     def addkey(self, keyinfo):
         self._add_child(keyinfo.name, keyinfo)
 
     def addsection(self, name, sectinfo):
         assert name not in ("*", "+")
+        # Check that this isn't a different definition of the section type,
+        # since once _add_child() returns we must succeed, or undo a whole
+        # bunch of stuff.  This is the easier alternative.  ;-)
+        oldinfo = self._secttypemap.get(sectinfo.typename)
+        if oldinfo not in (None, sectinfo):
+            raise ZConfig.ConfigurationError(
+                "duplicate definition of section type " + `name`)
         self._add_child(name, sectinfo)
+        self._secttypemap[sectinfo.typename] = sectinfo
 
-    def getinfo(self, name):
-        if not name:
+    def getinfo(self, key):
+        if not key:
             raise ZConfig.ConfigurationError(
                 "cannot match a key without a name")
-        for n, info in self._children:
-            if n == name:
-                return info
-        raise ZConfig.ConfigurationError("no key matching " + `name`)
+        index = self._keymap.get(key)
+        if index is None:
+            raise ZConfig.ConfigurationError("no key matching " + `key`)
+        else:
+            return self._children[index][1]
 
     def getchildnames(self):
-        return [n for (n,info) in self._children]
+        return [key for (key, info) in self._children]
 
     def getsectionindex(self, type, name):
         index = -1
-        for n, info in self._children:
+        for key, info in self._children:
             index += 1
-            if n:
-                if n == name:
+            if key:
+                if key == name:
                     if not info.issection():
                         raise ZConfig.ConfigurationError(
-                            "section name %s already in use for key"
-                            % str(n))
+                            "section name %s already in use for key" % key)
                     if not info.typename == type:
                         raise ZConfig.ConfigurationError(
                             "name %s must be used for a %s section"
@@ -194,3 +218,10 @@
 
     def isAllowedName(self, name):
         return False
+
+
+class NullConversion:
+    def convert(self, value):
+        return value
+
+_null_conversion = NullConversion()


=== Packages/ZConfig/matcher.py 1.1.2.4 => 1.1.2.5 ===
--- Packages/ZConfig/matcher.py:1.1.2.4	Tue Dec 10 18:25:01 2002
+++ Packages/ZConfig/matcher.py	Wed Dec 11 01:10:36 2002
@@ -19,68 +19,85 @@
             raise ZConfig.ConfigurationError(
                 `info.name` + " sections may not be unnamed")
         self.info = info
-        self._values = {}
+        self._values = [None] * len(info)
 
     def addSection(self, type, name, sectvalue):
         i = self.info.getsectionindex(type, name)
-        raise NotImpementedError("still working on this...")
+        ci = self.info.getsectioninfo(type, name)
+        v = self._values[i]
+        if v is None and ci.ismulti():
+            v = [sectvalue]
+            self._values[i] = v
+        elif ci.ismulti():
+            v.append(sectvalue)
+        else:
+            self._values[i] = sectvalue
 
     def addValue(self, key, value):
-        keyinfo = self.info.getinfo(key)
-        if keyinfo.issection():
-            if keyinfo.name:
+        length = len(self.info)
+        for i in range(length):
+            k, ci = self.info[i]
+            if k == key:
+                break
+        else:
+            raise ZConfig.ConfigurationError(
+                `key` + " is not a known key name")
+        if ci.issection():
+            if ci.name:
                 extra = " in %s sections" % `self.info.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`)
+
+        v = self._values[i]
+        if v is None:
+            if ci.ismulti():
+                v = []
+                self._values[i] = v
+        elif not ci.ismulti():
+            raise ZConfig.ConfigurationError(
+                `key` + " does not support multiple values")
+        elif len(v) == ci.maxOccurs:
+            raise ZConfig.ConfigurationError(
+                "too many values for " + `name`)
+
+        if ci.ismulti():
+            v.append(value)
         else:
-            L.append(value)
-        self._values[key] = L
+            self._values[i] = value
 
     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()
-        return self.constuct()
-
-    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)
+        length = len(self.info)
+        values = [None] * length
+        keys = [None] * length
+        for i in range(length):
+            key, ci = self.info[i]
             keys[i] = ci.attribute
-            if self._values.has_key(name):
-                L = self._values[name]
-            elif ci.ismulti():
-                L = ci.getdefault()
-            else:
-                L = [ci.getdefault()]
+            if ci.ismulti() and len(self._values[i]) < ci.minOccurs:
+                raise ZConfig.ConfigurationError(
+                    "not enough values for %s; %d found, %d required"
+                    % (`key`, len(L), ci.minOccurs))
+            v = self._values[i]
+            if v is None:
+                if ci.ismulti():
+                    v = ci.getdefault()[:]
+                else:
+                    v = ci.getdefault()
+                self._values[i] = v
+        return self.constuct(keys, values)
+
+    def constuct(self, keys, values):
+        length = len(self.info)
+        for i in range(length):
+            name, ci = self.info[i]
+            dt = ci.datatype
             if ci.ismulti():
-                values[i] = [ci.datatype.convert(s) for s in L]
-            elif ci.issection() and ci.datatype is None:
-                values[i] = L[0]
+                values[i] = [dt.convert(s) for s in self._values[i]]
             else:
-                assert len(L) == 1
-                values[i] = ci.datatype.convert(L[0])
+                values[i] = dt.convert(self._values[i])
         v = SectionValue(keys, values)
         # XXX  Really should delay this until after all the
         # XXX  sibling SectionValue instances have been created and


=== Packages/ZConfig/schema.py 1.1.2.2 => 1.1.2.3 ===
--- Packages/ZConfig/schema.py:1.1.2.2	Tue Dec 10 18:25:01 2002
+++ Packages/ZConfig/schema.py	Wed Dec 11 01:10:36 2002
@@ -40,15 +40,15 @@
     def startElement(self, name, attrs):
         attrs = dict(attrs)
         if name == "schema":
-            if self._schema:
+            if self._schema is not None:
                 self.doSchemaError("schema element improperly nested")
             self.start_schema(attrs)
         elif name in self._handled_tags:
-            if not self._schema:
+            if self._schema is None:
                 self.doSchemaError(name + " element outside of schema")
             getattr(self, "start_" + name)(attrs)
         elif name in self._cdata_tags:
-            if not self._schema:
+            if self._schema is None:
                 self.doSchemaError(name + " element outside of schema")
             if self._cdata is not None:
                 self.doSchemaError(name + " element improperly nested")