[Zope3-checkins] CVS: Zope/lib/python/ZConfig - cfgparser.py:1.6.2.1 datatypes.py:1.5.2.1 loader.py:1.10.2.2 matcher.py:1.4.2.1 schema.py:1.11.2.2 url.py:1.4.2.1

Fred L. Drake, Jr. fred@zope.com
Thu, 23 Jan 2003 17:02:27 -0500


Update of /cvs-repository/Zope/lib/python/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv32578

Modified Files:
      Tag: chrism-install-branch
	cfgparser.py datatypes.py loader.py matcher.py schema.py 
	url.py 
Log Message:
Merge from the ZConfig trunk.

=== Zope/lib/python/ZConfig/cfgparser.py 1.6 => 1.6.2.1 ===
--- Zope/lib/python/ZConfig/cfgparser.py:1.6	Thu Jan  9 11:34:43 2003
+++ Zope/lib/python/ZConfig/cfgparser.py	Thu Jan 23 17:01:52 2003
@@ -13,9 +13,10 @@
 ##############################################################################
 """Configuration parser."""
 
-from ZConfig import ConfigurationError, ConfigurationSyntaxError
+import ZConfig
+import ZConfig.url
+
 from ZConfig.substitution import isname, substitute
-from ZConfig.url import urljoin
 
 try:
     True
@@ -95,7 +96,7 @@
         try:
             newsect = self.context.startSection(section, type, name,
                                                 delegatename)
-        except ConfigurationError, e:
+        except ZConfig.ConfigurationError, e:
             self.error(e[0])
 
         if isempty:
@@ -115,7 +116,7 @@
         try:
             self.context.endSection(
                 prevsection, type, name, delegatename, section)
-        except ConfigurationError, e:
+        except ZConfig.ConfigurationError, e:
             self.error(e[0])
         return prevsection
 
@@ -130,7 +131,7 @@
             value = substitute(value, self.defs)
         try:
             section.addValue(key, value, (self.lineno, None, self.url))
-        except ConfigurationError, e:
+        except ZConfig.ConfigurationError, e:
             self.error(e[0])
 
     def handle_directive(self, section, rest):
@@ -150,7 +151,7 @@
             assert 0, "unexpected directive for " + `"%" + rest`
 
     def handle_include(self, section, rest):
-        newurl = urljoin(self.url, rest)
+        newurl = ZConfig.url.urljoin(self.url, rest)
         self.context.includeConfiguration(section, newurl, self.defs)
 
     def handle_define(self, section, rest):
@@ -166,7 +167,7 @@
         self.defs[defname] = substitute(defvalue, self.defs)
 
     def error(self, message):
-        raise ConfigurationSyntaxError(message, self.url, self.lineno)
+        raise ZConfig.ConfigurationSyntaxError(message, self.url, self.lineno)
 
 
 import re


=== Zope/lib/python/ZConfig/datatypes.py 1.5 => 1.5.2.1 ===
--- Zope/lib/python/ZConfig/datatypes.py:1.5	Thu Jan  9 11:34:43 2003
+++ Zope/lib/python/ZConfig/datatypes.py	Thu Jan 23 17:01:52 2003
@@ -103,32 +103,6 @@
         RegularExpressionConversion.__init__(self, "[_a-zA-Z][_a-zA-Z0-9]*")
 
 
-class LogLevelConversion:
-    # This uses the 'logging' package conventions; only makes sense
-    # for Zope 2.7 (and newer) and Zope 3.  Not sure what the
-    # compatibility should be.
-
-    _levels = {
-        "critical": 50,
-        "fatal": 50,
-        "error": 40,
-        "warn": 30,
-        "info": 20,
-        "debug": 10,
-        "all": 0,
-        }
-
-    def __call__(self, value):
-        s = str(value).lower()
-        if self._levels.has_key(s):
-            return self._levels[s]
-        else:
-            v = int(s)
-            if v < 0 or v > 50:
-                raise ValueError("log level not in range: " + `v`)
-            return v
-
-
 if sys.version[:3] < "2.3":
     def integer(value):
         try:
@@ -154,6 +128,11 @@
         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__
 
 
@@ -200,9 +179,12 @@
                 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"|([^0-9][A-Za-z0-9-_.]+)") # or hostname
+                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):
     if os.path.isdir(v):
         return v
@@ -304,11 +286,11 @@
     "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(),
-    "logging-level":     LogLevelConversion(),
     "inet-address":      inet_address,
     "socket-address":    SocketAddress,
     "ipaddr-or-hostname":IpaddrOrHostname(),
@@ -331,15 +313,24 @@
 
 class Registry:
     __metatype__ = type
-    __slots__ = '_stock', '_other'
+    __slots__ = '_stock', '_other', '_basic_key'
 
     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)


