[Zope3-checkins] CVS: Packages/ZConfig - datatypes.py:1.1.2.1 info.py:1.1.2.1 matcher.py:1.1.2.1 SchemaParser.py:1.1.4.8 cfgparser.py:1.1.2.2 DataTypes.py:NONE SchemaInfo.py:NONE SectionMatcher.py:NONE
Fred L. Drake, Jr.
fred@zope.com
Tue, 10 Dec 2002 14:17:55 -0500
Update of /cvs-repository/Packages/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv29433
Modified Files:
Tag: zconfig-schema-devel-branch
SchemaParser.py cfgparser.py
Added Files:
Tag: zconfig-schema-devel-branch
datatypes.py info.py matcher.py
Removed Files:
Tag: zconfig-schema-devel-branch
DataTypes.py SchemaInfo.py SectionMatcher.py
Log Message:
Many module renamings; the Zope 3 proposal is the Right Way.
=== Added File Packages/ZConfig/datatypes.py ===
"""Selection of standard datatypes for ZConfig."""
import re
class TrivialConversion:
"""Datatype that exposes a conversion implemented as a function."""
def __init__(self, conversion):
self.convert = conversion
class MemoizedConversion:
"""Conversion helper that caches the results of expensive conversions."""
def __init__(self, conversion):
self._memo = {}
self._conversion = conversion
def convert(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 convert(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:
def __init__(self, regex):
self._rx = re.compile(regex)
def convert(self, value):
m = self._rx.match(value)
if m and m.group() == value:
return value
else:
raise ValueError("value did not match regular expression: "
+ `value`)
class Locale:
def convert(self, value):
locale = self._get_locale_module()
# get current setting of 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
)
return value
def _get_locale_module(self):
try:
return self._locale
except AttributeError:
try:
import locale
except ImportError:
raise ValueError(
'The locale module could not be imported.\n'
'To use localization options, you must ensure\n'
'that the locale module is compiled into your\n'
'Python installation.'
)
Locale._locale = locale
return locale
class BasicKeyConversion(RegularExpressionConversion):
def __init__(self):
RegularExpressionConversion.__init__(self, "[_a-zA-Z][-._a-zA-Z0-9]*")
def convert(self, value):
return RegularExpressionConversion.convert(self, value).lower()
class IdentifierConversion(RegularExpressionConversion):
def __init__(self):
RegularExpressionConversion.__init__(self, "[_a-zA-Z][_a-zA-Z0-9]*")
stock_datatypes = {
"int": TrivialConversion(int),
"float": TrivialConversion(float),
"str": TrivialConversion(str),
"locale": MemoizedConversion(Locale().convert),
"port-number": RangeCheckedConversion(int, min=1, max=0xffff),
"basic-key": BasicKeyConversion(),
"identifier": IdentifierConversion(),
}
class Registry:
def __init__(self):
self._stock = stock_datatypes.copy()
self._other = {}
def get(self, name):
if name is None:
name = "str"
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, datatype):
if self._stock.has_key(name):
raise ValueError("datatype name conflicts with built-in types: "
+ `name`)
if self._other.has_key(name):
raise ValueError("datatype name already registered:" + `name`)
self._other[name] = datatype
def search(self, name):
if not "." in name:
raise ValueError("unloadable datatype name: " + `name`)
components = name.split('.')
start = components[0]
g = globals()
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)
datatype = package()
self._other[name] = datatype
return datatype
_r = Registry()
get = _r.get
register = _r.register
=== Added File Packages/ZConfig/info.py ===
"""Objects that can describe a ZConfig schema."""
class UnboundedThing:
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 KeyInfo:
"""Information about a single configuration key."""
def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
attribute):
if maxOccurs is not None and maxOccurs < 1:
if maxOccurs < 1:
raise ValueError("maxOccurs must be at least 1")
if minOccurs is not None and minOccurs < maxOccurs:
raise ValueError("minOccurs must be at least maxOccurs")
self.name = name
self.datatype = datatype
self.minOccurs = minOccurs
self.maxOccurs = maxOccurs
self.handler = handler
self.attribute = attribute
self._default = None
self._finished = False
def finish(self):
if self._finished:
raise ValueError("cannot finish KeyInfo more than once")
if self.minOccurs is None:
if self._default is not None:
self.minOccurs = 1
else:
self.minOccurs = 0
self._finished = True
def adddefault(self, value):
if self._finished:
raise ValueError("cannot add default values to finished KeyInfo")
if self.maxOccurs > 1:
if self._default is None:
self._default = [value]
else:
self._default.append(value)
elif self._default is not None:
raise ValueError("cannot set more than one default to key with"
" maxOccurs == 1")
else:
self._default = value
def getdefault(self):
if not self._finished:
raise ValueError("cannot get default value of key before KeyInfo"
" has been completely initialized")
if self._default is None and self.maxOccurs > 1:
return []
else:
return self._default
def hasdefault(self):
return self._default is not None
def ismulti(self):
return self.maxOccurs > 1
def isoptional(self):
return self.minOccurs == 0
def issection(self):
return False
class SectionInfo(KeyInfo):
def __init__(self, name, datatype, minOccurs, maxOccurs, handler,
attribute, keytype, names, nametype):
assert keytype is not None
self.keytype = keytype
self.names = names # '*', '+', or [name1, ...]
self.nametype = nametype
self._children = [] # [(name, info), ...]
KeyInfo.__init__(self, name, datatype, minOccurs, maxOccurs,
handler, attribute)
def _add_child(self, name, thing):
for n, info in self._children:
if name and n == name:
raise ValueError("child name %s already used" % name)
if info.attribute and info.attribute == thing.attribute:
raise ValueError("child attribute name %s already used"
% thing.attribute)
self._children.append((name, thing))
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, name):
if not name:
return None
for n, info in self._children:
if n == name:
return info
else:
return None
def getchildnames(self):
return [n for (n,info) in self._children]
def issection(self):
return True
def allowUnnamed(self):
return self.names == "*"
def isAllowedName(self, name):
if name == "*" or name == "+":
return False
elif self.names == "+":
return bool(name)
elif not name:
return self.names == "*"
else:
return name in self.names
=== Added File Packages/ZConfig/matcher.py ===
"""Utility that manages the binding of configuration data to a section."""
import ZConfig
class SectionMatcher:
def __init__(self, info, name=None):
if name is not None:
self.name = info.nametype.convert(name)
if not info.isAllowedName(self.name):
raise ZConfig.ConfigurationError(
"%s is not an allowed name for %s sections"
% (`name`, `info.name`))
elif info.allowUnnamed():
self.name = None
else:
raise ZConfig.ConfigurationError(
`info.name` + " sections may not be unnamed")
self.info = info
self._values = {}
def addValue(self, key, value):
keyinfo = self.info.getinfo(key)
if keyinfo.issection():
if keyinfo.name:
extra = " in %s sections" % `self.info.name`
else:
extra = ""
raise ZConfig.ConfigurationError(
"%s is not a valid key name%s" % (`key`, extra))
L = self._values.get(key)
if L is None:
L = []
if keyinfo.maxOccurs is None:
L.append(value)
elif len(L) = keyinfo.maxOccurs:
raise ZConfig.ConfigurationError(
"too many values for " + `name`)
else:
L.append(value)
self._values[key] = L
def finish(self):
"""Check the constraints of the section and convert to an application
object."""
values = {}
for key in self.info.getchildnames():
ci = self.info.getinfo(key)
if self._values.has_key(key):
L = self._values[key]
if len(L) < ci.minOccurs:
raise ZConfig.ConfigurationError(
"not enough values for %s; %d found, %d required"
% (`key`, len(L), ci.minOccurs))
else:
L = ci.getdefault()
def constuct(self):
keys = self.info.getchildnames()
values = [None] * len(keys)
for i in range(len(keys)):
name = keys[i]
ci = self.info.getinfo(name)
keys[i] = ci.attribute
if self._values.has_key(name):
L = self._values[key]
elif ci.ismulti():
L = ci.getdefault()
else:
L = [ci.getdefault()]
if ci.ismulti():
values[i] = [ci.datatype.convert(s) for s in L]
else:
assert len(L) == 1
values[i] = ci.datatype.convert(L[0])
v = SectionValue(keys, values)
# XXX Really should delay this until after all the
# XXX sibling SectionValue instances have been created and
# XXX we're ready to construct the parent.
if self.info.handler:
v = self.info.handler(v)
return v
class SectionValue:
"""Generic 'bag-of-values' object for a section."""
def __init__(self, keys, values):
self._keys = keys
self._values = values
def __len__(self):
return len(self._keys)
def __getitem__(self, index):
if isinstance(index, slice):
raise TypeError("SectionValue does not support slicing")
return self._values[index]
def __getattr__(self, name):
try:
i = self._keys.index(name)
except ValueError:
raise AttributeError, name
return self._values[i]
=== Packages/ZConfig/SchemaParser.py 1.1.4.7 => 1.1.4.8 ===
--- Packages/ZConfig/SchemaParser.py:1.1.4.7 Tue Dec 10 11:30:47 2002
+++ Packages/ZConfig/SchemaParser.py Tue Dec 10 14:17:55 2002
@@ -1,19 +1,18 @@
"""Parser for ZConfig schemas."""
-import types
import xml.sax
import ZConfig
-import ZConfig.DataTypes
-from ZConfig.SchemaInfo import SectionInfo, KeyInfo, Unbounded
+from ZConfig import datatypes
+from ZConfig import info
-default_value_type = ZConfig.DataTypes.get("str")
-default_key_type = ZConfig.DataTypes.get("basic-key")
+default_value_type = datatypes.get("str")
+default_key_type = datatypes.get("basic-key")
default_name_type = default_key_type
-_identifier = ZConfig.DataTypes.get("identifier").convert
+_identifier = datatypes.get("identifier").convert
class SchemaParser(xml.sax.ContentHandler):
@@ -98,11 +97,11 @@
if handler:
handler = self.get_classname(handler)
if attrs.has_key("keytype"):
- keytype = ZConfig.DataTypes.get(attrs["keytype"])
+ keytype = datatypes.get(attrs["keytype"])
else:
keytype = default_key_type
- self._schema = SectionInfo(None, None, 1, 1, handler, None,
- keytype, (), None)
+ self._schema = info.SectionInfo(None, None, 1, 1, handler, None,
+ keytype, (), None)
self._sections = [self._schema]
self._stack = [self._schema]
@@ -118,11 +117,11 @@
if not type:
self.doSchemaError("section does not specify type")
if attrs.has_key("keytype"):
- keytype = ZConfig.DataTypes.get(attrs["keytype"])
+ keytype = datatypes.get(attrs["keytype"])
else:
keytype = default_key_type
if attrs.has_key("nametype"):
- nametype = ZConfig.DataTypes.get(attrs["nametype"])
+ nametype = datatypes.get(attrs["nametype"])
else:
nametype = default_name_type
maxOccurs, minOccurs, handler = self.get_common_info(attrs)
@@ -131,8 +130,8 @@
parent = self._stack[-1]
else:
parent = self._schema
- section = SectionInfo(None, None, minOccurs, maxOccurs, handler,
- attribute, keytype, names, nametype)
+ section = info.SectionInfo(None, None, minOccurs, maxOccurs, handler,
+ attribute, keytype, names, nametype)
if any:
parent.addsection(None, section)
else:
@@ -162,15 +161,15 @@
self.doSchemaError("key name may not be omitted or empty")
# run the keytype converter to make sure this is a valid key
name = self._stack[-1].keytype.convert(name)
- datatype = ZConfig.DataTypes.get(attrs.get("type"))
+ datatype = datatypes.get(attrs.get("type"))
maxOccurs, minOccurs, handler = self.get_common_info(attrs)
attribute = attrs.get("attribute")
if attribute:
attribute = _identifier(attribute)
else:
attribute = _identifier(name.replace("-", "_"))
- key = KeyInfo(name, datatype, minOccurs, maxOccurs, handler,
- attribute)
+ key = info.KeyInfo(name, datatype, minOccurs, maxOccurs, handler,
+ attribute)
self._sections[-1].addkey(key)
self._stack.append(key)
@@ -181,7 +180,7 @@
maxOccurs = attrs.get("maxOccurs")
if maxOccurs is not None:
if maxOccurs == "unbounded":
- maxOccurs = Unbounded
+ maxOccurs = info.Unbounded
else:
maxOccurs = int(maxOccurs)
else:
=== Packages/ZConfig/cfgparser.py 1.1.2.1 => 1.1.2.2 ===
--- Packages/ZConfig/cfgparser.py:1.1.2.1 Tue Dec 10 13:50:11 2002
+++ Packages/ZConfig/cfgparser.py Tue Dec 10 14:17:55 2002
@@ -31,11 +31,8 @@
def parse(self, section):
done, line = self.nextline()
while not done:
- if not line:
- # blank line
- pass
- elif line[0] == "#":
- # comment
+ if line[:1] in ("", "#"):
+ # blank line or comment
pass
elif line[:2] == "</":
=== Removed File Packages/ZConfig/DataTypes.py ===
=== Removed File Packages/ZConfig/SchemaInfo.py ===
=== Removed File Packages/ZConfig/SectionMatcher.py ===