[Zope-Checkins] CVS: Packages/ZConfig - Config.py:1.16 __init__.py:1.5 cfgparser.py:1.3 info.py:1.4 matcher.py:1.3 schema.py:1.4

Fred L. Drake, Jr. fred@zope.com
Mon, 6 Jan 2003 14:36:15 -0500


Update of /cvs-repository/Packages/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv8539

Modified Files:
	Config.py __init__.py cfgparser.py info.py matcher.py 
	schema.py 
Log Message:
Values now have location information stored along with the actual text of the
value.  This is used to improve error reporting to the end user.


=== Packages/ZConfig/Config.py 1.15 => 1.16 ===
--- Packages/ZConfig/Config.py:1.15	Fri Jan  3 16:05:51 2003
+++ Packages/ZConfig/Config.py	Mon Jan  6 14:35:41 2003
@@ -102,7 +102,8 @@
             type = type.lower()
             return [sect for sect in self._sections if sect.type == type]
 
-    def addValue(self, key, value):
+    def addValue(self, key, value, position=None):
+        # position is needed for interface compatibility, but isn't used here
         key = key.lower()
         try:
             self._data[key]


=== Packages/ZConfig/__init__.py 1.4 => 1.5 ===
--- Packages/ZConfig/__init__.py:1.4	Fri Jan  3 16:05:51 2003
+++ Packages/ZConfig/__init__.py	Mon Jan  6 14:35:41 2003
@@ -102,6 +102,27 @@
         ConfigurationError.__init__(self, msg)
 
 
+class DataConversionError(ConfigurationError, ValueError):
+    """Raised when a data type conversion function raises ValueError."""
+
+    def __init__(self, exception, value, position):
+        ConfigurationError.__init__(self, str(exception))
+        self.exception = exception
+        self.value = value
+        self.position = position
+        self.lineno, self.colno, self.url = position
+
+    def __str__(self):
+        s = "%s (line %d" % (self.message, self.lineno)
+        if self.colno is not None:
+            s += ", %d" % self.colno
+        if self.url:
+            s += ", in %s)" % self.url
+        else:
+            s += ")"
+        return s
+
+
 class SubstitutionSyntaxError(ConfigurationError):
     """Raised when interpolation source text contains syntactical errors."""
 


=== Packages/ZConfig/cfgparser.py 1.2 => 1.3 ===
--- Packages/ZConfig/cfgparser.py:1.2	Fri Jan  3 16:05:51 2003
+++ Packages/ZConfig/cfgparser.py	Mon Jan  6 14:35:41 2003
@@ -123,7 +123,7 @@
         else:
             value = substitute(value, self.defs)
         try:
-            section.addValue(key, value)
+            section.addValue(key, value, (self.lineno, None, self.url))
         except ConfigurationError, e:
             self.error(e[0])
 


=== Packages/ZConfig/info.py 1.3 => 1.4 ===
--- Packages/ZConfig/info.py:1.3	Mon Jan  6 13:19:38 2003
+++ Packages/ZConfig/info.py	Mon Jan  6 14:35:41 2003
@@ -48,6 +48,19 @@
 Unbounded = UnboundedThing()
 
 
+class ValueInfo:
+    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."""
 
@@ -100,10 +113,11 @@
                 "cannot finish KeyInfo more than once")
         self._finished = True
 
-    def adddefault(self, value):
+    def adddefault(self, value, position):
         if self._finished:
             raise ZConfig.SchemaError(
                 "cannot add default values to finished KeyInfo")
+        value = ValueInfo(value, position)
         if self.maxOccurs > 1:
             if self._default is None:
                 self._default = [value]


=== Packages/ZConfig/matcher.py 1.2 => 1.3 ===
--- Packages/ZConfig/matcher.py:1.2	Fri Jan  3 16:05:51 2003
+++ Packages/ZConfig/matcher.py	Mon Jan  6 14:35:41 2003
@@ -17,6 +17,8 @@
 
 import ZConfig
 
+from ZConfig.info import ValueInfo
+
 
 class BaseMatcher:
     def __init__(self, info, type, handlers):
@@ -54,7 +56,7 @@
             raise ZConfig.ConfigurationError(
                 "too many instances of %s section" % `ci.sectiontype.name`)
 
-    def addValue(self, key, value):
+    def addValue(self, key, value, position):
         length = len(self.type)
         arbkey_info = None
         for i in range(length):
@@ -92,6 +94,7 @@
             raise ZConfig.ConfigurationError(
                 "too many values for " + `name`)
 
+        value = ValueInfo(value, position)
         if k == '+':
             if ismulti:
                 if v.has_key(key):
@@ -165,9 +168,9 @@
                 elif ci.name == '+':
                     v = values[i]
                     for key, val in v.items():
-                        v[key] = [ci.datatype(s) for s in val]
+                        v[key] = [vi.convert(ci.datatype) for vi in val]
                 else:
-                    v = [ci.datatype(s) for s in values[i]]
+                    v = [vi.convert(ci.datatype) for vi in values[i]]
             elif ci.issection():
                 if values[i] is not None:
                     v = values[i]._type.datatype(values[i])
@@ -176,11 +179,11 @@
             elif name == '+':
                 v = values[i]
                 for key, val in v.items():
-                    v[key] = ci.datatype(val)
+                    v[key] = val.convert(ci.datatype)
             else:
                 v = values[i]
                 if v is not None:
-                    v = ci.datatype(v)
+                    v = v.convert(ci.datatype)
             values[i] = v
             if ci.handler is not None:
                 self._handlers.append((ci.handler, v))


=== Packages/ZConfig/schema.py 1.3 => 1.4 ===
--- Packages/ZConfig/schema.py:1.3	Mon Jan  6 13:19:38 2003
+++ Packages/ZConfig/schema.py	Mon Jan  6 14:35:41 2003
@@ -84,11 +84,14 @@
             if self._cdata is not None:
                 self.error(name + " element improperly nested")
             self._cdata = []
+            self._position = None
         else:
             self.error("Unknown tag " + name)
 
     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: "
@@ -102,7 +105,7 @@
             self._cdata = None
             if name == "default":
                 # value for a key
-                self._stack[-1].adddefault(data)
+                self._stack[-1].adddefault(data, self._position)
             else:
                 setattr(self._stack[-1], name, data)
 
@@ -136,6 +139,14 @@
     def end_import(self):
         pass
 
+    def get_position(self):
+        if self._locator:
+            return (self._locator.getLineNumber(),
+                    self._locator.getColumnNumber(),
+                    self._url)
+        else:
+            return None, None, self._url
+
     def get_handler(self, attrs):
         v = attrs.get("handler")
         if v is None:
@@ -313,7 +324,8 @@
         if attrs.has_key("default"):
             if min:
                 self.error("required key cannot have a default value")
-            key.adddefault(str(attrs["default"]).strip())
+            key.adddefault(str(attrs["default"]).strip(),
+                           self.get_position())
         key.finish()
         self._stack[-1].addkey(key)
         self._stack.append(key)