[Zconfig] SVN: ZConfig/trunk/ fix up the ZConfig tree to separate
distribution stuff from code
Fred L. Drake, Jr.
fdrake at gmail.com
Mon Sep 19 16:22:49 EDT 2005
Log message for revision 38533:
fix up the ZConfig tree to separate distribution stuff from code
Changed:
A ZConfig/trunk/DEPENDENCIES.cfg
U ZConfig/trunk/PACKAGE.cfg
U ZConfig/trunk/SETUP.cfg
A ZConfig/trunk/ZConfig/
A ZConfig/trunk/ZConfig/__init__.py
A ZConfig/trunk/ZConfig/cfgparser.py
A ZConfig/trunk/ZConfig/cmdline.py
A ZConfig/trunk/ZConfig/components/
A ZConfig/trunk/ZConfig/datatypes.py
A ZConfig/trunk/ZConfig/info.py
A ZConfig/trunk/ZConfig/loader.py
A ZConfig/trunk/ZConfig/matcher.py
A ZConfig/trunk/ZConfig/schema.py
A ZConfig/trunk/ZConfig/substitution.py
A ZConfig/trunk/ZConfig/tests/
A ZConfig/trunk/ZConfig/url.py
D ZConfig/trunk/__init__.py
D ZConfig/trunk/cfgparser.py
D ZConfig/trunk/cmdline.py
D ZConfig/trunk/components/
D ZConfig/trunk/datatypes.py
D ZConfig/trunk/info.py
D ZConfig/trunk/loader.py
D ZConfig/trunk/matcher.py
D ZConfig/trunk/schema.py
D ZConfig/trunk/substitution.py
D ZConfig/trunk/tests/
D ZConfig/trunk/url.py
A ZConfig/trunk/zpkg.conf
-=-
Added: ZConfig/trunk/DEPENDENCIES.cfg
===================================================================
--- ZConfig/trunk/DEPENDENCIES.cfg 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/DEPENDENCIES.cfg 2005-09-19 20:22:48 UTC (rev 38533)
@@ -0,0 +1,6 @@
+# We need this since we're playing games with zpkg. As far as zpkg is
+# concerned, we're building a small collection distribution that
+# contains a single Python package. That package is what we're naming
+# here.
+
+ZConfig
Property changes on: ZConfig/trunk/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:eol-style
+ native
Modified: ZConfig/trunk/PACKAGE.cfg
===================================================================
--- ZConfig/trunk/PACKAGE.cfg 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/PACKAGE.cfg 2005-09-19 20:22:48 UTC (rev 38533)
@@ -2,21 +2,16 @@
# Add a few things to the distribution root.
<distribution>
- doc
LICENSE.txt
NEWS.txt
README.txt
+ doc/zconfig.pdf
+ doc/schema.dtd
</distribution>
# Specify what is included in the component.
<collection>
- # Python modules from the package:
- *.py
-
- # Child packages:
- components
- tests
-
- # Other files and directories needed when distutils runs:
+ doc/zconfig.pdf
+ doc/schema.dtd
scripts
</collection>
Modified: ZConfig/trunk/SETUP.cfg
===================================================================
--- ZConfig/trunk/SETUP.cfg 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/SETUP.cfg 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,6 +1,6 @@
# Metadata used by zpkg.
-#documentation doc/zconfig.pdf
-#documentation doc/schema.dtd
+documentation doc/zconfig.pdf
+documentation doc/schema.dtd
script scripts/zconfig*
Copied: ZConfig/trunk/ZConfig/__init__.py (from rev 38532, ZConfig/trunk/__init__.py)
Copied: ZConfig/trunk/ZConfig/cfgparser.py (from rev 38532, ZConfig/trunk/cfgparser.py)
Copied: ZConfig/trunk/ZConfig/cmdline.py (from rev 38532, ZConfig/trunk/cmdline.py)
Copied: ZConfig/trunk/ZConfig/components (from rev 38532, ZConfig/trunk/components)
Copied: ZConfig/trunk/ZConfig/datatypes.py (from rev 38532, ZConfig/trunk/datatypes.py)
Copied: ZConfig/trunk/ZConfig/info.py (from rev 38532, ZConfig/trunk/info.py)
Copied: ZConfig/trunk/ZConfig/loader.py (from rev 38532, ZConfig/trunk/loader.py)
Copied: ZConfig/trunk/ZConfig/matcher.py (from rev 38532, ZConfig/trunk/matcher.py)
Copied: ZConfig/trunk/ZConfig/schema.py (from rev 38532, ZConfig/trunk/schema.py)
Copied: ZConfig/trunk/ZConfig/substitution.py (from rev 38532, ZConfig/trunk/substitution.py)
Copied: ZConfig/trunk/ZConfig/tests (from rev 38532, ZConfig/trunk/tests)
Copied: ZConfig/trunk/ZConfig/url.py (from rev 38532, ZConfig/trunk/url.py)
Deleted: ZConfig/trunk/__init__.py
===================================================================
--- ZConfig/trunk/__init__.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/__init__.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,128 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Configuration data structures and loader for the ZRS.
-
-$Id: __init__.py,v 1.18 2004/04/15 20:33:32 fdrake Exp $
-"""
-version_info = (2, 3)
-__version__ = ".".join([str(n) for n in version_info])
-
-from ZConfig.loader import loadConfig, loadConfigFile
-from ZConfig.loader import loadSchema, loadSchemaFile
-
-
-class ConfigurationError(Exception):
- """Base class for ZConfig exceptions."""
-
- def __init__(self, msg, url=None):
- self.message = msg
- self.url = url
- Exception.__init__(self, msg)
-
- def __str__(self):
- return self.message
-
-
-class _ParseError(ConfigurationError):
- def __init__(self, msg, url, lineno, colno=None):
- self.lineno = lineno
- self.colno = colno
- ConfigurationError.__init__(self, msg, url)
-
- def __str__(self):
- s = self.message
- if self.url:
- s += "\n("
- elif (self.lineno, self.colno) != (None, None):
- s += " ("
- if self.lineno:
- s += "line %d" % self.lineno
- if self.colno is not None:
- s += ", column %d" % self.colno
- if self.url:
- s += " in %s)" % self.url
- else:
- s += ")"
- elif self.url:
- s += self.url + ")"
- return s
-
-
-class SchemaError(_ParseError):
- """Raised when there's an error in the schema itself."""
-
- def __init__(self, msg, url=None, lineno=None, colno=None):
- _ParseError.__init__(self, msg, url, lineno, colno)
-
-
-class SchemaResourceError(SchemaError):
- """Raised when there's an error locating a resource required by the schema.
- """
-
- def __init__(self, msg, url=None, lineno=None, colno=None,
- path=None, package=None, filename=None):
- self.filename = filename
- self.package = package
- if path is not None:
- path = path[:]
- self.path = path
- SchemaError.__init__(self, msg, url, lineno, colno)
-
- def __str__(self):
- s = SchemaError.__str__(self)
- if self.package is not None:
- s += "\n Package name: " + repr(self.package)
- if self.filename is not None:
- s += "\n File name: " + repr(self.filename)
- if self.package is not None:
- s += "\n Package path: " + repr(self.path)
- return s
-
-
-class ConfigurationSyntaxError(_ParseError):
- """Raised when there's a syntax error in a configuration file."""
-
-
-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 %s" % (self.message, self.lineno)
- if self.colno is not None:
- s += ", %s" % self.colno
- if self.url:
- s += ", in %s)" % self.url
- else:
- s += ")"
- return s
-
-
-class SubstitutionSyntaxError(ConfigurationError):
- """Raised when interpolation source text contains syntactical errors."""
-
-
-class SubstitutionReplacementError(ConfigurationSyntaxError, LookupError):
- """Raised when no replacement is available for a reference."""
-
- def __init__(self, source, name, url=None, lineno=None):
- self.source = source
- self.name = name
- ConfigurationSyntaxError.__init__(
- self, "no replacement for " + `name`, url, lineno)
Deleted: ZConfig/trunk/cfgparser.py
===================================================================
--- ZConfig/trunk/cfgparser.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/cfgparser.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,193 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Configuration parser."""
-
-import ZConfig
-import ZConfig.url
-
-from ZConfig.substitution import isname, substitute
-
-
-class ZConfigParser:
- __metaclass__ = type
- __slots__ = ('resource', 'context', 'lineno',
- 'stack', 'defines', '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, prevmatcher), ...]
- if defines is None:
- defines = {}
- self.defines = defines
-
- def nextline(self):
- line = self.file.readline()
- if line:
- self.lineno += 1
- return False, line.strip()
- else:
- return True, None
-
- def parse(self, section):
- done, line = self.nextline()
- while not done:
- if line[:1] in ("", "#"):
- # blank line or comment
- pass
-
- elif line[:2] == "</":
- # section end
- if line[-1] != ">":
- self.error("malformed section end")
- section = self.end_section(section, line[2:-1])
-
- elif line[0] == "<":
- # section start
- if line[-1] != ">":
- self.error("malformed section start")
- section = self.start_section(section, line[1:-1])
-
- elif line[0] == "%":
- self.handle_directive(section, line[1:])
-
- else:
- self.handle_key_value(section, line)
-
- done, line = self.nextline()
-
- if self.stack:
- self.error("unclosed sections not allowed")
-
- def start_section(self, section, rest):
- isempty = rest[-1:] == "/"
- if isempty:
- rest = rest[:-1]
- text = rest.rstrip()
- # parse section start stuff here
- m = _section_start_rx.match(text)
- if not m:
- self.error("malformed section header")
- type, name = m.group('type', 'name')
- type = self._normalize_case(type)
- if name:
- name = self._normalize_case(name)
- try:
- newsect = self.context.startSection(section, type, name)
- except ZConfig.ConfigurationError, e:
- self.error(e[0])
-
- if isempty:
- self.context.endSection(section, type, name, newsect)
- return section
- else:
- self.stack.append((type, name, section))
- return newsect
-
- def end_section(self, section, rest):
- if not self.stack:
- self.error("unexpected section end")
- type = self._normalize_case(rest.rstrip())
- opentype, name, prevsection = self.stack.pop()
- if type != opentype:
- self.error("unbalanced section end")
- try:
- self.context.endSection(
- prevsection, type, name, section)
- except ZConfig.ConfigurationError, e:
- self.error(e[0])
- return prevsection
-
- def handle_key_value(self, section, rest):
- m = _keyvalue_rx.match(rest)
- if not m:
- self.error("malformed configuration data")
- key, value = m.group('key', 'value')
- if not value:
- value = ''
- else:
- value = self.replace(value)
- try:
- section.addValue(key, value, (self.lineno, None, self.url))
- except ZConfig.ConfigurationError, e:
- self.error(e[0])
-
- def handle_directive(self, section, rest):
- m = _keyvalue_rx.match(rest)
- if not m:
- self.error("missing or unrecognized directive")
- name, arg = m.group('key', 'value')
- if name not in ("define", "import", "include"):
- self.error("unknown directive: " + `name`)
- if not arg:
- self.error("missing argument to %%%s directive" % name)
- if name == "include":
- 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.defines)
-
- def handle_define(self, section, rest):
- parts = rest.split(None, 1)
- defname = self._normalize_case(parts[0])
- defvalue = ''
- if len(parts) == 2:
- defvalue = parts[1]
- if self.defines.has_key(defname):
- self.error("cannot redefine " + `defname`)
- if not isname(defname):
- self.error("not a substitution legal name: " + `defname`)
- self.defines[defname] = self.replace(defvalue)
-
- def replace(self, text):
- try:
- return substitute(text, self.defines)
- except ZConfig.SubstitutionReplacementError, e:
- e.lineno = self.lineno
- e.url = self.url
- raise
-
- def error(self, message):
- raise ZConfig.ConfigurationSyntaxError(message, self.url, self.lineno)
-
- def _normalize_case(self, string):
- return string.lower()
-
-
-import re
-# _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"$"
- % (_name_re, _name_re))
-del re
Deleted: ZConfig/trunk/cmdline.py
===================================================================
--- ZConfig/trunk/cmdline.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/cmdline.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,182 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (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.
-#
-##############################################################################
-
-"""Support for command-line provision of settings.
-
-This module provides an extension of the ConfigLoader class which adds
-a way to add configuration settings from an alternate source. Each
-setting is described by a string of the form::
-
- some/path/to/key=value
-"""
-
-import ZConfig
-import ZConfig.loader
-import ZConfig.matcher
-
-
-class ExtendedConfigLoader(ZConfig.loader.ConfigLoader):
- def __init__(self, schema):
- ZConfig.loader.ConfigLoader.__init__(self, schema)
- self.clopts = [] # [(optpath, value, source-position), ...]
-
- def addOption(self, spec, pos=None):
- if pos is None:
- pos = "<command-line option>", -1, -1
- if "=" not in spec:
- e = ZConfig.ConfigurationSyntaxError(
- "invalid configuration specifier", *pos)
- e.specifier = spec
- raise e
- # For now, just add it to the list; not clear that checking
- # against the schema at this point buys anything.
- opt, val = spec.split("=", 1)
- optpath = opt.split("/")
- if "" in optpath:
- # // is not allowed in option path
- e = ZConfig.ConfigurationSyntaxError(
- "'//' is not allowed in an option path", *pos)
- e.specifier = spec
- raise e
- self.clopts.append((optpath, val, pos))
-
- def createSchemaMatcher(self):
- if self.clopts:
- sm = ExtendedSchemaMatcher(self.schema)
- sm.set_optionbag(self.cook())
- else:
- sm = ZConfig.loader.ConfigLoader.createSchemaMatcher(self)
- return sm
-
- def cook(self):
- if self.clopts:
- return OptionBag(self.schema, self.schema, self.clopts)
- else:
- return None
-
-
-class OptionBag:
- def __init__(self, schema, sectiontype, options):
- self.sectiontype = sectiontype
- self.schema = schema
- self.keypairs = {}
- self.sectitems = []
- self._basic_key = schema.registry.get("basic-key")
- for item in options:
- optpath, val, pos = item
- name = sectiontype.keytype(optpath[0])
- if len(optpath) == 1:
- self.add_value(name, val, pos)
- else:
- self.sectitems.append(item)
-
- def basic_key(self, s, pos):
- try:
- return self._basic_key(s)
- except ValueError:
- raise ZConfig.ConfigurationSyntaxError(
- "could not convert basic-key value", *pos)
-
- def add_value(self, name, val, pos):
- if self.keypairs.has_key(name):
- L = self.keypairs[name]
- else:
- L = []
- self.keypairs[name] = L
- L.append((val, pos))
-
- def has_key(self, name):
- return self.keypairs.has_key(name)
-
- def get_key(self, name):
- """Return a list of (value, pos) items for the key 'name'.
-
- The returned list may be empty.
- """
- L = self.keypairs.get(name)
- if L:
- del self.keypairs[name]
- return L
- else:
- return []
-
- def keys(self):
- return self.keypairs.keys()
-
- def get_section_info(self, type, name):
- L = [] # what pertains to the child section
- R = [] # what we keep
- for item in self.sectitems:
- optpath, val, pos = item
- s = optpath[0]
- bk = self.basic_key(s, pos)
- if name and self._normalize_case(s) == name:
- L.append((optpath[1:], val, pos))
- elif bk == type:
- L.append((optpath[1:], val, pos))
- else:
- R.append(item)
- if L:
- self.sectitems[:] = R
- return OptionBag(self.schema, self.schema.gettype(type), L)
- else:
- return None
-
- def finish(self):
- if self.sectitems or self.keypairs:
- raise ZConfig.ConfigurationError(
- "not all command line options were consumed")
-
- def _normalize_case(self, string):
- return string.lower()
-
-
-class MatcherMixin:
- def set_optionbag(self, bag):
- self.optionbag = bag
-
- def addValue(self, key, value, position):
- try:
- realkey = self.type.keytype(key)
- except ValueError, e:
- raise ZConfig.DataConversionError(e, key, position)
- if self.optionbag.has_key(realkey):
- return
- ZConfig.matcher.BaseMatcher.addValue(self, key, value, position)
-
- def createChildMatcher(self, type, name):
- sm = ZConfig.matcher.BaseMatcher.createChildMatcher(self, type, name)
- bag = self.optionbag.get_section_info(type.name, name)
- if bag is not None:
- sm = ExtendedSectionMatcher(
- sm.info, sm.type, sm.name, sm.handlers)
- sm.set_optionbag(bag)
- return sm
-
- def finish_optionbag(self):
- for key in self.optionbag.keys():
- for val, pos in self.optionbag.get_key(key):
- ZConfig.matcher.BaseMatcher.addValue(self, key, val, pos)
- self.optionbag.finish()
-
-
-class ExtendedSectionMatcher(MatcherMixin, ZConfig.matcher.SectionMatcher):
- def finish(self):
- self.finish_optionbag()
- return ZConfig.matcher.SectionMatcher.finish(self)
-
-class ExtendedSchemaMatcher(MatcherMixin, ZConfig.matcher.SchemaMatcher):
- def finish(self):
- self.finish_optionbag()
- return ZConfig.matcher.SchemaMatcher.finish(self)
Deleted: ZConfig/trunk/datatypes.py
===================================================================
--- ZConfig/trunk/datatypes.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/datatypes.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,425 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Selection of standard datatypes for ZConfig."""
-
-import os
-import re
-import sys
-import datetime
-
-try:
- unicode
-except NameError:
- have_unicode = False
-else:
- have_unicode = True
-
-
-class MemoizedConversion:
- """Conversion helper that caches the results of expensive conversions."""
-
- def __init__(self, conversion):
- self._memo = {}
- self._conversion = conversion
-
- def __call__(self, value):
- try:
- return self._memo[value]
- except KeyError:
- v = self._conversion(value)
- self._memo[value] = v
- return v
-
-
-class RangeCheckedConversion:
- """Conversion helper that range checks another conversion."""
-
- def __init__(self, conversion, min=None, max=None):
- self._min = min
- self._max = max
- self._conversion = conversion
-
- def __call__(self, value):
- v = self._conversion(value)
- if self._min is not None and v < self._min:
- raise ValueError("%s is below lower bound (%s)"
- % (`v`, `self._min`))
- if self._max is not None and v > self._max:
- raise ValueError("%s is above upper bound (%s)"
- % (`v`, `self._max`))
- return v
-
-
-class RegularExpressionConversion:
- reason = "value did not match regular expression"
-
- def __init__(self, regex):
- self._rx = re.compile(regex)
-
- def __call__(self, value):
- m = self._rx.match(value)
- if m and m.group() == value:
- return value
- else:
- raise ValueError("%s: %s" % (self.reason, repr(value)))
-
-
-def check_locale(value):
- import locale
- prev = locale.setlocale(locale.LC_ALL)
- try:
- try:
- locale.setlocale(locale.LC_ALL, value)
- finally:
- locale.setlocale(locale.LC_ALL, prev)
- except locale.Error:
- raise ValueError(
- 'The specified locale "%s" is not supported by your system.\n'
- 'See your operating system documentation for more\n'
- 'information on locale support.' % value)
- else:
- return value
-
-
-class BasicKeyConversion(RegularExpressionConversion):
- def __init__(self):
- RegularExpressionConversion.__init__(self, "[a-zA-Z][-._a-zA-Z0-9]*")
-
- def __call__(self, value):
- value = str(value)
- return RegularExpressionConversion.__call__(self, value).lower()
-
-
-class ASCIIConversion(RegularExpressionConversion):
- def __call__(self, value):
- value = RegularExpressionConversion.__call__(self, value)
- if have_unicode and isinstance(value, unicode):
- value = value.encode("ascii")
- return value
-
-
-_ident_re = "[_a-zA-Z][_a-zA-Z0-9]*"
-
-class IdentifierConversion(ASCIIConversion):
- reason = "not a valid Python identifier"
-
- def __init__(self):
- ASCIIConversion.__init__(self, _ident_re)
-
-
-class DottedNameConversion(ASCIIConversion):
- reason = "not a valid dotted name"
-
- def __init__(self):
- ASCIIConversion.__init__(self,
- r"%s(?:\.%s)*" % (_ident_re, _ident_re))
-
-
-class DottedNameSuffixConversion(ASCIIConversion):
- reason = "not a valid dotted name or suffix"
-
- def __init__(self):
- ASCIIConversion.__init__(self,
- r"(?:%s)(?:\.%s)*|(?:\.%s)+"
- % (_ident_re, _ident_re, _ident_re))
-
-
-def integer(value):
- try:
- return int(value)
- except ValueError:
- return long(value)
- except OverflowError:
- return long(value)
-
-
-def null_conversion(value):
- return value
-
-
-def asBoolean(s):
- """Convert a string value to a boolean value."""
- ss = str(s).lower()
- if ss in ('yes', 'true', 'on'):
- return True
- elif ss in ('no', 'false', 'off'):
- return False
- else:
- raise ValueError("not a valid boolean value: " + repr(s))
-
-
-def string_list(s):
- """Convert a string to a list of strings using .split()."""
- return s.split()
-
-
-port_number = RangeCheckedConversion(integer, min=1, max=0xffff).__call__
-
-
-class InetAddress:
-
- def __init__(self, default_host):
- self.DEFAULT_HOST = default_host
-
- def __call__(self, s):
- # returns (host, port) tuple
- host = ''
- port = None
- if ":" in s:
- host, s = s.split(":", 1)
- if s:
- port = port_number(s)
- host = host.lower()
- else:
- try:
- port = port_number(s)
- except ValueError:
- if len(s.split()) != 1:
- raise ValueError("not a valid host name: " + repr(s))
- host = s.lower()
- if not host:
- host = self.DEFAULT_HOST
- return host, port
-
-
-if sys.platform[:3] == "win":
- DEFAULT_HOST = "localhost"
-else:
- DEFAULT_HOST = ""
-
-inet_address = InetAddress(DEFAULT_HOST)
-inet_connection_address = InetAddress("127.0.0.1")
-inet_binding_address = InetAddress("")
-
-class SocketAddress:
- def __init__(self, s):
- import socket
- if "/" in s or s.find(os.sep) >= 0:
- self.family = getattr(socket, "AF_UNIX", None)
- self.address = s
- else:
- self.family = socket.AF_INET
- self.address = self._parse_address(s)
-
- def _parse_address(self, s):
- return inet_address(s)
-
-class SocketBindingAddress(SocketAddress):
-
- def _parse_address(self, s):
- return inet_binding_address(s)
-
-class SocketConnectionAddress(SocketAddress):
-
- def _parse_address(self, s):
- return inet_connection_address(s)
-
-
-def float_conversion(v):
- if isinstance(v, basestring):
- if v.lower() in ["inf", "-inf", "nan"]:
- raise ValueError(`v` + " is not a portable float representation")
- return float(v)
-
-class IpaddrOrHostname(RegularExpressionConversion):
- def __init__(self):
- # IP address regex from the Perl Cookbook, Recipe 6.23 (revised ed.)
- # We allow underscores in hostnames although this is considered
- # illegal according to RFC1034.
- expr = (r"(^(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr
- r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr cont'd
- r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])\." #ipaddr cont'd
- r"(\d|[01]?\d\d|2[0-4]\d|25[0-5])$)" #ipaddr cont'd
- r"|([A-Za-z_][-A-Za-z0-9_.]*[-A-Za-z0-9_])") # or hostname
- RegularExpressionConversion.__init__(self, expr)
-
- def __call__(self, value):
- return RegularExpressionConversion.__call__(self, value).lower()
-
-def existing_directory(v):
- nv = os.path.expanduser(v)
- if os.path.isdir(nv):
- return nv
- raise ValueError('%s is not an existing directory' % v)
-
-def existing_path(v):
- nv = os.path.expanduser(v)
- if os.path.exists(nv):
- return nv
- raise ValueError('%s is not an existing path' % v)
-
-def existing_file(v):
- nv = os.path.expanduser(v)
- if os.path.exists(nv):
- return nv
- raise ValueError('%s is not an existing file' % v)
-
-def existing_dirpath(v):
- nv = os.path.expanduser(v)
- dir = os.path.dirname(nv)
- if not dir:
- # relative pathname with no directory component
- return nv
- if os.path.isdir(dir):
- return nv
- raise ValueError('The directory named as part of the path %s '
- 'does not exist.' % v)
-
-
-class SuffixMultiplier:
- # d is a dictionary of suffixes to integer multipliers. If no suffixes
- # match, default is the multiplier. Matches are case insensitive. Return
- # values are in the fundamental unit.
- def __init__(self, d, default=1):
- self._d = d
- self._default = default
- # all keys must be the same size
- self._keysz = None
- for k in d.keys():
- if self._keysz is None:
- self._keysz = len(k)
- else:
- assert self._keysz == len(k)
-
- def __call__(self, v):
- v = v.lower()
- for s, m in self._d.items():
- if v[-self._keysz:] == s:
- return int(v[:-self._keysz]) * m
- return int(v) * self._default
-
-
-def timedelta(s):
- # Unlike the standard time-interval data type, which returns a float
- # number of seconds, this datatype takes a wider range of syntax and
- # returns a datetime.timedelta
- #
- # Accepts suffixes:
- # w - weeks
- # d - days
- # h - hours
- # m - minutes
- # s - seconds
- #
- # and all arguments may be integers or floats, positive or negative.
- # More than one time interval suffix value may appear on the line, but
- # they should all be separated by spaces, e.g.:
- #
- # sleep_time 4w 2d 7h 12m 0.00001s
- weeks = days = hours = minutes = seconds = 0
- for part in s.split():
- val = float(part[:-1])
- suffix = part[-1]
- if suffix == 'w':
- weeks = val
- elif suffix == 'd':
- days = val
- elif suffix == 'h':
- hours = val
- elif suffix == 'm':
- minutes = val
- elif suffix == 's':
- seconds = val
- else:
- raise TypeError('bad part %s in %s' % (part, s))
- return datetime.timedelta(weeks=weeks, days=days, hours=hours,
- minutes=minutes, seconds=seconds)
-
-
-stock_datatypes = {
- "boolean": asBoolean,
- "dotted-name": DottedNameConversion(),
- "dotted-suffix": DottedNameSuffixConversion(),
- "identifier": IdentifierConversion(),
- "integer": integer,
- "float": float_conversion,
- "string": str,
- "string-list": string_list,
- "null": null_conversion,
- "locale": MemoizedConversion(check_locale),
- "port-number": port_number,
- "basic-key": BasicKeyConversion(),
- "inet-address": inet_address,
- "inet-binding-address": inet_binding_address,
- "inet-connection-address": inet_connection_address,
- "socket-address": SocketAddress,
- "socket-binding-address": SocketBindingAddress,
- "socket-connection-address": SocketConnectionAddress,
- "ipaddr-or-hostname":IpaddrOrHostname(),
- "existing-directory":existing_directory,
- "existing-path": existing_path,
- "existing-file": existing_file,
- "existing-dirpath": existing_dirpath,
- "byte-size": SuffixMultiplier({'kb': 1024,
- 'mb': 1024*1024,
- 'gb': 1024*1024*1024L,
- }),
- "time-interval": SuffixMultiplier({'s': 1,
- 'm': 60,
- 'h': 60*60,
- 'd': 60*60*24,
- }),
- "timedelta": timedelta,
- }
-
-
-class Registry:
- def __init__(self, stock=None):
- if stock is None:
- stock = stock_datatypes.copy()
- self._stock = stock
- self._other = {}
- self._basic_key = None
-
- def get(self, name):
- if '.' not in name:
- if self._basic_key is None:
- self._basic_key = self._other.get("basic-key")
- if self._basic_key is None:
- self._basic_key = self._stock.get("basic-key")
- if self._basic_key is None:
- self._basic_key = stock_datatypes["basic-key"]
- name = self._basic_key(name)
- t = self._stock.get(name)
- if t is None:
- t = self._other.get(name)
- if t is None:
- t = self.search(name)
- return t
-
- def register(self, name, conversion):
- if self._stock.has_key(name):
- raise ValueError("datatype name conflicts with built-in type: "
- + `name`)
- if self._other.has_key(name):
- raise ValueError("datatype name already registered: " + `name`)
- self._other[name] = conversion
-
- def search(self, name):
- if not "." in name:
- raise ValueError("unloadable datatype name: " + `name`)
- components = name.split('.')
- start = components[0]
- g = {}
- package = __import__(start, g, g)
- modulenames = [start]
- for component in components[1:]:
- modulenames.append(component)
- try:
- package = getattr(package, component)
- except AttributeError:
- n = '.'.join(modulenames)
- package = __import__(n, g, g, component)
- self._other[name] = package
- return package
Deleted: ZConfig/trunk/info.py
===================================================================
--- ZConfig/trunk/info.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/info.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,514 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Objects that can describe a ZConfig schema."""
-
-import copy
-
-import ZConfig
-
-
-class UnboundedThing:
- __metaclass__ = type
- __slots__ = ()
-
- def __lt__(self, other):
- return False
-
- def __le__(self, other):
- return isinstance(other, self.__class__)
-
- def __gt__(self, other):
- return True
-
- def __ge__(self, other):
- return True
-
- def __eq__(self, other):
- return isinstance(other, self.__class__)
-
- def __ne__(self, other):
- return not isinstance(other, self.__class__)
-
- def __repr__(self):
- return "<Unbounded>"
-
-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."""
-
- description = None
- example = None
- metadefault = None
-
- def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
- attribute):
- if maxOccurs is not None and maxOccurs < 1:
- if maxOccurs < 1:
- raise ZConfig.SchemaError(
- "maxOccurs must be at least 1")
- if minOccurs is not None and minOccurs < maxOccurs:
- raise ZConfig.SchemaError(
- "minOccurs must be at least maxOccurs")
- self.name = name
- self.datatype = datatype
- self.minOccurs = minOccurs
- self.maxOccurs = maxOccurs
- self.handler = handler
- self.attribute = attribute
-
- def __repr__(self):
- clsname = self.__class__.__name__
- return "<%s for %s>" % (clsname, `self.name`)
-
- def isabstract(self):
- return False
-
- def ismulti(self):
- return self.maxOccurs > 1
-
- def issection(self):
- return False
-
-
-class BaseKeyInfo(BaseInfo):
-
- _rawdefaults = None
-
- def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
- attribute):
- assert minOccurs is not None
- BaseInfo.__init__(self, name, datatype, minOccurs, maxOccurs,
- handler, attribute)
- self._finished = False
-
- def finish(self):
- if self._finished:
- raise ZConfig.SchemaError(
- "cannot finish KeyInfo more than once")
- self._finished = True
-
- def adddefault(self, value, position, key=None):
- if self._finished:
- raise ZConfig.SchemaError(
- "cannot add default values to finished KeyInfo")
- # Check that the name/keyed relationship is right:
- if self.name == "+" and key is None:
- raise ZConfig.SchemaError(
- "default values must be keyed for name='+'")
- elif self.name != "+" and key is not None:
- raise ZConfig.SchemaError(
- "unexpected key for default value")
- self.add_valueinfo(ValueInfo(value, position), key)
-
- def add_valueinfo(self, vi, key):
- """Actually add a ValueInfo to this key-info object.
-
- The appropriate value of None-ness of key has already been
- checked with regard to the name of the key, and has been found
- permissible to add.
-
- This method is a requirement for subclasses, and should not be
- called by client code.
- """
- raise NotImplementedError(
- "add_valueinfo() must be implemented by subclasses of BaseKeyInfo")
-
- def prepare_raw_defaults(self):
- assert self.name == "+"
- if self._rawdefaults is None:
- self._rawdefaults = self._default
- self._default = {}
-
-
-class KeyInfo(BaseKeyInfo):
-
- _default = None
-
- def __init__(self, name, datatype, minOccurs, handler, attribute):
- BaseKeyInfo.__init__(self, name, datatype, minOccurs, 1,
- handler, attribute)
- if self.name == "+":
- self._default = {}
-
- def add_valueinfo(self, vi, key):
- if self.name == "+":
- if self._default.has_key(key):
- # not ideal: we're presenting the unconverted
- # version of the key
- raise ZConfig.SchemaError(
- "duplicate default value for key %s" % `key`)
- self._default[key] = vi
- elif self._default is not None:
- raise ZConfig.SchemaError(
- "cannot set more than one default to key with maxOccurs == 1")
- else:
- self._default = vi
-
- def computedefault(self, keytype):
- self.prepare_raw_defaults()
- for k, vi in self._rawdefaults.iteritems():
- key = ValueInfo(k, vi.position).convert(keytype)
- self.add_valueinfo(vi, key)
-
- def getdefault(self):
- # Use copy.copy() to make sure we don't allow polution of
- # our internal data without having to worry about both the
- # list and dictionary cases:
- return copy.copy(self._default)
-
-
-class MultiKeyInfo(BaseKeyInfo):
-
- def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
- attribute):
- BaseKeyInfo.__init__(self, name, datatype, minOccurs, maxOccurs,
- handler, attribute)
- if self.name == "+":
- self._default = {}
- else:
- self._default = []
-
- def add_valueinfo(self, vi, key):
- if self.name == "+":
- # This is a keyed value, not a simple value:
- if key in self._default:
- self._default[key].append(vi)
- else:
- self._default[key] = [vi]
- else:
- self._default.append(vi)
-
- def computedefault(self, keytype):
- self.prepare_raw_defaults()
- for k, vlist in self._rawdefaults.iteritems():
- key = ValueInfo(k, vlist[0].position).convert(keytype)
- for vi in vlist:
- self.add_valueinfo(vi, key)
-
- def getdefault(self):
- return copy.copy(self._default)
-
-
-class SectionInfo(BaseInfo):
- def __init__(self, name, sectiontype, minOccurs, maxOccurs, handler,
- attribute):
- # name - name of the section; one of '*', '+', or name1
- # sectiontype - SectionType instance
- # minOccurs - minimum number of occurances of the section
- # maxOccurs - maximum number of occurances; if > 1, name
- # must be '*' or '+'
- # handler - handler name called when value(s) must take effect,
- # or None
- # attribute - name of the attribute on the SectionValue object
- if maxOccurs > 1:
- if name not in ('*', '+'):
- raise ZConfig.SchemaError(
- "sections which can occur more than once must"
- " use a name of '*' or '+'")
- if not attribute:
- raise ZConfig.SchemaError(
- "sections which can occur more than once must"
- " specify a target attribute name")
- if sectiontype.isabstract():
- datatype = None
- else:
- datatype = sectiontype.datatype
- BaseInfo.__init__(self, name, datatype,
- minOccurs, maxOccurs, handler, attribute)
- self.sectiontype = sectiontype
-
- def __repr__(self):
- clsname = self.__class__.__name__
- return "<%s for %s (%s)>" % (
- clsname, self.sectiontype.name, `self.name`)
-
- def issection(self):
- return True
-
- def allowUnnamed(self):
- return self.name == "*"
-
- def isAllowedName(self, name):
- if name == "*" or name == "+":
- return False
- elif self.name == "+":
- return name and True or False
- elif self.name == "*":
- return True
- else:
- return name == self.name
-
- def getdefault(self):
- # sections cannot have defaults
- if self.maxOccurs > 1:
- return []
- else:
- return None
-
-
-class AbstractType:
- __metaclass__ = type
- __slots__ = '_subtypes', 'name', 'description'
-
- def __init__(self, name):
- self._subtypes = {}
- self.name = name
- self.description = None
-
- def addsubtype(self, type):
- self._subtypes[type.name] = type
-
- def getsubtype(self, name):
- try:
- return self._subtypes[name]
- except KeyError:
- raise ZConfig.SchemaError("no sectiontype %s in abstracttype %s"
- % (`name`, `self.name`))
-
- def hassubtype(self, name):
- """Return true iff this type has 'name' as a concrete manifestation."""
- return name in self._subtypes.keys()
-
- def getsubtypenames(self):
- """Return the names of all concrete types as a sorted list."""
- L = self._subtypes.keys()
- L.sort()
- return L
-
- def isabstract(self):
- return True
-
-
-class SectionType:
- 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
- # valuetype - default type for key values
- self.name = name
- self.datatype = datatype
- self.keytype = keytype
- self.valuetype = valuetype
- self.handler = None
- self.description = None
- self.registry = registry
- self._children = [] # [(key, info), ...]
- self._attrmap = {} # {attribute: info, ...}
- self._keymap = {} # {key: info, ...}
- 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)
-
- def __getitem__(self, index):
- return self._children[index]
-
- def _add_child(self, key, info):
- # check naming constraints
- assert key or info.attribute
- if key and self._keymap.has_key(key):
- raise ZConfig.SchemaError(
- "child name %s already used" % key)
- if info.attribute and self._attrmap.has_key(info.attribute):
- raise ZConfig.SchemaError(
- "child attribute name %s already used" % info.attribute)
- # a-ok, add the item to the appropriate maps
- if info.attribute:
- self._attrmap[info.attribute] = info
- if key:
- self._keymap[key] = info
- self._children.append((key, info))
-
- def addkey(self, keyinfo):
- self._add_child(keyinfo.name, keyinfo)
-
- def addsection(self, name, sectinfo):
- assert name not in ("*", "+")
- self._add_child(name, sectinfo)
-
- def getinfo(self, key):
- if not key:
- raise ZConfig.ConfigurationError(
- "cannot match a key without a name")
- try:
- return self._keymap[key]
- except KeyError:
- raise ZConfig.ConfigurationError("no key matching " + `key`)
-
- def getrequiredtypes(self):
- d = {}
- if self.name:
- d[self.name] = 1
- stack = [self]
- while stack:
- info = stack.pop()
- for key, ci in info._children:
- if ci.issection():
- t = ci.sectiontype
- if not d.has_key(t.name):
- d[t.name] = 1
- stack.append(t)
- return d.keys()
-
- def getsectioninfo(self, type, name):
- for key, info in self._children:
- if key:
- if key == name:
- if not info.issection():
- raise ZConfig.ConfigurationError(
- "section name %s already in use for key" % key)
- st = info.sectiontype
- if st.isabstract():
- try:
- st = st.getsubtype(type)
- except ZConfig.ConfigurationError:
- raise ZConfig.ConfigurationError(
- "section type %s not allowed for name %s"
- % (`type`, `key`))
- if not st.name == type:
- raise ZConfig.ConfigurationError(
- "name %s must be used for a %s section"
- % (`name`, `st.name`))
- return info
- # 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 info
- elif info.sectiontype.isabstract():
- st = info.sectiontype
- if st.name == type:
- raise ZConfig.ConfigurationError(
- "cannot define section with an abstract type")
- try:
- st = st.getsubtype(type)
- except ZConfig.ConfigurationError:
- # not this one; maybe a different one
- pass
- else:
- return info
- raise ZConfig.ConfigurationError(
- "no matching section defined for type='%s', name='%s'" % (
- type, name))
-
- def isabstract(self):
- return False
-
-
-class SchemaType(SectionType):
- def __init__(self, keytype, valuetype, datatype, handler, url,
- registry):
- SectionType.__init__(self, None, keytype, valuetype, datatype,
- registry, {})
- self._components = {}
- self.handler = handler
- self.url = url
-
- def addtype(self, typeinfo):
- n = typeinfo.name
- 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
-
- def isAllowedName(self, name):
- return False
-
- def issection(self):
- return True
-
- def getunusedtypes(self):
- alltypes = self.gettypenames()
- reqtypes = self.getrequiredtypes()
- for n in reqtypes:
- alltypes.remove(n)
- 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, keytype, valuetype, datatype):
- if isinstance(base, SchemaType):
- raise ZConfig.SchemaError(
- "cannot derive sectiontype from top-level schema")
- t = self.createSectionType(name, keytype, valuetype, datatype)
- t._attrmap.update(base._attrmap)
- t._keymap.update(base._keymap)
- t._children.extend(base._children)
- for i in range(len(t._children)):
- key, info = t._children[i]
- if isinstance(info, BaseKeyInfo) and info.name == "+":
- # need to create a new info object and recompute the
- # default mapping based on the new keytype
- info = copy.copy(info)
- info.computedefault(t.keytype)
- t._children[i] = (key, info)
- 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
Deleted: ZConfig/trunk/loader.py
===================================================================
--- ZConfig/trunk/loader.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/loader.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,307 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Schema loader utility."""
-
-import os.path
-import sys
-import urllib
-import urllib2
-
-import ZConfig
-import ZConfig.cfgparser
-import ZConfig.datatypes
-import ZConfig.info
-import ZConfig.matcher
-import ZConfig.schema
-import ZConfig.url
-
-
-def loadSchema(url):
- return SchemaLoader().loadURL(url)
-
-def loadSchemaFile(file, url=None):
- return SchemaLoader().loadFile(file, url)
-
-def loadConfig(schema, url, overrides=()):
- return _get_config_loader(schema, overrides).loadURL(url)
-
-def loadConfigFile(schema, file, url=None, overrides=()):
- return _get_config_loader(schema, overrides).loadFile(file, url)
-
-
-def _get_config_loader(schema, overrides):
- if overrides:
- from ZConfig import cmdline
- loader = cmdline.ExtendedConfigLoader(schema)
- for opt in overrides:
- loader.addOption(opt)
- else:
- loader = ConfigLoader(schema)
- return loader
-
-
-class BaseLoader:
- def __init__(self):
- pass
-
- def createResource(self, file, url):
- return Resource(file, url)
-
- def loadURL(self, url):
- url = self.normalizeURL(url)
- r = self.openResource(url)
- try:
- return self.loadResource(r)
- finally:
- r.close()
-
- def loadFile(self, file, url=None):
- if not url:
- url = _url_from_file(file)
- r = self.createResource(file, url)
- try:
- return self.loadResource(r)
- finally:
- r.close()
-
- # utilities
-
- def loadResource(self, resource):
- raise NotImplementedError(
- "BaseLoader.loadResource() must be overridden by a subclass")
-
- def openResource(self, url):
- # ConfigurationError exceptions raised here should be
- # str()able to generate a message for an end user.
- #
- # XXX This should be replaced to use a local cache for remote
- # resources. The policy needs to support both re-retrieve on
- # change and provide the cached resource when the remote
- # resource is not accessible.
- url = str(url)
- try:
- file = urllib2.urlopen(url)
- except urllib2.URLError, e:
- # urllib2.URLError has a particularly hostile str(), so we
- # generally don't want to pass it along to the user.
- self._raise_open_error(url, e.reason)
- except (IOError, OSError), e:
- # Python 2.1 raises a different error from Python 2.2+,
- # so we catch both to make sure we detect the situation.
- self._raise_open_error(url, str(e))
- return self.createResource(file, url)
-
- def _raise_open_error(self, url, message):
- if url[:7].lower() == "file://":
- what = "file"
- ident = urllib.url2pathname(url[7:])
- else:
- what = "URL"
- ident = url
- raise ZConfig.ConfigurationError(
- "error opening %s %s: %s" % (what, ident, message),
- url)
-
- def normalizeURL(self, url):
- if self.isPath(url):
- url = "file://" + urllib.pathname2url(os.path.abspath(url))
- newurl, fragment = ZConfig.url.urldefrag(url)
- if fragment:
- raise ZConfig.ConfigurationError(
- "fragment identifiers are not supported",
- url)
- return newurl
-
- def isPath(self, s):
- """Return True iff 's' should be handled as a filesystem path."""
- if ":" in s:
- # XXX This assumes that one-character scheme identifiers
- # are always Windows drive letters; I don't know of any
- # one-character scheme identifiers.
- scheme, rest = urllib.splittype(s)
- return len(scheme) == 1
- else:
- return True
-
-
-
-def _url_from_file(file):
- name = getattr(file, "name", None)
- if name and name[0] != "<" and name[-1] != ">":
- return "file://" + urllib.pathname2url(os.path.abspath(name))
- else:
- return None
-
-
-class SchemaLoader(BaseLoader):
- def __init__(self, registry=None):
- if registry is None:
- registry = ZConfig.datatypes.Registry()
- BaseLoader.__init__(self)
- self.registry = registry
- self._cache = {}
-
- def loadResource(self, resource):
- if resource.url and self._cache.has_key(resource.url):
- schema = self._cache[resource.url]
- else:
- schema = ZConfig.schema.parseResource(resource, self)
- self._cache[resource.url] = schema
- return schema
-
- # schema parser support API
-
- def schemaComponentSource(self, package, file):
- parts = package.split(".")
- if not parts:
- raise ZConfig.SchemaError(
- "illegal schema component name: " + `package`)
- if "" in parts:
- # '' somewhere in the package spec; still illegal
- raise ZConfig.SchemaError(
- "illegal schema component name: " + `package`)
- file = file or "component.xml"
- try:
- __import__(package)
- except ImportError, e:
- raise ZConfig.SchemaResourceError(
- "could not load package %s: %s" % (package, str(e)),
- filename=file,
- package=package)
- pkg = sys.modules[package]
- if not hasattr(pkg, "__path__"):
- raise ZConfig.SchemaResourceError(
- "import name does not refer to a package",
- filename=file, package=package)
- for dir in pkg.__path__:
- dirname = os.path.abspath(dir)
- fn = os.path.join(dirname, file)
- if os.path.exists(fn):
- return "file://" + urllib.pathname2url(fn)
- else:
- raise ZConfig.SchemaResourceError("schema component not found",
- filename=file,
- package=package,
- path=pkg.__path__)
-
-
-class ConfigLoader(BaseLoader):
- def __init__(self, schema):
- if schema.isabstract():
- raise ZConfig.SchemaError(
- "cannot check a configuration an abstract type")
- BaseLoader.__init__(self)
- self.schema = schema
- self._private_schema = False
-
- def loadResource(self, resource):
- sm = self.createSchemaMatcher()
- self._parse_resource(sm, resource)
- result = sm.finish(), CompositeHandler(sm.handlers, self.schema)
- return result
-
- def createSchemaMatcher(self):
- return ZConfig.matcher.SchemaMatcher(self.schema)
-
- # config parser support API
-
- def startSection(self, parent, type, name):
- t = self.schema.gettype(type)
- if t.isabstract():
- raise ZConfig.ConfigurationError(
- "concrete sections cannot match abstract section types;"
- " found abstract type " + `type`)
- return parent.createChildMatcher(t, name)
-
- 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)
- try:
- self._parse_resource(section, r, defines)
- finally:
- r.close()
-
- # internal helper
-
- def _parse_resource(self, matcher, resource, defines=None):
- parser = ZConfig.cfgparser.ZConfigParser(resource, self, defines)
- parser.parse(matcher)
-
-
-class CompositeHandler:
-
- def __init__(self, handlers, schema):
- self._handlers = handlers
- self._convert = schema.registry.get("basic-key")
-
- def __call__(self, handlermap):
- d = {}
- for name, callback in handlermap.items():
- n = self._convert(name)
- if d.has_key(n):
- raise ZConfig.ConfigurationError(
- "handler name not unique when converted to a basic-key: "
- + `name`)
- d[n] = callback
- L = []
- for handler, value in self._handlers:
- if not d.has_key(handler):
- L.append(handler)
- if L:
- raise ZConfig.ConfigurationError(
- "undefined handlers: " + ", ".join(L))
- for handler, value in self._handlers:
- f = d[handler]
- if f is not None:
- f(value)
-
- def __len__(self):
- return len(self._handlers)
-
-
-class Resource:
- def __init__(self, file, url):
- self.file = file
- self.url = url
-
- def close(self):
- if self.file is not None:
- self.file.close()
- self.file = None
- self.closed = True
-
- def __getattr__(self, name):
- return getattr(self.file, name)
Deleted: ZConfig/trunk/matcher.py
===================================================================
--- ZConfig/trunk/matcher.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/matcher.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,302 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Utility that manages the binding of configuration data to a section."""
-
-import ZConfig
-
-from ZConfig.info import ValueInfo
-
-
-class BaseMatcher:
- def __init__(self, info, type, handlers):
- self.info = info
- self.type = type
- self._values = {}
- for key, info in type:
- if info.name == "+" and not info.issection():
- v = {}
- elif info.ismulti():
- v = []
- else:
- v = None
- assert info.attribute is not None
- self._values[info.attribute] = v
- self._sectionnames = {}
- if handlers is None:
- handlers = []
- self.handlers = handlers
-
- def __repr__(self):
- clsname = self.__class__.__name__
- extra = "type " + `self.type.name`
- return "<%s for %s>" % (clsname, extra)
-
- def addSection(self, type, name, sectvalue):
- if name:
- if self._sectionnames.has_key(name):
- raise ZConfig.ConfigurationError(
- "section names must not be re-used within the"
- " same container:" + `name`)
- self._sectionnames[name] = name
- ci = self.type.getsectioninfo(type, name)
- attr = ci.attribute
- v = self._values[attr]
- if ci.ismulti():
- v.append(sectvalue)
- elif v is None:
- self._values[attr] = sectvalue
- else:
- raise ZConfig.ConfigurationError(
- "too many instances of %s section" % `ci.sectiontype.name`)
-
- def addValue(self, key, value, position):
- try:
- realkey = self.type.keytype(key)
- except ValueError, e:
- raise ZConfig.DataConversionError(e, key, position)
- arbkey_info = None
- for i in range(len(self.type)):
- k, ci = self.type[i]
- if k == realkey:
- break
- if ci.name == "+" and not ci.issection():
- arbkey_info = k, ci
- else:
- if arbkey_info is None:
- raise ZConfig.ConfigurationError(
- `key` + " is not a known key name")
- k, ci = arbkey_info
- if ci.issection():
- if ci.name:
- extra = " in %s sections" % `self.type.name`
- else:
- extra = ""
- raise ZConfig.ConfigurationError(
- "%s is not a valid key name%s" % (`key`, extra))
-
- ismulti = ci.ismulti()
- attr = ci.attribute
- assert attr is not None
- v = self._values[attr]
- if v is None:
- if k == '+':
- v = {}
- elif ismulti:
- v = []
- self._values[attr] = v
- elif not ismulti:
- if k != '+':
- raise ZConfig.ConfigurationError(
- `key` + " does not support multiple values")
- elif len(v) == ci.maxOccurs:
- raise ZConfig.ConfigurationError(
- "too many values for " + `name`)
-
- value = ValueInfo(value, position)
- if k == '+':
- if ismulti:
- if v.has_key(realkey):
- v[realkey].append(value)
- else:
- v[realkey] = [value]
- else:
- if v.has_key(realkey):
- raise ZConfig.ConfigurationError(
- "too many values for " + `key`)
- v[realkey] = value
- elif ismulti:
- v.append(value)
- else:
- self._values[attr] = value
-
- def createChildMatcher(self, type, name):
- ci = self.type.getsectioninfo(type.name, name)
- assert not ci.isabstract()
- if not ci.isAllowedName(name):
- raise ZConfig.ConfigurationError(
- "%s is not an allowed name for %s sections"
- % (`name`, `ci.sectiontype.name`))
- return SectionMatcher(ci, type, name, self.handlers)
-
- def finish(self):
- """Check the constraints of the section and convert to an application
- object."""
- values = self._values
- for key, ci in self.type:
- if key:
- key = repr(key)
- else:
- key = "section type " + `ci.sectiontype.name`
- assert ci.attribute is not None
- attr = ci.attribute
- v = values[attr]
- if ci.name == '+' and not ci.issection():
- # v is a dict
- if ci.minOccurs > len(v):
- raise ZConfig.ConfigurationError(
- "no keys defined for the %s key/value map; at least %d"
- " must be specified" % (attr, ci.minOccurs))
- if v is None and ci.minOccurs:
- default = ci.getdefault()
- if default is None:
- raise ZConfig.ConfigurationError(
- "no values for %s; %s required" % (key, ci.minOccurs))
- else:
- v = values[attr] = default[:]
- if ci.ismulti():
- if not v:
- default = ci.getdefault()
- if isinstance(default, dict):
- v.update(default)
- else:
- v[:] = default
- if len(v) < ci.minOccurs:
- raise ZConfig.ConfigurationError(
- "not enough values for %s; %d found, %d required"
- % (key, len(v), ci.minOccurs))
- if v is None and not ci.issection():
- if ci.ismulti():
- v = ci.getdefault()[:]
- else:
- v = ci.getdefault()
- values[attr] = v
- return self.constuct()
-
- def constuct(self):
- values = self._values
- for name, ci in self.type:
- assert ci.attribute is not None
- attr = ci.attribute
- if ci.ismulti():
- if ci.issection():
- v = []
- for s in values[attr]:
- if s is not None:
- st = s.getSectionDefinition()
- try:
- s = st.datatype(s)
- except ValueError, e:
- raise ZConfig.DataConversionError(
- e, s, (-1, -1, None))
- v.append(s)
- elif ci.name == '+':
- v = values[attr]
- for key, val in v.items():
- v[key] = [vi.convert(ci.datatype) for vi in val]
- else:
- v = [vi.convert(ci.datatype) for vi in values[attr]]
- elif ci.issection():
- if values[attr] is not None:
- st = values[attr].getSectionDefinition()
- try:
- v = st.datatype(values[attr])
- except ValueError, e:
- raise ZConfig.DataConversionError(
- e, values[attr], (-1, -1, None))
- else:
- v = None
- elif name == '+':
- v = values[attr]
- if not v:
- for key, val in ci.getdefault().items():
- v[key] = val.convert(ci.datatype)
- else:
- for key, val in v.items():
- v[key] = val.convert(ci.datatype)
- else:
- v = values[attr]
- if v is not None:
- v = v.convert(ci.datatype)
- values[attr] = v
- if ci.handler is not None:
- self.handlers.append((ci.handler, v))
- return self.createValue()
-
- def createValue(self):
- return SectionValue(self._values, None, self)
-
-
-class SectionMatcher(BaseMatcher):
- def __init__(self, info, type, name, handlers):
- if name or info.allowUnnamed():
- self.name = name
- else:
- raise ZConfig.ConfigurationError(
- `type.name` + " sections may not be unnamed")
- BaseMatcher.__init__(self, info, type, handlers)
-
- def createValue(self):
- return SectionValue(self._values, self.name, self)
-
-
-class SchemaMatcher(BaseMatcher):
- def __init__(self, schema):
- BaseMatcher.__init__(self, schema, schema, [])
-
- def finish(self):
- # Since there's no outer container to call datatype()
- # for the schema, we convert on the way out.
- v = BaseMatcher.finish(self)
- v = self.type.datatype(v)
- if self.type.handler is not None:
- self.handlers.append((self.type.handler, v))
- return v
-
-
-class SectionValue:
- """Generic 'bag-of-values' object for a section.
-
- Derived classes should always call the SectionValue constructor
- before attempting to modify self.
- """
-
- def __init__(self, values, name, matcher):
- self.__dict__.update(values)
- self._name = name
- self._matcher = matcher
- self._attributes = tuple(values.keys())
-
- def __repr__(self):
- if self._name:
- # probably unique for a given config file; more readable than id()
- name = `self._name`
- else:
- # identify uniquely
- name = "at %#x" % id(self)
- clsname = self.__class__.__name__
- return "<%s for %s %s>" % (clsname, self._matcher.type.name, name)
-
- def __str__(self):
- l = []
- attrnames = [s for s in self.__dict__.keys() if s[0] != "_"]
- attrnames.sort()
- for k in attrnames:
- v = getattr(self, k)
- l.append('%-40s: %s' % (k, v))
- return '\n'.join(l)
-
- def getSectionName(self):
- return self._name
-
- def getSectionType(self):
- return self._matcher.type.name
-
- def getSectionDefinition(self):
- return self._matcher.type
-
- def getSectionMatcher(self):
- return self._matcher
-
- def getSectionAttributes(self):
- return self._attributes
Deleted: ZConfig/trunk/schema.py
===================================================================
--- ZConfig/trunk/schema.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/schema.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,582 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Parser for ZConfig schemas."""
-
-import os
-import xml.sax
-
-import ZConfig
-
-from ZConfig import info
-from ZConfig import 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
- return `ob`[1:]
- else:
- return `ob`
-
-
-class BaseParser(xml.sax.ContentHandler):
-
- _cdata_tags = "description", "metadefault", "example", "default"
- _handled_tags = ("import", "abstracttype", "sectiontype",
- "key", "multikey", "section", "multisection")
-
- _allowed_parents = {
- "description": ["key", "section", "multikey", "multisection",
- "sectiontype", "abstracttype",
- "schema", "component"],
- "example": ["key", "section", "multikey", "multisection"],
- "metadefault": ["key", "section", "multikey", "multisection"],
- "default": ["key", "multikey"],
- "import": ["schema", "component"],
- "abstracttype": ["schema", "component"],
- "sectiontype": ["schema", "component"],
- "key": ["schema", "sectiontype"],
- "multikey": ["schema", "sectiontype"],
- "section": ["schema", "sectiontype"],
- "multisection": ["schema", "sectiontype"],
- }
-
- def __init__(self, loader, url):
- self._registry = loader.registry
- self._loader = loader
- 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._elem_stack = []
-
- # SAX 2 ContentHandler methods
-
- def setDocumentLocator(self, locator):
- self._locator = locator
-
- def startElement(self, name, attrs):
- attrs = dict(attrs)
- if self._elem_stack:
- parent = self._elem_stack[-1]
- if not self._allowed_parents.has_key(name):
- self.error("Unknown tag " + name)
- if parent not in self._allowed_parents[name]:
- self.error("%s elements may not be nested in %s elements"
- % (_srepr(name), _srepr(parent)))
- elif name != self._top_level:
- self.error("Unknown document type " + name)
- self._elem_stack.append(name)
- if name == self._top_level:
- if self._schema is not None:
- self.error("schema element improperly nested")
- getattr(self, "start_" + name)(attrs)
- elif name in self._handled_tags:
- if self._schema is None:
- self.error(name + " element outside of schema")
- getattr(self, "start_" + name)(attrs)
- elif name in self._cdata_tags:
- if self._schema is None:
- self.error(name + " element outside of schema")
- if self._cdata is not None:
- self.error(name + " element improperly nested")
- self._cdata = []
- self._position = None
- self._attrs = attrs
-
- def characters(self, data):
- if self._cdata is not None:
- if self._position is None:
- self._position = self.get_position()
- self._cdata.append(data)
- elif data.strip():
- self.error("unexpected non-blank character data: "
- + `data.strip()`)
-
- def endElement(self, name):
- del self._elem_stack[-1]
- if name in self._handled_tags:
- getattr(self, "end_" + name)()
- else:
- data = ''.join(self._cdata).strip()
- self._cdata = None
- getattr(self, "characters_" + name)(data)
-
- def endDocument(self):
- if self._schema is None:
- self.error("no %s found" % self._top_level)
-
- # helper methods
-
- def get_position(self):
- if self._locator:
- return (self._locator.getLineNumber(),
- self._locator.getColumnNumber(),
- (self._locator.getSystemId() or self._url))
- else:
- return None, None, self._url
-
- def get_handler(self, attrs):
- v = attrs.get("handler")
- if v is None:
- return v
- else:
- return self.basic_key(v)
-
- def push_prefix(self, attrs):
- name = attrs.get("prefix")
- if name:
- if self._prefixes:
- convert = self._registry.get("dotted-suffix")
- else:
- convert = self._registry.get("dotted-name")
- try:
- name = convert(name)
- except ValueError, err:
- self.error("not a valid prefix: %s (%s)"
- % (_srepr(name), str(err)))
- if name[0] == ".":
- prefix = self._prefixes[-1] + name
- else:
- prefix = name
- elif self._prefixes:
- prefix = self._prefixes[-1]
- else:
- prefix = ''
- self._prefixes.append(prefix)
-
- def pop_prefix(self):
- del self._prefixes[-1]
-
- def get_classname(self, name):
- name = str(name)
- if name.startswith("."):
- return self._prefixes[-1] + name
- else:
- return name
-
- def get_datatype(self, attrs, attrkey, default, base=None):
- if attrs.has_key(attrkey):
- dtname = self.get_classname(attrs[attrkey])
- else:
- convert = getattr(base, attrkey, None)
- if convert is not None:
- return convert
- dtname = default
-
- try:
- return self._registry.get(dtname)
- except ValueError, e:
- self.error(e[0])
-
- def get_sect_typeinfo(self, attrs, base=None):
- keytype = self.get_datatype(attrs, "keytype", "basic-key", base)
- valuetype = self.get_datatype(attrs, "valuetype", "string")
- datatype = self.get_datatype(attrs, "datatype", "null", base)
- return keytype, valuetype, datatype
-
- def get_required(self, attrs):
- if attrs.has_key("required"):
- v = attrs["required"]
- if v == "yes":
- return True
- elif v == "no":
- return False
- self.error("value for 'required' must be 'yes' or 'no'")
- else:
- return False
-
- def get_ordinality(self, attrs):
- # used by start_multi*()
- min, max = 0, info.Unbounded
- if self.get_required(attrs):
- min = 1
- return min, max
-
- def get_sectiontype(self, attrs):
- type = attrs.get("type")
- if not type:
- self.error("section must specify type")
- return self._schema.gettype(type)
-
- def get_key_info(self, attrs, element):
- any, name, attribute = self.get_name_info(attrs, element)
- if any == '*':
- self.error(element + " may not specify '*' for name")
- if not name and any != '+':
- self.error(element + " name may not be omitted or empty")
- datatype = self.get_datatype(attrs, "datatype", "string")
- handler = self.get_handler(attrs)
- return name or any, datatype, handler, attribute
-
- def get_name_info(self, attrs, element, default=None):
- name = attrs.get("name", default)
- if not name:
- self.error(element + " name must be specified and non-empty")
- aname = attrs.get("attribute")
- if aname:
- aname = self.identifier(aname)
- if aname.startswith("getSection"):
- # reserved; used for SectionValue methods to get meta-info
- self.error("attribute names may not start with 'getSection'")
- if name in ("*", "+"):
- if not aname:
- self.error(
- "container attribute must be specified and non-empty"
- " when using '*' or '+' for a section name")
- return name, None, aname
- else:
- # run the keytype converter to make sure this is a valid key
- try:
- name = self._stack[-1].keytype(name)
- except ValueError, e:
- self.error("could not convert key name to keytype: " + str(e))
- if not aname:
- aname = self.basic_key(name)
- aname = self.identifier(aname.replace('-', '_'))
- return None, name, aname
-
- # schema loading logic
-
- def characters_default(self, data):
- key = self._attrs.get("key")
- self._stack[-1].adddefault(data, self._position, key)
-
- def characters_description(self, data):
- if self._stack[-1].description is not None:
- self.error(
- "at most one <description> may be used for each element")
- self._stack[-1].description = data
-
- def characters_example(self, data):
- self._stack[-1].example = data
-
- def characters_metadefault(self, data):
- self._stack[-1].metadefault = data
-
- def start_import(self, attrs):
- src = attrs.get("src", "").strip()
- pkg = attrs.get("package", "").strip()
- file = attrs.get("file", "").strip()
- if not (src or pkg):
- self.error("import must specify either src or package")
- if src and pkg:
- self.error("import may only specify one of src or package")
- if src:
- if file:
- self.error("import may not specify file and src")
- src = url.urljoin(self._url, src)
- src, fragment = url.urldefrag(src)
- if fragment:
- self.error("import src many not include"
- " a fragment identifier")
- schema = self._loader.loadURL(src)
- for n in schema.gettypenames():
- self._schema.addtype(schema.gettype(n))
- else:
- if os.path.dirname(file):
- self.error("file may not include a directory part")
- pkg = self.get_classname(pkg)
- src = self._loader.schemaComponentSource(pkg, file)
- 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._loader, src, self._schema)
- try:
- xml.sax.parse(r.file, parser)
- finally:
- r.close()
-
- def end_import(self):
- pass
-
- def start_sectiontype(self, attrs):
- name = attrs.get("name")
- if not name:
- self.error("sectiontype name must not be omitted or empty")
- name = self.basic_key(name)
- self.push_prefix(attrs)
- if attrs.has_key("extends"):
- basename = self.basic_key(attrs["extends"])
- base = self._schema.gettype(basename)
- if base.isabstract():
- self.error("sectiontype cannot extend an abstract type")
- keytype, valuetype, datatype = self.get_sect_typeinfo(attrs, base)
- sectinfo = self._schema.deriveSectionType(
- base, name, keytype, valuetype, datatype)
- else:
- keytype, valuetype, datatype = self.get_sect_typeinfo(attrs)
- sectinfo = self._schema.createSectionType(
- name, keytype, valuetype, datatype)
- if attrs.has_key("implements"):
- ifname = self.basic_key(attrs["implements"])
- interface = self._schema.gettype(ifname)
- if not interface.isabstract():
- self.error(
- "type specified by implements is not an abstracttype")
- interface.addsubtype(sectinfo)
- self._stack.append(sectinfo)
-
- def end_sectiontype(self):
- self.pop_prefix()
- self._stack.pop()
-
- def start_section(self, attrs):
- sectiontype = self.get_sectiontype(attrs)
- handler = self.get_handler(attrs)
- min = self.get_required(attrs) and 1 or 0
- any, name, attribute = self.get_name_info(attrs, "section", "*")
- if any and not attribute:
- self.error(
- "attribute must be specified if section name is '*' or '+'")
- section = info.SectionInfo(any or name, sectiontype,
- min, 1, handler, attribute)
- self._stack[-1].addsection(name, section)
- self._stack.append(section)
-
- def end_section(self):
- self._stack.pop()
-
- def start_multisection(self, attrs):
- sectiontype = self.get_sectiontype(attrs)
- min, max = self.get_ordinality(attrs)
- any, name, attribute = self.get_name_info(attrs, "multisection", "*")
- if any not in ("*", "+"):
- self.error("multisection must specify '*' or '+' for the name")
- handler = self.get_handler(attrs)
- section = info.SectionInfo(any or name, sectiontype,
- min, max, handler, attribute)
- self._stack[-1].addsection(name, section)
- self._stack.append(section)
-
- def end_multisection(self):
- self._stack.pop()
-
- def start_abstracttype(self, attrs):
- name = attrs.get("name")
- if not name:
- self.error("abstracttype name must not be omitted or empty")
- name = self.basic_key(name)
- abstype = info.AbstractType(name)
- self._schema.addtype(abstype)
- self._stack.append(abstype)
-
- def end_abstracttype(self):
- self._stack.pop()
-
- def start_key(self, attrs):
- name, datatype, handler, attribute = self.get_key_info(attrs, "key")
- min = self.get_required(attrs) and 1 or 0
- key = info.KeyInfo(name, datatype, min, handler, attribute)
- if attrs.has_key("default"):
- if min:
- self.error("required key cannot have a default value")
- key.adddefault(str(attrs["default"]).strip(),
- self.get_position())
- if name != "+":
- key.finish()
- self._stack[-1].addkey(key)
- self._stack.append(key)
-
- def end_key(self):
- key = self._stack.pop()
- if key.name == "+":
- key.computedefault(self._stack[-1].keytype)
- key.finish()
-
- def start_multikey(self, attrs):
- if attrs.has_key("default"):
- self.error("default values for multikey must be given using"
- " 'default' elements")
- name, datatype, handler, attribute = self.get_key_info(attrs,
- "multikey")
- min, max = self.get_ordinality(attrs)
- key = info.MultiKeyInfo(name, datatype, min, max, handler, attribute)
- self._stack[-1].addkey(key)
- self._stack.append(key)
-
- def end_multikey(self):
- multikey = self._stack.pop()
- if multikey.name == "+":
- multikey.computedefault(self._stack[-1].keytype)
- multikey.finish()
-
- # datatype conversion wrappers
-
- def basic_key(self, s):
- try:
- return self._basic_key(s)
- except ValueError, e:
- self.error(e[0])
-
- def identifier(self, s):
- try:
- return self._identifier(s)
- except ValueError, e:
- self.error(e[0])
-
- # exception setup helpers
-
- def initerror(self, e):
- if self._locator is not None:
- e.colno = self._locator.getColumnNumber()
- e.lineno = self._locator.getLineNumber()
- e.url = self._locator.getSystemId()
- return e
-
- def error(self, message):
- raise self.initerror(ZConfig.SchemaError(message))
-
-
-class SchemaParser(BaseParser):
-
- # needed by startElement() and endElement()
- _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)
-
- 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
- self.pop_prefix()
- assert not self._prefixes
-
-
-class ComponentParser(BaseParser):
-
- _handled_tags = BaseParser._handled_tags + ("component",)
- _top_level = "component"
-
- def __init__(self, loader, url, schema):
- BaseParser.__init__(self, loader, url)
- self._parent = schema
-
- def characters_description(self, data):
- if self._stack:
- self._stack[-1].description = data
-
- def start_key(self, attrs):
- self._check_not_toplevel("key")
- BaseParser.start_key(self, attrs)
-
- def start_multikey(self, attrs):
- self._check_not_toplevel("multikey")
- BaseParser.start_multikey(self, attrs)
-
- def start_section(self, attrs):
- self._check_not_toplevel("section")
- BaseParser.start_section(self, attrs)
-
- def start_multisection(self, attrs):
- self._check_not_toplevel("multisection")
- BaseParser.start_multisection(self, attrs)
-
- 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))
Deleted: ZConfig/trunk/substitution.py
===================================================================
--- ZConfig/trunk/substitution.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/substitution.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,86 +0,0 @@
-##############################################################################
-#
-# 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.1 (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.
-#
-##############################################################################
-"""Substitution support for ZConfig values."""
-
-import ZConfig
-
-
-def substitute(s, mapping):
- """Interpolate variables from `mapping` into `s`."""
- if "$" in s:
- result = ''
- rest = s
- while rest:
- p, name, namecase, rest = _split(rest)
- result += p
- if name:
- v = mapping.get(name)
- if v is None:
- raise ZConfig.SubstitutionReplacementError(s, namecase)
- result += v
- return result
- else:
- return s
-
-
-def isname(s):
- """Return True iff s is a valid substitution name."""
- m = _name_match(s)
- if m:
- return m.group() == s
- else:
- return False
-
-
-def _split(s):
- # Return a four tuple: prefix, name, namecase, suffix
- # - prefix is text that can be used literally in the result (may be '')
- # - name is a referenced name, or None
- # - namecase is the name with case preserved
- # - suffix is trailling text that may contain additional references
- # (may be '' or None)
- if "$" in s:
- i = s.find("$")
- c = s[i+1:i+2]
- if c == "":
- raise ZConfig.SubstitutionSyntaxError(
- "illegal lone '$' at end of source")
- if c == "$":
- return s[:i+1], None, None, s[i+2:]
- prefix = s[:i]
- if c == "{":
- m = _name_match(s, i + 2)
- if not m:
- raise ZConfig.SubstitutionSyntaxError(
- "'${' not followed by name")
- name = m.group(0)
- i = m.end() + 1
- if not s.startswith("}", i - 1):
- raise ZConfig.SubstitutionSyntaxError(
- "'${%s' not followed by '}'" % name)
- else:
- m = _name_match(s, i+1)
- if not m:
- raise ZConfig.SubstitutionSyntaxError(
- "'$' not followed by '$' or name")
- name = m.group(0)
- i = m.end()
- return prefix, name.lower(), name, s[i:]
- else:
- return s, None, None, None
-
-
-import re
-_name_match = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*").match
-del re
Deleted: ZConfig/trunk/url.py
===================================================================
--- ZConfig/trunk/url.py 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/url.py 2005-09-19 20:22:48 UTC (rev 38533)
@@ -1,67 +0,0 @@
-##############################################################################
-#
-# 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.1 (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 urlparse as _urlparse
-
-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):
- lc = url.lower()
- if lc.startswith("file:/") and not lc.startswith("file:///"):
- url = "file://" + url[5:]
- return url
-
-
-def 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:///")):
- url = "file://" + url[5:]
- return url
-
-
-def urldefrag(url):
- url, fragment = _urlparse.urldefrag(url)
- return urlnormalize(url), fragment
-
-
-def urljoin(base, relurl):
- url = _urlparse.urljoin(base, relurl)
- if url.startswith("file:/") and not url.startswith("file:///"):
- url = "file://" + url[5:]
- return url
Added: ZConfig/trunk/zpkg.conf
===================================================================
--- ZConfig/trunk/zpkg.conf 2005-09-19 19:53:54 UTC (rev 38532)
+++ ZConfig/trunk/zpkg.conf 2005-09-19 20:22:48 UTC (rev 38533)
@@ -0,0 +1,8 @@
+collect-dependencies true
+default-collection ZConfig-dist
+release-name ZConfig
+
+<resources>
+ ZConfig ZConfig
+ ZConfig-dist .
+</resources>
Property changes on: ZConfig/trunk/zpkg.conf
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:eol-style
+ native
More information about the ZConfig
mailing list