[Zope-Checkins] CVS: ZODB3/ZConfig - schema.py:1.24.6.1 loader.py:1.21.6.1 info.py:1.18.2.1 datatypes.py:1.15.28.1 cfgparser.py:1.8.20.1 Context.py:NONE Config.py:NONE

Jeremy Hylton jeremy at zope.com
Tue Dec 23 14:06:39 EST 2003


Update of /cvs-repository/ZODB3/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv26665/ZConfig

Modified Files:
      Tag: ZODB3-mvcc-2-branch
	schema.py loader.py info.py datatypes.py cfgparser.py 
Removed Files:
      Tag: ZODB3-mvcc-2-branch
	Context.py Config.py 
Log Message:
Merge the head to the mvcc branch.

This merge should be the final preparation for merging the branch to
the trunk.


=== ZODB3/ZConfig/schema.py 1.24 => 1.24.6.1 ===
--- ZODB3/ZConfig/schema.py:1.24	Thu Sep 25 10:59:09 2003
+++ ZODB3/ZConfig/schema.py	Tue Dec 23 14:06:04 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
@@ -300,15 +304,13 @@
             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(src):
+                self._schema.addComponent(src)
                 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:
@@ -455,14 +457,76 @@
     _handled_tags = BaseParser._handled_tags + ("schema",)
     _top_level = "schema"
 
+    def __init__(self, loader, url, extending_parser=None):
+        BaseParser.__init__(self, loader, url)
+        self._extending_parser = extending_parser
+        self._base_keytypes = []
+        self._base_datatypes = []
+
     def start_schema(self, attrs):
         self.push_prefix(attrs)
         handler = self.get_handler(attrs)
         keytype, valuetype, datatype = self.get_sect_typeinfo(attrs)
-        self._schema = info.SchemaType(keytype, valuetype, datatype,
-                                       handler, self._url, self._registry)
+
+        if self._extending_parser is None:
+            # We're not being inherited, so we need to create the schema
+            self._schema = info.SchemaType(keytype, valuetype, datatype,
+                                           handler, self._url, self._registry)
+        else:
+            # Parse into the extending ("subclass") parser's schema
+            self._schema = self._extending_parser._schema
+
         self._stack = [self._schema]
 
+        if attrs.has_key("extends"):
+            sources = attrs["extends"].split()
+            sources.reverse()
+
+            for src in sources:
+                src = url.urljoin(self._url, src)
+                src, fragment = url.urldefrag(src)
+                if fragment:
+                    self.error("schema extends many not include"
+                               " a fragment identifier")
+                self.extendSchema(src)
+
+            # Inherit keytype from bases, if unspecified and not conflicting
+            if self._base_keytypes and not attrs.has_key("keytype"):
+                keytype = self._base_keytypes[0]
+                for kt in self._base_keytypes[1:]:
+                    if kt is not keytype:
+                        self.error("base schemas have conflicting keytypes,"
+                                   " but no keytype was specified in the"
+                                   " extending schema")
+
+            # Inherit datatype from bases, if unspecified and not conflicting
+            if self._base_datatypes and not attrs.has_key("datatype"):
+                datatype = self._base_datatypes[0]
+                for dt in self._base_datatypes[1:]:
+                    if dt is not datatype:
+                        self.error("base schemas have conflicting datatypes,"
+                                   " but no datatype was specified in the"
+                                   " extending schema")
+
+        # Reset the schema types to our own, while we parse the schema body
+        self._schema.keytype = keytype
+        self._schema.valuetype = valuetype
+        self._schema.datatype = datatype
+
+        # Update base key/datatypes for the "extending" parser
+        if self._extending_parser is not None:
+            self._extending_parser._base_keytypes.append(keytype)
+            self._extending_parser._base_datatypes.append(datatype)
+
+
+    def extendSchema(self,src):
+        parser = SchemaParser(self._loader, src, self)
+        r = self._loader.openResource(src)
+        try:
+            xml.sax.parse(r.file, parser)
+        finally:
+            r.close()
+
     def end_schema(self):
         del self._stack[-1]
         assert not self._stack
@@ -475,8 +539,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):


=== ZODB3/ZConfig/loader.py 1.21 => 1.21.6.1 ===
--- ZODB3/ZConfig/loader.py:1.21	Wed Sep 10 16:14:01 2003
+++ ZODB3/ZConfig/loader.py	Tue Dec 23 14:06:04 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
@@ -83,7 +84,7 @@
     # utilities
 
     def loadResource(self, resource):
