[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