[Zope-Checkins] CVS: Zope3/src/ZConfig - cfgparser.py:1.9 info.py:1.19 loader.py:1.23 schema.py:1.25

Fred L. Drake, Jr. fred at zope.com
Fri Oct 3 16:02:27 EDT 2003


Update of /cvs-repository/Zope3/src/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv2255

Modified Files:
	cfgparser.py info.py loader.py schema.py 
Log Message:
Implementation and tests for %import keyword in the configuration language.
This allows specific configurations to load new implementations of existing
abstract types without having to modify the basic schema.
We expect this to be useful to support (for example) add-on storage and
database types, logging handlers, or even server components.


=== Zope3/src/ZConfig/cfgparser.py 1.8 => 1.9 ===
--- Zope3/src/ZConfig/cfgparser.py:1.8	Fri Aug  1 16:41:59 2003
+++ Zope3/src/ZConfig/cfgparser.py	Fri Oct  3 16:01:56 2003
@@ -139,7 +139,7 @@
         if not m:
             self.error("missing or unrecognized directive")
         name, arg = m.group('key', 'value')
-        if name not in ("define", "include"):
+        if name not in ("define", "import", "include"):
             self.error("unknown directive: " + `name`)
         if not arg:
             self.error("missing argument to %%%s directive" % name)
@@ -147,10 +147,17 @@
             self.handle_include(section, arg)
         elif name == "define":
             self.handle_define(section, arg)
+        elif name == "import":
+            self.handle_import(section, arg)
         else:
             assert 0, "unexpected directive for " + `"%" + rest`
 
+    def handle_import(self, section, rest):
+        pkgname = self.replace(rest.strip())
+        self.context.importSchemaComponent(pkgname)
+
     def handle_include(self, section, rest):
+        rest = self.replace(rest.strip())
         newurl = ZConfig.url.urljoin(self.url, rest)
         self.context.includeConfiguration(section, newurl, self.defs)
 


=== Zope3/src/ZConfig/info.py 1.18 => 1.19 ===
--- Zope3/src/ZConfig/info.py:1.18	Thu Oct  2 16:41:43 2003
+++ Zope3/src/ZConfig/info.py	Fri Oct  3 16:01:56 2003
@@ -368,6 +368,7 @@
                  registry):
         SectionType.__init__(self, None, keytype, valuetype, datatype,
                              registry, {})
+        self._components = {}
         self.handler = handler
         self.url = url
 
@@ -411,3 +412,23 @@
         t._keymap.update(base._keymap)
         t._children.extend(base._children)
         return t
+
+    def addComponent(self, name):
+        if self._components.has_key(name):
+            raise ZConfig.SchemaError("already have component %s" % name)
+        self._components[name] = name
+
+    def hasComponent(self, name):
+        return self._components.has_key(name)
+
+
+def createDerivedSchema(base):
+    new = SchemaType(base.keytype, base.valuetype, base.datatype,
+                     base.handler, base.url, base.registry)
+    new._components.update(base._components)
+    new.description = base.description
+    new._children[:] = base._children
+    new._attrmap.update(base._attrmap)
+    new._keymap.update(base._keymap)
+    new._types.update(base._types)
+    return new


=== Zope3/src/ZConfig/loader.py 1.22 => 1.23 ===
--- Zope3/src/ZConfig/loader.py:1.22	Fri Oct  3 12:32:10 2003
+++ Zope3/src/ZConfig/loader.py	Fri Oct  3 16:01:56 2003
@@ -21,6 +21,7 @@
 import ZConfig
 import ZConfig.cfgparser
 import ZConfig.datatypes
+import ZConfig.info
 import ZConfig.matcher
 import ZConfig.schema
 import ZConfig.url
@@ -133,8 +134,7 @@
         if resource.url and self._cache.has_key(resource.url):
             schema = self._cache[resource.url]
         else:
-            schema = ZConfig.schema.parseResource(resource,
-                                                  self.registry, self)
+            schema = ZConfig.schema.parseResource(resource, self)
             self._cache[resource.url] = schema
         return schema
 
@@ -145,12 +145,16 @@
         if not parts:
             raise ZConfig.SchemaError(
                 "illegal schema component name: " + `package`)
-        if len(filter(None, parts)) != len(parts):
+        if "" in parts:
             # '' somewhere in the package spec; still illegal
             raise ZConfig.SchemaError(
                 "illegal schema component name: " + `package`)
         file = file or "component.xml"