=== Zope/lib/python/ZConfig/loader.py 1.10.2.1 => 1.10.2.2 ===
--- Zope/lib/python/ZConfig/loader.py:1.10.2.1	Mon Jan 13 20:17:27 2003
+++ Zope/lib/python/ZConfig/loader.py	Thu Jan 23 17:01:52 2003
@@ -19,10 +19,11 @@
 import urllib2
 
 import ZConfig
-
-from ZConfig import datatypes
-from ZConfig import matcher
-from ZConfig.url import urlnormalize, urldefrag, urljoin, urlsplit, urlunsplit
+import ZConfig.cfgparser
+import ZConfig.datatypes
+import ZConfig.matcher
+import ZConfig.schema
+import ZConfig.url
 
 try:
     True
@@ -77,13 +78,21 @@
         # change and provide the cached resource when the remote
         # resource is not accessible.
         url = str(url)
-        file = urllib2.urlopen(url)
+        try:
+            file = urllib2.urlopen(url)
+        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.
+            error = ZConfig.ConfigurationError("error opening resource %s: %s"
+                                               % (url, str(e)))
+            error.url = url
+            raise error
         return self.createResource(file, url)
 
     def normalizeURL(self, url):
-        if os.path.exists(url):
+        if os.path.exists(url) or ":" not in url:
             url = "file://" + urllib.pathname2url(os.path.abspath(url))
-        url, fragment = urldefrag(url)
+        url, fragment = ZConfig.url.urldefrag(url)
         if fragment:
             raise ZConfig.ConfigurationError(
                 "fragment identifiers are not supported")
@@ -101,7 +110,7 @@
 class SchemaLoader(BaseLoader):
     def __init__(self, registry=None):
         if registry is None:
-            registry = datatypes.Registry()
+            registry = ZConfig.datatypes.Registry()
         BaseLoader.__init__(self)
         self.registry = registry
         self._cache = {}
@@ -110,8 +119,8 @@
         if resource.url and self._cache.has_key(resource.url):
             schema = self._cache[resource.url]
         else:
-            from ZConfig.schema import parseResource
-            schema = parseResource(resource, self.registry, self)
+            schema = ZConfig.schema.parseResource(resource,
+                                                  self.registry, self)
             self._cache[resource.url] = schema
         return schema
 
@@ -155,9 +164,11 @@
 
     def loadResource(self, resource):
         self.handlers = []
-        sm = matcher.SchemaMatcher(self.schema, self.handlers)
+        sm = ZConfig.matcher.SchemaMatcher(self.schema, self.handlers)
         self._parse_resource(sm, resource)
-        return sm.finish(), CompositeHandler(self.handlers, self.schema)
+        result = sm.finish(), CompositeHandler(self.handlers, self.schema)
+        del self.handlers
+        return result
 
     # config parser support API
 
@@ -175,7 +186,7 @@
             raise ZConfig.ConfigurationError(
                 "%s is not an allowed name for %s sections"
                 % (`name`, `ci.sectiontype.name`))
-        return matcher.SectionMatcher(ci, t, name, self.handlers)
+        return ZConfig.matcher.SectionMatcher(ci, t, name, self.handlers)
 
     def endSection(self, parent, type, name, delegatename, matcher):
         assert not delegatename
@@ -183,14 +194,14 @@
         parent.addSection(type, name, sectvalue)
 
     def includeConfiguration(self, section, url, defines):
+        url = self.normalizeURL(url)
         r = self.openResource(url)
         self._parse_resource(section, r, defines)
 
     # internal helper
 
     def _parse_resource(self, matcher, resource, defines=None):
-        from ZConfig.cfgparser import ZConfigParser
-        parser = ZConfigParser(resource, self, defines)
+        parser = ZConfig.cfgparser.ZConfigParser(resource, self, defines)
         parser.parse(matcher)
 
 


=== Zope/lib/python/ZConfig/matcher.py 1.4 => 1.4.2.1 ===
--- Zope/lib/python/ZConfig/matcher.py:1.4	Mon Jan  6 15:29:33 2003
+++ Zope/lib/python/ZConfig/matcher.py	Thu Jan 23 17:01:52 2003
@@ -57,11 +57,15 @@
                 "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)
         length = len(self.type)
         arbkey_info = None
         for i in range(length):
             k, ci = self.type[i]
-            if k == key:
+            if k == realkey:
                 break
             if ci.name == "+" and not ci.issection():
                 arbkey_info = i, k, ci
@@ -97,15 +101,15 @@
         value = ValueInfo(value, position)
         if k == '+':
             if ismulti:
-                if v.has_key(key):
-                    v[key].append(value)
+                if v.has_key(realkey):
+                    v[realkey].append(value)
                 else:
