[Zodb-checkins] CVS: Zope/lib/python/ZConfig - BRANCHES.txt:1.2.2.1 Config.py:1.14.10.5 Context.py:1.15.10.8 __init__.py:1.3.10.9 cfgparser.py:1.1.2.8 datatypes.py:1.1.2.26 info.py:1.1.2.23 loader.py:1.1.2.28 matcher.py:1.1.2.33 schema.py:1.1.2.40 substitution.py:1.1.2.2 url.py:1.1.2.5
Fred L. Drake, Jr.
fred@zope.com
Thu, 9 Jan 2003 14:28:24 -0500
Update of /cvs-repository/Zope/lib/python/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv3113
Modified Files:
Tag: zconfig-schema-devel-branch
BRANCHES.txt Config.py Context.py __init__.py cfgparser.py
datatypes.py info.py loader.py matcher.py schema.py
substitution.py url.py
Log Message:
Merge from the ZConfig HEAD.
=== Zope/lib/python/ZConfig/BRANCHES.txt 1.2 => 1.2.2.1 ===
--- Zope/lib/python/ZConfig/BRANCHES.txt:1.2 Fri Dec 6 13:15:00 2002
+++ Zope/lib/python/ZConfig/BRANCHES.txt Thu Jan 9 14:27:44 2003
@@ -3,12 +3,14 @@
ZConfig package.
zconfig-brace-syntax
+ NOT ACTIVE
An example of an alternate syntax for ZConfig. This syntax was
developed while trying the package initially, but was rejected.
It is saved on a branch to avoid losing historical information.
zconfig-schema-devel-branch
+ NOT ACTIVE
Development branch for schema support in ZConfig. The branch is
based on the ZConfig trunk, but the development is strongly based
on the work Chris McDonough started in the chrism-install-branch
- for Zope 2.
+ for Zope 2. This was merged into the trunk on 3-Jan-2002.
=== Zope/lib/python/ZConfig/Config.py 1.14.10.4 => 1.14.10.5 ===
--- Zope/lib/python/ZConfig/Config.py:1.14.10.4 Wed Dec 11 15:20:37 2002
+++ Zope/lib/python/ZConfig/Config.py Thu Jan 9 14:27:44 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -102,7 +102,8 @@
type = type.lower()
return [sect for sect in self._sections if sect.type == type]
- def addValue(self, key, value):
+ def addValue(self, key, value, position=None):
+ # position is needed for interface compatibility, but isn't used here
key = key.lower()
try:
self._data[key]
=== Zope/lib/python/ZConfig/Context.py 1.15.10.7 => 1.15.10.8 ===
--- Zope/lib/python/ZConfig/Context.py:1.15.10.7 Wed Dec 11 15:20:37 2002
+++ Zope/lib/python/ZConfig/Context.py Thu Jan 9 14:27:44 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -13,8 +13,6 @@
##############################################################################
"""Top-level configuration handle."""
-import urlparse
-
import ZConfig
from ZConfig import loader
@@ -42,9 +40,9 @@
# overriding the Context.getDelegateType() method.
return type.lower()
- def parse(self, resource, section):
+ def parse(self, resource, section, defines=None):
from ZConfig.cfgparser import ZConfigParser
- ZConfigParser(resource, self).parse(section)
+ ZConfigParser(resource, self, defines).parse(section)
def loadResource(self, resource):
top = self.createToplevelSection(resource.url)
@@ -53,13 +51,12 @@
self._finish()
return top
-
# interface for parser
- def includeConfiguration(self, section, url):
+ def includeConfiguration(self, section, url, defines):
r = self.openResource(url)
try:
- self.parse(r, section)
+ self.parse(r, section, defines)
finally:
r.close()
=== Zope/lib/python/ZConfig/__init__.py 1.3.10.8 => 1.3.10.9 ===
--- Zope/lib/python/ZConfig/__init__.py:1.3.10.8 Thu Jan 2 17:50:19 2003
+++ Zope/lib/python/ZConfig/__init__.py Thu Jan 9 14:27:44 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -100,6 +100,26 @@
self.found = found
self.expected = expected
ConfigurationError.__init__(self, msg)
+
+
+class DataConversionError(ConfigurationError, ValueError):
+ """Raised when a data type conversion function raises ValueError."""
+
+ def __init__(self, exception, value, position):
+ ConfigurationError.__init__(self, str(exception))
+ self.exception = exception
+ self.value = value
+ self.lineno, self.colno, self.url = position
+
+ def __str__(self):
+ s = "%s (line %d" % (self.message, self.lineno)
+ if self.colno is not None:
+ s += ", %d" % self.colno
+ if self.url:
+ s += ", in %s)" % self.url
+ else:
+ s += ")"
+ return s
class SubstitutionSyntaxError(ConfigurationError):
=== Zope/lib/python/ZConfig/cfgparser.py 1.1.2.7 => 1.1.2.8 ===
--- Zope/lib/python/ZConfig/cfgparser.py:1.1.2.7 Tue Dec 24 15:48:18 2002
+++ Zope/lib/python/ZConfig/cfgparser.py Thu Jan 9 14:27:45 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -25,14 +25,20 @@
class ZConfigParser:
- def __init__(self, resource, context):
+ __metaclass__ = type
+ __slots__ = ('resource', 'context', 'lineno',
+ 'stack', 'defs', 'file', 'url')
+
+ def __init__(self, resource, context, defines=None):
self.resource = resource
self.context = context
self.file = resource.file
self.url = resource.url
self.lineno = 0
self.stack = [] # [(type, name, delegatename, prevmatcher), ...]
- self.defs = {}
+ if defines is None:
+ defines = {}
+ self.defs = defines
def nextline(self):
line = self.file.readline()
@@ -123,7 +129,7 @@
else:
value = substitute(value, self.defs)
try:
- section.addValue(key, value)
+ section.addValue(key, value, (self.lineno, None, self.url))
except ConfigurationError, e:
self.error(e[0])
@@ -145,7 +151,7 @@
def handle_include(self, section, rest):
newurl = urljoin(self.url, rest)
- self.context.includeConfiguration(section, newurl)
+ self.context.includeConfiguration(section, newurl, self.defs)
def handle_define(self, section, rest):
parts = rest.split(None, 1)
@@ -157,7 +163,7 @@
self.error("cannot redefine " + `defname`)
if not isname(defname):
self.error("not a substitution legal name: " + `defname`)
- self.defs[defname] = defvalue
+ self.defs[defname] = substitute(defvalue, self.defs)
def error(self, message):
raise ConfigurationSyntaxError(message, self.url, self.lineno)
=== Zope/lib/python/ZConfig/datatypes.py 1.1.2.25 => 1.1.2.26 ===
--- Zope/lib/python/ZConfig/datatypes.py:1.1.2.25 Fri Jan 3 14:01:50 2003
+++ Zope/lib/python/ZConfig/datatypes.py Thu Jan 9 14:27:45 2003
@@ -174,17 +174,16 @@
return host, port
-def socket_address(s):
- # returns (family, address) tuple
- import socket
- if "/" in s:
- if hasattr(socket, "AF_UNIX"):
- return socket.AF_UNIX, s
+class SocketAddress:
+ def __init__(self, s):
+ # returns (family, address) tuple
+ import socket
+ if "/" in s:
+ self.family = getattr(socket, "AF_UNIX", None)
+ self.address = s
else:
- raise ValueError(
- "AF_UNIX sockets are not supported on this platform")
- else:
- return socket.AF_INET, inet_address(s)
+ self.family = socket.AF_INET
+ self.address = inet_address(s)
def float_conversion(v):
if isinstance(v, type('')) or isinstance(v, type(u'')):
@@ -311,7 +310,7 @@
"basic-key": BasicKeyConversion(),
"logging-level": LogLevelConversion(),
"inet-address": inet_address,
- "socket-address": socket_address,
+ "socket-address": SocketAddress,
"ipaddr-or-hostname":IpaddrOrHostname(),
"existing-directory":existing_directory,
"existing-path": existing_path,
@@ -331,6 +330,9 @@
}
class Registry:
+ __metatype__ = type
+ __slots__ = '_stock', '_other'
+
def __init__(self, stock=None):
if stock is None:
stock = stock_datatypes.copy()
=== Zope/lib/python/ZConfig/info.py 1.1.2.22 => 1.1.2.23 ===
--- Zope/lib/python/ZConfig/info.py:1.1.2.22 Fri Jan 3 12:05:21 2003
+++ Zope/lib/python/ZConfig/info.py Thu Jan 9 14:27:45 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -24,6 +24,9 @@
class UnboundedThing:
+ __metaclass__ = type
+ __slots__ = ()
+
def __lt__(self, other):
return False
@@ -48,6 +51,22 @@
Unbounded = UnboundedThing()
+class ValueInfo:
+ __metaclass__ = type
+ __slots__ = 'value', 'position'
+
+ def __init__(self, value, position):
+ self.value = value
+ # position is (lineno, colno, url)
+ self.position = position
+
+ def convert(self, datatype):
+ try:
+ return datatype(self.value)
+ except ValueError, e:
+ raise ZConfig.DataConversionError(e, self.value, self.position)
+
+
class BaseInfo:
"""Information about a single configuration key."""
@@ -75,7 +94,7 @@
clsname = self.__class__.__name__
return "<%s for %s>" % (clsname, `self.name`)
- def istypegroup(self):
+ def isabstract(self):
return False
def ismulti(self):
@@ -100,10 +119,11 @@
"cannot finish KeyInfo more than once")
self._finished = True
- def adddefault(self, value):
+ def adddefault(self, value, position):
if self._finished:
raise ZConfig.SchemaError(
"cannot add default values to finished KeyInfo")
+ value = ValueInfo(value, position)
if self.maxOccurs > 1:
if self._default is None:
self._default = [value]
@@ -146,7 +166,7 @@
raise ZConfig.SchemaError(
"sections which can occur more than once must"
" specify a target attribute name")
- if sectiontype.istypegroup():
+ if sectiontype.isabstract():
datatype = None
else:
datatype = sectiontype.datatype
@@ -170,8 +190,8 @@
return False
elif self.name == "+":
return name and True or False
- elif not name:
- return self.name == "*"
+ elif self.name == "*":
+ return True
else:
return name == self.name
@@ -182,39 +202,36 @@
else:
return None
-class TypeContainer:
- def __init__(self):
- self._types = {}
- def addtype(self, typeinfo):
- n = typeinfo.name.lower()
- if self._types.has_key(n):
- raise ZConfig.SchemaError("type name cannot be redefined: "
- + `typeinfo.name`)
- self._types[n] = typeinfo
+class AbstractType:
+ __metaclass__ = type
+ __slots__ = '_subtypes', 'name'
- def gettype(self, name):
- n = name.lower()
+ def __init__(self, name):
+ self._subtypes = {}
+ self.name = name
+
+ def addsubtype(self, type):
+ self._subtypes[type.name] = type
+
+ def getsubtype(self, name):
try:
- return self._types[n]
+ return self._subtypes[name]
except KeyError:
- raise ZConfig.SchemaError("unknown type name: " + `name`)
+ raise ZConfig.SchemaError("no sectiontype %s in abstracttype %s"
+ % (`name`, `self.name`))
- def gettypenames(self):
- return self._types.keys()
+ def getsubtypenames(self):
+ L = self._subtypes.keys()
+ L.sort()
+ return L
-
-class GroupType(TypeContainer):
- def __init__(self, name):
- TypeContainer.__init__(self)
- self.name = name
-
- def istypegroup(self):
+ def isabstract(self):
return True
class SectionType:
- def __init__(self, name, keytype, valuetype, datatype):
+ def __init__(self, name, keytype, valuetype, datatype, registry, types):
# name - name of the section, or '*' or '+'
# datatype - type for the section itself
# keytype - type for the keys themselves
@@ -223,9 +240,22 @@
self.datatype = datatype
self.keytype = keytype
self.valuetype = valuetype
+ self.handler = None
+ self.registry = registry
self._children = [] # [(key, info), ...]
self._attrmap = {} # {attribute: index, ...}
self._keymap = {} # {key: index, ...}
+ self._types = types
+
+ def gettype(self, name):
+ n = name.lower()
+ try:
+ return self._types[n]
+ except KeyError:
+ raise ZConfig.SchemaError("unknown type name: " + `name`)
+
+ def gettypenames(self):
+ return self._types.keys()
def __len__(self):
return len(self._children)
@@ -294,9 +324,9 @@
raise ZConfig.ConfigurationError(
"section name %s already in use for key" % key)
st = info.sectiontype
- if st.istypegroup():
+ if st.isabstract():
try:
- st = st.gettype(type)
+ st = st.getsubtype(type)
except ZConfig.ConfigurationError:
raise ZConfig.ConfigurationError(
"section type %s not allowed for name %s"
@@ -306,19 +336,19 @@
"name %s must be used for a %s section"
% (`name`, `st.name`))
return index
- # else must be a section or a sectiongroup:
+ # else must be a sectiontype or an abstracttype:
elif info.sectiontype.name == type:
if not (name or info.allowUnnamed()):
raise ZConfig.ConfigurationError(
`type` + " sections must be named")
return index
- elif info.sectiontype.istypegroup():
+ elif info.sectiontype.isabstract():
st = info.sectiontype
if st.name == type:
raise ZConfig.ConfigurationError(
- "cannot define section with a sectiongroup type")
+ "cannot define section with an abstract type")
try:
- st = st.gettype(type)
+ st = st.getsubtype(type)
except ZConfig.ConfigurationError:
# not this one; maybe a different one
pass
@@ -329,21 +359,29 @@
def getsectioninfo(self, type, name):
i = self.getsectionindex(type, name)
st = self._children[i][1]
- if st.istypegroup():
+ if st.isabstract():
st = st.gettype(type)
return st
- def istypegroup(self):
+ def isabstract(self):
return False
-class SchemaType(TypeContainer, SectionType):
- def __init__(self, name, keytype, valuetype, datatype, handler, url):
- SectionType.__init__(self, name, keytype, valuetype, datatype)
- TypeContainer.__init__(self)
+class SchemaType(SectionType):
+ def __init__(self, name, keytype, valuetype, datatype, handler, url,
+ registry):
+ SectionType.__init__(self, name, keytype, valuetype, datatype,
+ registry, {})
self.handler = handler
self.url = url
+ def addtype(self, typeinfo):
+ n = typeinfo.name.lower()
+ if self._types.has_key(n):
+ raise ZConfig.SchemaError("type name cannot be redefined: "
+ + `typeinfo.name`)
+ self._types[n] = typeinfo
+
def allowUnnamed(self):
return True
@@ -361,3 +399,19 @@
if self.name and self.name in alltypes:
alltypes.remove(self.name)
return alltypes
+
+ def createSectionType(self, name, keytype, valuetype, datatype):
+ t = SectionType(name, keytype, valuetype, datatype,
+ self.registry, self._types)
+ self.addtype(t)
+ return t
+
+ def deriveSectionType(self, base, name, valuetype, datatype):
+ if isinstance(base, SchemaType):
+ raise ZConfig.SchemaError(
+ "cannot derive sectiontype from top-level schema")
+ t = self.createSectionType(name, base.keytype, valuetype, datatype)
+ t._attrmap.update(base._attrmap)
+ t._keymap.update(base._keymap)
+ t._children.extend(base._children)
+ return t
=== Zope/lib/python/ZConfig/loader.py 1.1.2.27 => 1.1.2.28 ===
--- Zope/lib/python/ZConfig/loader.py:1.1.2.27 Fri Jan 3 13:53:03 2003
+++ Zope/lib/python/ZConfig/loader.py Thu Jan 9 14:27:45 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -14,6 +14,7 @@
"""Schema loader utility."""
import os.path
+import sys
import urllib
import urllib2
@@ -30,8 +31,7 @@
False = 0
-RESOURCE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- "resources")
+LIBRARY_DIR = os.path.join(sys.prefix, "lib", "zconfig")
def loadSchema(url):
@@ -79,15 +79,14 @@
# resources. The policy needs to support both re-retrieve on
# change and provide the cached resource when the remote
# resource is not accessible.
- parts = list(urlsplit(url))
+ url = str(url)
+ parts = urlsplit(url)
fragment = parts[-1]
if fragment:
+ parts = list(parts)
parts[-1] = ''
url = urlunsplit(tuple(parts))
- if parts[0] == 'zconfig':
- file = _open_resource_file(url)
- else:
- file = urllib2.urlopen(url)
+ file = urllib2.urlopen(url)
return self.createResource(file, url, fragment or None)
def normalizeURL(self, url):
@@ -114,22 +113,16 @@
return None
-def _open_resource_file(url):
- parts = urlsplit(url)
- assert parts[0] == 'zconfig'
- fn = os.path.join(RESOURCE_DIR, parts[2])
- if not os.path.isfile(fn):
- raise ValueError("no such resource: " + `parts[2]`)
- return open(fn)
-
-
class SchemaLoader(BaseLoader):
- def __init__(self, registry=None):
+ def __init__(self, registry=None, library=None):
if registry is None:
registry = datatypes.Registry()
+ BaseLoader.__init__(self)
self.registry = registry
self._cache = {}
- BaseLoader.__init__(self)
+ if library is None:
+ library = LIBRARY_DIR
+ self._library = library
def loadResource(self, resource):
if resource.url and self._cache.has_key(resource.url):
@@ -146,10 +139,36 @@
def allowFragments(self):
return True
+ # schema parser support API
+
+ def schemaPackageInfo(self, package):
+ parts = package.split(".")
+ if not parts:
+ raise ZConfig.SchemaError(
+ "illegal schema component name: " + `package`)
+ if len(filter(None, parts)) != len(parts):
+ # '' somewhere in the package spec; still illegal
+ raise ZConfig.SchemaError(
+ "illegal schema component name: " + `package`)
+ dirname = os.path.join(self._library, *parts)
+ fn = os.path.join(dirname, "component.xml")
+ if not os.path.exists(fn):
+ raise ZConfig.SchemaError(
+ "schema component not found: " + `package`)
+ url = "file://" + urllib.pathname2url(fn)
+ extensions = []
+ for fn in os.listdir(dirname):
+ if fn == "component.xml":
+ continue
+ path = os.path.join(dirname, fn, "extension.xml")
+ if os.path.exists(path):
+ extensions.append("file://" + urllib.pathname2url(path))
+ return url, extensions
+
class ConfigLoader(BaseLoader):
def __init__(self, schema):
- if schema.istypegroup():
+ if schema.isabstract():
raise ZConfig.SchemaError(
"cannot check a configuration an abstract type")
BaseLoader.__init__(self)
@@ -161,18 +180,18 @@
self._parse_resource(sm, resource)
return sm.finish(), CompositeHandler(self.handlers, self.schema)
- # parser support API
+ # config parser support API
def startSection(self, parent, type, name, delegatename):
if delegatename:
raise NotImpementedError("section delegation is not yet supported")
t = self.schema.gettype(type)
- if t.istypegroup():
+ if t.isabstract():
raise ZConfig.ConfigurationError(
"concrete sections cannot match abstract section types;"
" found abstract type " + `type`)
ci = parent.type.getsectioninfo(type, name)
- assert not ci.istypegroup()
+ assert not ci.isabstract()
if not ci.isAllowedName(name):
raise ZConfig.ConfigurationError(
"%s is not an allowed name for %s sections"
@@ -184,19 +203,22 @@
sectvalue = matcher.finish()
parent.addSection(type, name, sectvalue)
- def includeConfiguration(self, section, url):
+ def includeConfiguration(self, section, url, defines):
r = self.openResource(url)
- self._parse_resource(section, r)
+ self._parse_resource(section, r, defines)
# internal helper
- def _parse_resource(self, matcher, resource):
+ def _parse_resource(self, matcher, resource, defines=None):
from ZConfig.cfgparser import ZConfigParser
- parser = ZConfigParser(resource, self)
+ parser = ZConfigParser(resource, self, defines)
parser.parse(matcher)
class CompositeHandler:
+ __metatype__ = type
+ __slots__ = '_handlers', '_convert'
+
def __init__(self, handlers, schema):
self._handlers = handlers
self._convert = schema.registry.get("basic-key")
=== Zope/lib/python/ZConfig/matcher.py 1.1.2.32 => 1.1.2.33 ===
--- Zope/lib/python/ZConfig/matcher.py:1.1.2.32 Fri Jan 3 13:54:01 2003
+++ Zope/lib/python/ZConfig/matcher.py Thu Jan 9 14:27:45 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -17,6 +17,8 @@
import ZConfig
+from ZConfig.info import ValueInfo
+
class BaseMatcher:
def __init__(self, info, type, handlers):
@@ -54,7 +56,7 @@
raise ZConfig.ConfigurationError(
"too many instances of %s section" % `ci.sectiontype.name`)
- def addValue(self, key, value):
+ def addValue(self, key, value, position):
length = len(self.type)
arbkey_info = None
for i in range(length):
@@ -92,6 +94,7 @@
raise ZConfig.ConfigurationError(
"too many values for " + `name`)
+ value = ValueInfo(value, position)
if k == '+':
if ismulti:
if v.has_key(key):
@@ -100,7 +103,8 @@
v[key] = [value]
else:
if v.has_key(key):
- raise ZConfig.ConfigurationError("too many")
+ raise ZConfig.ConfigurationError(
+ "too many values for " + `key`)
v[key] = value
elif ismulti:
v.append(value)
@@ -165,9 +169,9 @@
elif ci.name == '+':
v = values[i]
for key, val in v.items():
- v[key] = [ci.datatype(s) for s in val]
+ v[key] = [vi.convert(ci.datatype) for vi in val]
else:
- v = [ci.datatype(s) for s in values[i]]
+ v = [vi.convert(ci.datatype) for vi in values[i]]
elif ci.issection():
if values[i] is not None:
v = values[i]._type.datatype(values[i])
@@ -176,11 +180,11 @@
elif name == '+':
v = values[i]
for key, val in v.items():
- v[key] = ci.datatype(val)
+ v[key] = val.convert(ci.datatype)
else:
v = values[i]
if v is not None:
- v = ci.datatype(v)
+ v = v.convert(ci.datatype)
values[i] = v
if ci.handler is not None:
self._handlers.append((ci.handler, v))
=== Zope/lib/python/ZConfig/schema.py 1.1.2.39 => 1.1.2.40 === (420/520 lines abridged)
--- Zope/lib/python/ZConfig/schema.py:1.1.2.39 Fri Jan 3 13:54:58 2003
+++ Zope/lib/python/ZConfig/schema.py Thu Jan 9 14:27:45 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -44,10 +44,10 @@
return parser._schema
-class SchemaParser(xml.sax.ContentHandler):
+class BaseParser(xml.sax.ContentHandler):
_cdata_tags = "description", "metadefault", "example", "default"
- _handled_tags = ("schema", "import", "sectiongroup", "sectiontype",
+ _handled_tags = ("import", "abstracttype", "sectiontype",
"key", "multikey", "section", "multisection")
def __init__(self, registry, loader, url):
@@ -60,8 +60,8 @@
self._prefixes = []
self._schema = None
self._stack = []
- self._group = None
self._url = url
+ self._components = {}
# SAX 2 ContentHandler methods
@@ -70,10 +70,10 @@
def startElement(self, name, attrs):
attrs = dict(attrs)
- if name == "schema":
+ if name == self._top_level:
if self._schema is not None:
self.error("schema element improperly nested")
- self.start_schema(attrs)
+ getattr(self, "start_" + name)(attrs)
elif name in self._handled_tags:
if self._schema is None:
self.error(name + " element outside of schema")
@@ -84,11 +84,14 @@
if self._cdata is not None:
self.error(name + " element improperly nested")
self._cdata = []
[-=- -=- -=- 420 lines omitted -=- -=- -=-]
+ "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
+ self.push_prefix(attrs)
+
+ def end_component(self):
+ self.pop_prefix()
+
+ 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
+ self.push_prefix(attrs)
+
+ def end_extension(self):
+ self.pop_prefix()
=== Zope/lib/python/ZConfig/substitution.py 1.1.2.1 => 1.1.2.2 ===
--- Zope/lib/python/ZConfig/substitution.py:1.1.2.1 Fri Dec 20 12:49:00 2002
+++ Zope/lib/python/ZConfig/substitution.py Thu Jan 9 14:27:45 2003
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2002 Zope Corporation and Contributors.
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
=== Zope/lib/python/ZConfig/url.py 1.1.2.4 => 1.1.2.5 ===
--- Zope/lib/python/ZConfig/url.py:1.1.2.4 Thu Jan 2 12:26:29 2003
+++ Zope/lib/python/ZConfig/url.py Thu Jan 9 14:27:45 2003
@@ -1,10 +1,44 @@
-"""urlparse-like helpers that support the zconfig scheme."""
+##############################################################################
+#
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""urlparse-like helpers that normalize file: URLs.
+
+ZConfig and urllib2 expect file: URLs to consistently use the '//'
+hostpart seperator; the functions here enforce this constraint.
+"""
import posixpath as _posixpath
import urlparse as _urlparse
from urllib import splittype as _splittype
+try:
+ from urlparse import urlsplit
+except ImportError:
+ def urlsplit(url):
+ # Check for the fragment here, since Python 2.1.3 didn't get
+ # it right for things like "http://www.python.org#frag".
+ if '#' in url:
+ url, fragment = url.split('#', 1)
+ else:
+ fragment = ''
+ parts = list(_urlparse.urlparse(url))
+ parts[-1] = fragment
+ param = parts.pop(3)
+ if param:
+ parts[2] += ";" + param
+ return tuple(parts)
+
def urlnormalize(url):
parts = urlsplit(url)
@@ -18,7 +52,9 @@
def urlunsplit(parts):
- url = _urlparse.urlunsplit(parts)
+ parts = list(parts)
+ parts.insert(3, '')
+ url = _urlparse.urlunparse(tuple(parts))
if ( parts[0] == "file"
and url.startswith("file:/")
and not url.startswith("file:///")):
@@ -27,68 +63,12 @@
def urldefrag(url):
- parts = urlsplit(url)
- if parts[0] == "zconfig":
- return "zconfig:" + parts[2], parts[4]
- else:
- url, fragment = _urlparse.urldefrag(url)
- return urlnormalize(url), fragment
+ url, fragment = _urlparse.urldefrag(url)
+ return urlnormalize(url), fragment
def urljoin(base, relurl):
- scheme = _splittype(base)[0]
- if scheme != "zconfig":
- url = _urlparse.urljoin(base, relurl)
- if url.startswith("file:/") and not url.startswith("file:///"):
- url = "file://" + url[5:]
- return url
- relscheme = _splittype(relurl)[0]
- if relscheme and relscheme != "zconfig":
- return _urlparse.urljoin(base, relurl)
- baseparts = urlsplit(base)
- relparts = urlsplit(relurl, "zconfig")
- if relparts[2]:
- d = _posixpath.dirname(baseparts[2])
- if d:
- d += "/"
- path = _posixpath.normpath(_posixpath.join(d, relparts[2]))
- else:
- path = baseparts[2]
- parts = path.split('/')
- if '..' in parts:
- raise ValueError("zconfig URIs cannot include '..' references: "
- + `path`)
- s = "zconfig:" + path
- if relparts[4]:
- s += "#" + relparts[4]
- return s
-
-
-def urlsplit(url, scheme=''):
- stated_scheme = _splittype(url)[0]
- scheme = stated_scheme or scheme
- parts = _urlparse.urlsplit(url, scheme=scheme)
- if scheme == "zconfig":
- path = parts[2]
- if stated_scheme:
- # These constraints only apply to absolute zconfig: URLs
- if not path:
- # Require a non-empty path; empty path is ok for
- # relative URL ("#frag").
- raise ValueError(
- "zconfig URIs require a non-empty path component")
- if '..' in path.split('/'):
- raise ValueError(
- "zconfig URIs cannot include '..' references: " + `url`)
- # Split the fragment ourselves since the urlparse module
- # doesn't know about the zconfig: scheme.
- if '#' in path:
- path, fragment = path.split('#', 1)
- parts = "zconfig", '', path, '', fragment
- if path[:1] == '/':
- raise ValueError(
- "path component of zconfig: URIs may not start with '/'")
- if '?' in path:
- raise ValueError("zconfig: URIs may not contain queries: "
- + `url`)
- return parts
+ url = _urlparse.urljoin(base, relurl)
+ if url.startswith("file:/") and not url.startswith("file:///"):
+ url = "file://" + url[5:]
+ return url