[Zope-Checkins] CVS: Packages/ZConfig - datatypes.py:1.1.2.12 loader.py:1.1.2.13 matcher.py:1.1.2.21 schema.py:1.1.2.16

Fred L. Drake, Jr. fred@zope.com
Fri, 13 Dec 2002 15:38:59 -0500


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

Modified Files:
      Tag: zconfig-schema-devel-branch
	datatypes.py loader.py matcher.py schema.py 
Log Message:
Several changes:
- ZConfig.loader.SchemaLoader takes an optional datatype registry,
  allowing it to be given a pre-loaded or app-specific package of
  types.
- ZConfig.datatypes acts as a standard type registry, though it
  provides the default implementation.
- Don't call handler functions as the configuration object is built
  up; save them up and allow the application decide when to call
  them.  *** This changes the return values from the .loadURL() and
  .loadFile() methods of SchemaLoader. ***
- ZConfig.schema.SchemaParser only uses types looked up from the
  provided type registry; it provides no default implementations.


=== Packages/ZConfig/datatypes.py 1.1.2.11 => 1.1.2.12 ===
--- Packages/ZConfig/datatypes.py:1.1.2.11	Fri Dec 13 15:15:02 2002
+++ Packages/ZConfig/datatypes.py	Fri Dec 13 15:38:57 2002
@@ -202,8 +202,3 @@
                 package = __import__(n, g, g, component)
         self._other[name] = package
         return package
-
-
-_r = Registry()
-get = _r.get
-register = _r.register


=== Packages/ZConfig/loader.py 1.1.2.12 => 1.1.2.13 ===
--- Packages/ZConfig/loader.py:1.1.2.12	Fri Dec 13 10:16:57 2002
+++ Packages/ZConfig/loader.py	Fri Dec 13 15:38:57 2002
@@ -20,6 +20,7 @@
 
 import ZConfig
 
+from ZConfig import datatypes
 from ZConfig import matcher
 
 try:
@@ -79,6 +80,12 @@
 class SchemaLoader(BaseLoader):
     _fragment = None
 
+    def __init__(self, registry=None):
+        if registry is None:
+            registry = datatypes.Registry()
+        self.registry = registry
+        BaseLoader.__init__(self)
+
     def normalizeURL(self, url):
         if url:
             url, self._fragment = urlparse.urldefrag(url)
@@ -86,7 +93,7 @@
 
     def loadResource(self, resource):
         from ZConfig.schema import SchemaParser
-        parser = SchemaParser()
+        parser = SchemaParser(self.registry)
         schema = parser.parseStream(resource.file)
         if self._fragment:
             schema = schema.gettype(self._fragment)
@@ -99,9 +106,10 @@
         self.schema = schema
 
     def loadResource(self, resource):
-        sm = matcher.SchemaMatcher(self.schema)
+        self.handlers = []
+        sm = matcher.SchemaMatcher(self.schema, self.handlers)
         self._parse_resource(sm, resource)
-        return sm.finish()
+        return sm.finish(), CompositeHandler(self.handlers)
 
     # parser support API
 
@@ -116,7 +124,8 @@
             raise ZConfig.ConfigurationError(
                 "%s is not an allowed name for %s sections"
                 % (`name`, `ci.sectiontype.name`))
-        return matcher.SectionMatcher(ci, self.schema.gettype(type), name)
+        return matcher.SectionMatcher(ci, self.schema.gettype(type), name,
+                                      self.handlers)
 
     def endSection(self, parent, type, name, delegatename, matcher):
         assert not delegatename
@@ -133,6 +142,18 @@
         from ZConfig.cfgparser import ZConfigParser
         parser = ZConfigParser(resource, self)
         parser.parse(matcher)
+
+
+class CompositeHandler:
+    def __init__(self, handlers):
+        self._handlers = handlers
+
+    def __call__(self):
+        for handler, value in self._handlers:
+            handler(value)
+
+    def __len__(self):
+        return len(self._handlers)
 
 
 class Resource:


=== Packages/ZConfig/matcher.py 1.1.2.20 => 1.1.2.21 ===
--- Packages/ZConfig/matcher.py:1.1.2.20	Fri Dec 13 13:50:34 2002
+++ Packages/ZConfig/matcher.py	Fri Dec 13 15:38:57 2002
@@ -19,11 +19,14 @@
 
 
 class BaseMatcher:
-    def __init__(self, info, type):
+    def __init__(self, info, type, handlers):
         self.info = info
         self.type = type
         self._values = [None] * len(type)
         self._sectionnames = {}
+        if handlers is None:
+            handlers = []
+        self._handlers = handlers
 
     def __repr__(self):
         clsname = self.__class__.__name__
@@ -139,7 +142,7 @@
         # XXX  sibling SectionValue instances have been created and
         # XXX  we're ready to construct the parent.
         if self.info.handler is not None:
-            self.info.handler(v)
+            self._handlers.append((self.info.handler, v))
         return v
 
     def createValue(self, attrnames):