-                    v[key] = [value]
+                    v[realkey] = [value]
             else:
-                if v.has_key(key):
+                if v.has_key(realkey):
                     raise ZConfig.ConfigurationError(
                         "too many values for " + `key`)
-                v[key] = value
+                v[realkey] = value
         elif ismulti:
             v.append(value)
         else:
@@ -134,7 +138,7 @@
                     if key:
                         s = `key`
                     else:
-                        s = "section type " + `ci.typename`
+                        s = "section type " + `ci.sectiontype.name`
                     raise ZConfig.ConfigurationError(
                         "no values for %s; %s required" % (s, ci.minOccurs))
                 else:


=== Zope/lib/python/ZConfig/schema.py 1.11.2.1 => 1.11.2.2 ===
--- Zope/lib/python/ZConfig/schema.py:1.11.2.1	Mon Jan 13 20:17:27 2003
+++ Zope/lib/python/ZConfig/schema.py	Thu Jan 23 17:01:52 2003
@@ -218,11 +218,14 @@
             return name, None, aname
         else:
             # run the keytype converter to make sure this is a valid key
-            name = self._stack[-1].keytype(name)
+            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, self.basic_key(name), aname
+            return None, name, aname
 
     # schema loading logic
 
@@ -304,6 +307,7 @@
         else:
             sectinfo = self._schema.createSectionType(
                 name, keytype, valuetype, datatype)
+        self._localtypes[name] = sectinfo
         if attrs.has_key("implements"):
             ifname = self.basic_key(attrs["implements"])
             interface = self._schema.gettype(ifname)
@@ -442,41 +446,36 @@
 
 class BaseComponentParser(BaseParser):
 
-    def __init__(self, registry, loader, url, localtypes):
-        self._localtypes = localtypes
+    def __init__(self, registry, loader, url, schema, localtypes):
         BaseParser.__init__(self, registry, loader, url)
+        self._localtypes = localtypes
+        self._parent = schema
 
     def characters_description(self, data):
         if self._stack:
             self._stack[-1].description = data
 
     def start_key(self, attrs):
-        if not self._stack:
-            self.error(
-                "cannot define top-level keys in a schema " + self._top_level)
+        self._check_not_toplevel("key")
         BaseParser.start_key(self, attrs)
 
     def start_multikey(self, attrs):
-        if not self._stack:
-            self.error(
-                "cannot define top-level multikeys in a schema "
-                + self._top_level)
+        self._check_not_toplevel("multikey")
         BaseParser.start_multikey(self, attrs)
 
     def start_section(self, attrs):
-        if not self._stack:
-            self.error(
-                "cannot define top-level sections in a schema "
-                + self._top_level)
+        self._check_not_toplevel("section")
         BaseParser.start_section(self, attrs)
 
     def start_multisection(self, attrs):
-        if not self._stack:
-            self.error(
-                "cannot define top-level multisections in a schema "
-                + self._top_level)
+        self._check_not_toplevel("multisection")
         BaseParser.start_multisection(self, attrs)
 
+    def _check_not_toplevel(self, what):
+        if not self._stack:
+            self.error("cannot define top-level %s in a schema %s"
+                       % (what, self._top_level))
+
 
 class ComponentParser(BaseComponentParser):
 
@@ -484,8 +483,7 @@
     _top_level = "component"
 
     def __init__(self, registry, loader, url, schema):
-        BaseComponentParser.__init__(self, registry, loader, url, {})
-        self._parent = schema
+        BaseComponentParser.__init__(self, registry, loader, url, schema, {})
 
     def start_component(self, attrs):
         self._schema = self._parent
@@ -505,10 +503,6 @@
 
     _handled_tags = BaseComponentParser._handled_tags + ("extension",)
     _top_level = "extension"
-
-    def __init__(self, registry, loader, url, schema, localtypes):
-        BaseComponentParser.__init__(self, registry, loader, url, localtypes)
-        self._parent = schema
 
     def start_extension(self, attrs):
         self._schema = self._parent


=== Zope/lib/python/ZConfig/url.py 1.4 => 1.4.2.1 ===
--- Zope/lib/python/ZConfig/url.py:1.4	Wed Jan  8 00:42:45 2003
+++ Zope/lib/python/ZConfig/url.py	Thu Jan 23 17:01:52 2003
@@ -41,12 +41,8 @@
 
 
 def urlnormalize(url):
-    parts = urlsplit(url)
-    if not parts[0]:
-        raise ValueError("invalid URL, or file does not exist:\n"
-                         + repr(url))
-    url = urlunsplit(parts)
-    if url.startswith("file:/") and not url.startswith("file:///"):
+    lc = url.lower()
+    if lc.startswith("file:/") and not lc.startswith("file:///"):
         url = "file://" + url[5:]
     return url