[Zodb-checkins] CVS: Zope/lib/python/ZConfig - __init__.py:1.9.22.4
cfgparser.py:1.7.52.4 cmdline.py:1.1.44.1 info.py:1.15.12.4
loader.py:1.18.44.4 schema.py:1.20.22.4 Config.py:NONE
Context.py:NONE
Fred L. Drake, Jr.
fred at zope.com
Tue Oct 7 15:36:53 EDT 2003
Update of /cvs-repository/Zope/lib/python/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv6557
Modified Files:
Tag: Zope-2_7-branch
__init__.py cfgparser.py cmdline.py info.py loader.py
schema.py
Removed Files:
Tag: Zope-2_7-branch
Config.py Context.py
Log Message:
Merge the ZConfig trunk to Zope 2.7.
This adds support for two approaches to schema extension.
=== Zope/lib/python/ZConfig/__init__.py 1.9.22.3 => 1.9.22.4 ===
=== Zope/lib/python/ZConfig/cfgparser.py 1.7.52.3 => 1.7.52.4 ===
--- Zope/lib/python/ZConfig/cfgparser.py:1.7.52.3 Fri Sep 19 17:24:51 2003
+++ Zope/lib/python/ZConfig/cfgparser.py Tue Oct 7 15:36:21 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
=== Zope/lib/python/ZConfig/cmdline.py 1.1 => 1.1.44.1 ===
--- Zope/lib/python/ZConfig/cmdline.py:1.1 Wed Feb 19 17:25:47 2003
+++ Zope/lib/python/ZConfig/cmdline.py Tue Oct 7 15:36:21 2003
@@ -76,7 +76,6 @@
for item in options:
optpath, val, pos = item
name = sectiontype.keytype(optpath[0])
- key = None, name # section type, name
if len(optpath) == 1:
self.add_value(name, val, pos)
else:
=== Zope/lib/python/ZConfig/info.py 1.15.12.3 => 1.15.12.4 ===
--- Zope/lib/python/ZConfig/info.py:1.15.12.3 Fri Sep 19 17:24:51 2003
+++ Zope/lib/python/ZConfig/info.py Tue Oct 7 15:36:21 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
=== Zope/lib/python/ZConfig/loader.py 1.18.44.3 => 1.18.44.4 ===
--- Zope/lib/python/ZConfig/loader.py:1.18.44.3 Fri Sep 19 17:24:51 2003
+++ Zope/lib/python/ZConfig/loader.py Tue Oct 7 15:36:21 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
@@ -75,12 +76,15 @@
if not url:
url = _url_from_file(file)
r = self.createResource(file, url)
- return self.loadResource(r)
+ try:
+ return self.loadResource(r)
+ finally:
+ r.close()
# utilities
def loadResource(self, resource):
- raise NotImpementedError(
+ raise NotImplementedError(
"BaseLoader.loadResource() must be overridden by a subclass")
def openResource(self, url):
@@ -130,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
@@ -142,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):
@@ -165,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()
@@ -177,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(
@@ -188,15 +197,35 @@
" 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)
- self._parse_resource(section, r, defines)
+ try:
+ self._parse_resource(section, r, defines)
+ finally:
+ r.close()
# internal helper
=== Zope/lib/python/ZConfig/schema.py 1.20.22.3 => 1.20.22.4 ===
--- Zope/lib/python/ZConfig/schema.py:1.20.22.3 Fri Sep 19 17:24:51 2003
+++ Zope/lib/python/ZConfig/schema.py Tue Oct 7 15:36:21 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(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:
@@ -327,8 +329,6 @@
if attrs.has_key("extends"):
basename = self.basic_key(attrs["extends"])
base = self._schema.gettype(basename)
- if not self._localtypes.has_key(basename):
- self.error("cannot extend type derived outside component")
if base.isabstract():
self.error("sectiontype cannot extend an abstract type")
if attrs.has_key("keytype"):
@@ -338,7 +338,6 @@
else:
sectinfo = self._schema.createSectionType(
name, keytype, valuetype, datatype)
- self._localtypes[name] = sectinfo
if attrs.has_key("implements"):
ifname = self.basic_key(attrs["implements"])
interface = self._schema.gettype(ifname)
@@ -458,15 +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)
- self._localtypes = self._schema._types
+
+ 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
@@ -474,12 +534,13 @@
assert not self._prefixes
+class ComponentParser(BaseParser):
-class BaseComponentParser(BaseParser):
+ _handled_tags = BaseParser._handled_tags + ("component",)
+ _top_level = "component"
- def __init__(self, registry, loader, url, schema, localtypes):
- BaseParser.__init__(self, registry, loader, url)
- self._localtypes = localtypes
+ def __init__(self, loader, url, schema):
+ BaseParser.__init__(self, loader, url)
self._parent = schema
def characters_description(self, data):
@@ -502,23 +563,14 @@
self._check_not_toplevel("multisection")
BaseParser.start_multisection(self, attrs)
- def _check_not_toplevel(self, what):
- if not self._stack:
- self.error("cannot define top-level %s in a schema %s"
- % (what, self._top_level))
-
-
-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, schema, {})
-
def start_component(self, attrs):
self._schema = self._parent
self.push_prefix(attrs)
def end_component(self):
self.pop_prefix()
+
+ def _check_not_toplevel(self, what):
+ if not self._stack:
+ self.error("cannot define top-level %s in a schema %s"
+ % (what, self._top_level))
=== Removed File Zope/lib/python/ZConfig/Config.py ===
=== Removed File Zope/lib/python/ZConfig/Context.py ===
More information about the Zodb-checkins
mailing list