[Zope-Checkins] CVS: Packages/ZConfig - loader.py:1.6 schema.py:1.9
Fred L. Drake, Jr.
fred@zope.com
Tue, 7 Jan 2003 15:03:12 -0500
Update of /cvs-repository/Packages/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv29089
Modified Files:
loader.py schema.py
Log Message:
Re-implement the extensible schema components mechanism (almost) completely.
This version is more sensible.
=== Packages/ZConfig/loader.py 1.5 => 1.6 ===
--- Packages/ZConfig/loader.py:1.5 Tue Jan 7 02:09:04 2003
+++ Packages/ZConfig/loader.py Tue Jan 7 15:02:35 2003
@@ -141,7 +141,7 @@
# schema parser support API
- def schemaPackageURLs(self, package):
+ def schemaPackageInfo(self, package):
parts = package.split(".")
if not parts:
raise ZConfig.SchemaError(
@@ -151,18 +151,19 @@
raise ZConfig.SchemaError(
"illegal schema component name: " + `package`)
dirname = os.path.join(self._library, *parts)
- fn = os.path.join(dirname, "schema.xml")
+ fn = os.path.join(dirname, "component.xml")
if not os.path.exists(fn):
raise ZConfig.SchemaError(
"schema component not found: " + `package`)
- urls = [fn]
+ url = "file://" + urllib.pathname2url(fn)
+ extensions = []
for fn in os.listdir(dirname):
- if fn == "schema.xml":
+ if fn == "component.xml":
continue
- path = os.path.join(dirname, fn, "schema.xml")
+ path = os.path.join(dirname, fn, "extension.xml")
if os.path.exists(path):
- urls.append(path)
- return urls
+ extensions.append("file://" + urllib.pathname2url(path))
+ return url, extensions
class ConfigLoader(BaseLoader):
=== Packages/ZConfig/schema.py 1.8 => 1.9 ===
--- Packages/ZConfig/schema.py:1.8 Tue Jan 7 13:31:03 2003
+++ Packages/ZConfig/schema.py Tue Jan 7 15:02:35 2003
@@ -62,6 +62,7 @@
self._stack = []
self._group = None
self._url = url
+ self._components = {}
# SAX 2 ContentHandler methods
@@ -250,15 +251,35 @@
src, fragment = url.urldefrag(src)
if fragment:
self.error("import src many not include a fragment identifier")
- urls = [src]
- else:
- urls = self._loader.schemaPackageURLs(pkg)
- if not urls:
- self.error("could not locate schema component " + `pkg`)
- for s in urls:
- schema = self._loader.loadURL(s)
+ schema = self._loader.loadURL(src)
for n in schema.gettypenames():
self._schema.addtype(schema.gettype(n))
+ elif self._components.has_key(pkg):
+ # already loaded, or in progress
+ pass
+ else:
+ pi = self._loader.schemaPackageInfo(pkg)
+ if not pi:
+ self.error("could not locate schema component " + `pkg`)
+ self._components[pkg] = pi
+ self.loadComponent(pi)
+
+ def loadComponent(self, info):
+ base, extensions = info
+ r = self._loader.openResource(base)
+ parser = ComponentParser(self._registry, self._loader, base,
+ self._schema)
+ parser._components = self._components
+ try:
+ xml.sax.parse(r.file, parser)
+ finally:
+ r.close()
+ for ext in extensions:
+ r = self._loader.openResource(ext)
+ try:
+ parser.loadExtension(r)
+ finally:
+ r.close()
def end_import(self):
pass
@@ -272,9 +293,9 @@
keytype, valuetype, datatype = self.get_sect_typeinfo(attrs)
if attrs.has_key("extends"):
basename = self.basic_key(attrs["extends"])
- if basename == name:
- self.error("sectiontype cannot extend itself")
base = self._schema.gettype(basename)
+ if not self._localtypes.has_key(basename):
+ self.error("cannot extend type derived outside component")
if base.istypegroup():
self.error("sectiontype cannot extend an abstract type")
if attrs.has_key("keytype"):
@@ -421,6 +442,7 @@
name = self.basic_key(name)
self._schema = info.SchemaType(name, keytype, valuetype, datatype,
handler, self._url, self._registry)
+ self._localtypes = self._schema._types
if name is not None:
# XXX circular reference
self._schema.addtype(self._schema)
@@ -431,3 +453,80 @@
assert not self._stack
self.pop_prefix()
assert not self._prefixes
+
+
+
+class BaseComponentParser(BaseParser):
+
+ def __init__(self, registry, loader, url, localtypes):
+ self._localtypes = localtypes
+ BaseParser.__init__(self, registry, loader, url)
+
+ def characters_description(self, data):
+ if self._stack:
+ self._stack[-1].description = data
+
+ def start_key(self, attrs):
+ if not self._stack:
+ self.error(
+ "cannot define top-level keys in a schema " + self._top_level)
+ BaseParser.start_key(self, attrs)
+
+ def start_multikey(self, attrs):
+ if not self._stack:
+ self.error(
+ "cannot define top-level multikeys in a schema "
+ + self._top_level)
+ BaseParser.start_multikey(self, attrs)
+
+ def start_section(self, attrs):
+ if not self._stack:
+ self.error(
+ "cannot define top-level sections in a schema "
+ + self._top_level)
+ BaseParser.start_section(self, attrs)
+
+ def start_multisection(self, attrs):
+ if not self._stack:
+ self.error(
+ "cannot define top-level multisections in a schema "
+ + self._top_level)
+ BaseParser.start_multisection(self, attrs)
+
+
+class ComponentParser(BaseComponentParser):
+
+ _handled_tags = BaseComponentParser._handled_tags + ("component",)
+ _top_level = "component"
+
+ def __init__(self, registry, loader, url, schema):
+ BaseComponentParser.__init__(self, registry, loader, url, {})
+ self._parent = schema
+
+ def start_component(self, attrs):
+ self._schema = self._parent
+
+ def end_component(self):
+ pass
+
+ def loadExtension(self, resource):
+ parser = ExtensionParser(self._registry, self._loader, resource.url,
+ self._parent, self._localtypes)
+ parser._components = self._components
+ xml.sax.parse(resource.file, parser)
+
+
+class ExtensionParser(BaseComponentParser):
+
+ _handled_tags = BaseComponentParser._handled_tags + ("extension",)
+ _top_level = "extension"
+
+ def __init__(self, registry, loader, url, schema, localtypes):
+ BaseComponentParser.__init__(self, registry, loader, url, localtypes)
+ self._parent = schema
+
+ def start_extension(self, attrs):
+ self._schema = self._parent
+
+ def end_extension(self):
+ pass