-        __import__(package)
+        try:
+            __import__(package)
+        except ImportError, e:
+            raise ZConfig.SchemaError("could not load package %s: %s"
+                                      % (package, str(e)))
         pkg = sys.modules[package]
         if not hasattr(pkg, "__path__"):
             raise ZConfig.SchemaError(
@@ -172,6 +176,7 @@
                 "cannot check a configuration an abstract type")
         BaseLoader.__init__(self)
         self.schema = schema
+        self._private_schema = False
 
     def loadResource(self, resource):
         sm = self.createSchemaMatcher()
@@ -199,6 +204,24 @@
         assert not delegatename
         sectvalue = matcher.finish()
         parent.addSection(type, name, sectvalue)
+
+    def importSchemaComponent(self, pkgname):
+        schema = self.schema
+        if schema.hasComponent(pkgname):
+            return
+        if not self._private_schema:
+            # replace the schema with an extended schema on the first %import
+            self._loader = SchemaLoader(self.schema.registry)
+            schema = ZConfig.info.createDerivedSchema(self.schema)
+            self._private_schema = True
+            self.schema = schema
+        url = self._loader.schemaComponentSource(pkgname, '')
+        resource = self.openResource(url)
+        schema.addComponent(pkgname)
+        try:
+            ZConfig.schema.parseComponent(resource, self._loader, schema)
+        finally:
+            resource.close()
 
     def includeConfiguration(self, section, url, defines):
         url = self.normalizeURL(url)


=== Zope3/src/ZConfig/schema.py 1.24 => 1.25 ===
--- Zope3/src/ZConfig/schema.py:1.24	Thu Sep 25 10:59:09 2003
+++ Zope3/src/ZConfig/schema.py	Fri Oct  3 16:01:56 2003
@@ -38,12 +38,17 @@
         return d
 
 
-def parseResource(resource, registry, loader):
-    parser = SchemaParser(registry, loader, resource.url)
+def parseResource(resource, loader):
+    parser = SchemaParser(loader, resource.url)
     xml.sax.parse(resource.file, parser)
     return parser._schema
 
 
+def parseComponent(resource, loader, schema):
+    parser = ComponentParser(loader, resource.url, schema)
+    xml.sax.parse(resource.file, parser)
+
+
 def _srepr(ob):
     if isinstance(ob, type(u'')):
         # drop the leading "u" from a unicode repr
@@ -74,18 +79,17 @@
         "multisection": ["schema", "sectiontype"],
         }
 
-    def __init__(self, registry, loader, url):
-        self._registry = registry
+    def __init__(self, loader, url):
+        self._registry = loader.registry
         self._loader = loader
-        self._basic_key = registry.get("basic-key")
-        self._identifier = registry.get("identifier")
+        self._basic_key = self._registry.get("basic-key")
+        self._identifier = self._registry.get("identifier")
         self._cdata = None
         self._locator = None
         self._prefixes = []
         self._schema = None
         self._stack = []
         self._url = url
-        self._components = {}
         self._elem_stack = []
 
     # SAX 2 ContentHandler methods
@@ -299,16 +303,14 @@
         else:
             if os.path.dirname(file):
                 self.error("file may not include a directory part")
-            src = self._loader.schemaComponentSource(pkg, file)
-            if not self._components.has_key(src):
-                self._components[pkg] = src
+            if not self._schema.hasComponent(pkg):
+                src = self._loader.schemaComponentSource(pkg, file)
+                self._schema.addComponent(pkg)
                 self.loadComponent(src)
 
     def loadComponent(self, src):
         r = self._loader.openResource(src)
-        parser = ComponentParser(self._registry, self._loader, src,
-                                 self._schema)
-        parser._components = self._components
+        parser = ComponentParser(self._loader, src, self._schema)
         try:
             xml.sax.parse(r.file, parser)
         finally:
@@ -475,8 +477,8 @@
     _handled_tags = BaseParser._handled_tags + ("component",)
     _top_level = "component"
 
-    def __init__(self, registry, loader, url, schema):
-        BaseParser.__init__(self, registry, loader, url)
+    def __init__(self, loader, url, schema):
+        BaseParser.__init__(self, loader, url)
         self._parent = schema
 
     def characters_description(self, data):




More information about the Zope-Checkins mailing list