@@ -147,21 +150,21 @@
 
 
 class SectionMatcher(BaseMatcher):
-    def __init__(self, info, type, name):
+    def __init__(self, info, type, name, handlers):
         if name or info.allowUnnamed():
             self.name = name
         else:
             raise ZConfig.ConfigurationError(
                 `type.name` + " sections may not be unnamed")
-        BaseMatcher.__init__(self, info, type)
+        BaseMatcher.__init__(self, info, type, handlers)
 
     def createValue(self, attrnames):
         return SectionValue(attrnames, self._values, self.name, self.type)
 
 
 class SchemaMatcher(BaseMatcher):
-    def __init__(self, info):
-        BaseMatcher.__init__(self, info, info)
+    def __init__(self, info, handlers=None):
+        BaseMatcher.__init__(self, info, info, handlers)
 
     def finish(self):
         # Since there's no outer container to call datatype()


=== Packages/ZConfig/schema.py 1.1.2.15 => 1.1.2.16 ===
--- Packages/ZConfig/schema.py:1.1.2.15	Fri Dec 13 12:28:11 2002
+++ Packages/ZConfig/schema.py	Fri Dec 13 15:38:57 2002
@@ -17,7 +17,6 @@
 
 import ZConfig
 
-from ZConfig import datatypes
 from ZConfig import info
 
 
@@ -31,22 +30,14 @@
         return d
 
 
-default_value_type = datatypes.get("str")
-default_key_type = datatypes.get("basic-key")
-default_name_type = default_key_type
-
-def default_section_type(value):
-    return value
-
-_identifier = datatypes.get("identifier")
-
-
 class SchemaParser(xml.sax.ContentHandler):
 
     _cdata_tags = "description", "metadefault", "example", "default"
     _handled_tags = "schema", "key", "section", "sectiongroup", "sectiontype"
 
-    def __init__(self):
+    def __init__(self, registry):
+        self._registry = registry
+        self._identifier = registry.get("identifier")
         self._cdata = None
         self._locator = None
         self._prefixes = []
@@ -120,17 +111,17 @@
             self.doSchemaError("prefix may not begin with '.'")
         self._prefixes.append(prefix)
 
-    def get_datatype(self, attrs, key, default):
-        if attrs.has_key(key):
-            dtname = self.get_classname(attrs[key])
-            return datatypes.get(dtname)
+    def get_datatype(self, attrs, attrkey, default):
+        if attrs.has_key(attrkey):
+            dtname = self.get_classname(attrs[attrkey])
+            return self._registry.get(dtname)
         else:
-            return default
+            return self._registry.get(default)
 
     def get_sect_typeinfo(self, attrs):
-        keytype = self.get_datatype(attrs, "keytype", default_key_type)
-        valuetype = self.get_datatype(attrs, "valuetype", default_value_type)
-        datatype = self.get_datatype(attrs, "datatype", default_section_type)
+        keytype = self.get_datatype(attrs, "keytype", "basic-key")
+        valuetype = self.get_datatype(attrs, "valuetype", "str")
+        datatype = self.get_datatype(attrs, "datatype", "null")
         return keytype, valuetype, datatype
 
     def start_schema(self, attrs):
@@ -149,7 +140,7 @@
         if not name:
             self.doSchemaError(
                 "sectiontype name must not be omitted or empty")
-        name = _identifier(name)
+        name = self._identifier(name)
         keytype, valuetype, datatype = self.get_sect_typeinfo(attrs)
         sectinfo = info.SectionType(name, keytype, valuetype, datatype)
         self._schema.addtype(sectinfo)
@@ -197,13 +188,13 @@
             self.doSchemaError("key name may not be omitted or empty")
         # run the keytype converter to make sure this is a valid key
         name = self._stack[-1].keytype(name)
-        datatype = datatypes.get(attrs.get("datatype"))
+        datatype = self._registry.get(attrs.get("datatype"))
         maxOccurs, minOccurs, handler = self.get_common_info(attrs)
         attribute = attrs.get("attribute")
         if attribute:
-            attribute = _identifier(attribute)
+            attribute = self._identifier(attribute)
         else:
-            attribute = _identifier(name.replace("-", "_"))
+            attribute = self._identifier(name.replace("-", "_"))
         key = info.KeyInfo(name, datatype, minOccurs, maxOccurs, handler,
                            attribute)
         self._stack[-1].addkey(key)
@@ -239,7 +230,7 @@
             self.doSchemaError("section name must be specified and non-empty")
         aname = attrs.get("attribute")
         if aname:
-            aname = _identifier(aname)
+            aname = self._identifier(aname)
         if name in ("*", "+"):
             if not aname:
                 self.doSchemaError(
@@ -247,7 +238,7 @@
                     " when using '*' or '+' for a section name")
             return name, None, aname
         else:
-            return None, _identifier(name), aname
+            return None, self._identifier(name), aname
 
     def doSchemaError(self, message):
         raise ZConfig.ConfigurationError(message)