-        raise NotImpementedError(
+        raise NotImplementedError(
             "BaseLoader.loadResource() must be overridden by a subclass")
 
     def openResource(self, 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,20 +145,28 @@
         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"
-        for dir in sys.path:
-            dirname = os.path.join(os.path.abspath(dir), *parts)
+        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(
+                "import name does not refer to a package: " + `package`)
+        for dir in pkg.__path__:
+            dirname = os.path.abspath(dir)
             fn = os.path.join(dirname, file)
             if os.path.exists(fn):
-                break
+                return "file://" + urllib.pathname2url(fn)
         else:
             raise ZConfig.SchemaError(
                 "schema component not found: " + `package`)
-        return "file://" + urllib.pathname2url(fn)
 
 
 class ConfigLoader(BaseLoader):
@@ -168,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()
@@ -180,10 +189,7 @@
 
     # config parser support API
 
-    def startSection(self, parent, type, name, delegatename):
-        if delegatename:
-            raise NotImpementedError(
-                "section delegation is not yet supported")
+    def startSection(self, parent, type, name):
         t = self.schema.gettype(type)
         if t.isabstract():
             raise ZConfig.ConfigurationError(
@@ -191,11 +197,28 @@
                 " found abstract type " + `type`)
         return parent.createChildMatcher(t, name)
 
-    def endSection(self, parent, type, name, delegatename, matcher):
-        assert not delegatename
+    def endSection(self, parent, type, name, matcher):
         sectvalue = matcher.finish()
         parent.addSection(type, name, sectvalue)
 
+    def importSchemaComponent(self, pkgname):
+        schema = self.schema
+        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, '')
+        if schema.hasComponent(url):
+            return
+        resource = self.openResource(url)
+        schema.addComponent(url)
+        try:
+            ZConfig.schema.parseComponent(resource, self._loader, schema)
+        finally:
+            resource.close()
+
     def includeConfiguration(self, section, url, defines):
         url = self.normalizeURL(url)
         r = self.openResource(url)
@@ -211,8 +234,7 @@
         parser.parse(matcher)
 
 
-class CompositeHandler:
-    __metatype__ = type
+class CompositeHandler(object):
     __slots__ = '_handlers', '_convert'
 
     def __init__(self, handlers, schema):


=== ZODB3/ZConfig/info.py 1.18 => 1.18.2.1 ===
--- ZODB3/ZConfig/info.py:1.18	Thu Oct  2 16:41:43 2003
+++ ZODB3/ZConfig/info.py	Tue Dec 23 14:06:04 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


=== ZODB3/ZConfig/datatypes.py 1.15 => 1.15.28.1 ===
--- ZODB3/ZConfig/datatypes.py:1.15	Fri Jul 11 10:44:40 2003
+++ ZODB3/ZConfig/datatypes.py	Tue Dec 23 14:06:04 2003
@@ -156,6 +156,8 @@
         try:
             port = port_number(s)
         except ValueError:
+            if len(s.split()) != 1:
+                raise ValueError("not a valid host name: " + repr(s))
             host = s.lower()
     return host, port
 
@@ -269,8 +271,7 @@
                                            }),
     }
 
-class Registry:
-    __metatype__ = type
+class Registry(object):
     __slots__ = '_stock', '_other', '_basic_key'
 
     def __init__(self, stock=None):


=== ZODB3/ZConfig/cfgparser.py 1.8 => 1.8.20.1 ===
--- ZODB3/ZConfig/cfgparser.py:1.8	Fri Aug  1 16:41:59 2003
+++ ZODB3/ZConfig/cfgparser.py	Tue Dec 23 14:06:04 2003
@@ -36,7 +36,7 @@
         self.file = resource.file
         self.url = resource.url
         self.lineno = 0
-        self.stack = []   # [(type, name, delegatename, prevmatcher), ...]
+        self.stack = []   # [(type, name, prevmatcher), ...]
         if defines is None:
             defines = {}
         self.defs = defines
@@ -89,33 +89,32 @@
         m = _section_start_rx.match(text)
         if not m:
             self.error("malformed section header")
-        type, name, delegatename = m.group('type', 'name', 'delegatename')
+        type, name = m.group('type', 'name')
         type = type.lower()
         if name:
             name = name.lower()
         try:
-            newsect = self.context.startSection(section, type, name,
-                                                delegatename)
+            newsect = self.context.startSection(section, type, name)
         except ZConfig.ConfigurationError, e:
             self.error(e[0])
 
         if isempty:
-            self.context.endSection(section, type, name, delegatename, newsect)
+            self.context.endSection(section, type, name, newsect)
             return section
         else:
-            self.stack.append((type, name, delegatename, section))
+            self.stack.append((type, name, section))
             return newsect
 
     def end_section(self, section, rest):
         if not self.stack:
             self.error("unexpected section end")
         type = rest.rstrip().lower()
-        opentype, name, delegatename, prevsection = self.stack.pop()
+        opentype, name, prevsection = self.stack.pop()
         if type != opentype:
             self.error("unbalanced section end")
         try:
             self.context.endSection(
-                prevsection, type, name, delegatename, section)
+                prevsection, type, name, section)
         except ZConfig.ConfigurationError, e:
             self.error(e[0])
         return prevsection
@@ -139,7 +138,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 +146,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)
 
@@ -179,15 +185,13 @@
 
 
 import re
-# _name_re cannot allow "(" or ")" since we need to be able to tell if
-# a section has a name or not: <section (name)> would be ambiguous if
-# parentheses were allowed in names.
+# _name_re does not allow "(" or ")" for historical reasons.  Though
+# the restriction could be lifted, there seems no need to do so.
 _name_re = r"[^\s()]+"
 _keyvalue_rx = re.compile(r"(?P<key>%s)\s*(?P<value>[^\s].*)?$"
                           % _name_re)
 _section_start_rx = re.compile(r"(?P<type>%s)"
                                r"(?:\s+(?P<name>%s))?"
-                               r"(?:\s*[(](?P<delegatename>%s)[)])?"
                                r"$"
-                               % (_name_re, _name_re, _name_re))
+                               % (_name_re, _name_re))
 del re

=== Removed File ZODB3/ZConfig/Context.py ===

=== Removed File ZODB3/ZConfig/Config.py ===




More information about the Zope-Checkins mailing list