[Zope3-checkins] CVS: Packages/ZConfig - datatypes.py:1.1.2.19

Chris McDonough chrism@zope.com
Sat, 21 Dec 2002 23:19:16 -0500


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

Modified Files:
      Tag: zconfig-schema-devel-branch
	datatypes.py 
Log Message:
Added following "stock" datatypes and tests:

"ipaddr-or-hostname":  Validates a valid IP address or hostname.
"existing-directory":  Ensures that a directory by the given name exists.
"existing-path":       Ensures that a path by the given name exists.
"existing-file":       Ensure that a file by the given name exists.
"existing-dirpath":    Ensure that the directory implied by path exists.
"constructor":         Parse a "constructor(1,2,3)" value into klass, pos, kw.
"key-value":           Space-separated key-value pairs in values.

Changed Zope schema to make use of these datatypes.



=== Packages/ZConfig/datatypes.py 1.1.2.18 => 1.1.2.19 ===
--- Packages/ZConfig/datatypes.py:1.1.2.18	Fri Dec 20 15:39:43 2002
+++ Packages/ZConfig/datatypes.py	Sat Dec 21 23:18:45 2002
@@ -15,6 +15,7 @@
 
 import re
 import sys
+import os
 
 try:
     True
@@ -181,13 +182,95 @@
     else:
         return socket.AF_INET, inet_address(s)
 
-
 def float_conversion(v):
     if isinstance(v, type('')) or isinstance(v, type(u'')):
         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"|([^0-9][A-Za-z0-9-_.]+)") # or hostname
+        RegularExpressionConversion.__init__(self, expr)
+
+def existing_directory(v):
+    if os.path.isdir(v):
+        return v
+    raise ValueError, '%s is not an existing directory' % v
+
+def existing_path(v):
+    if os.path.exists(v):
+        return v
+    raise ValueError, '%s is not an existing path' % v
+
+def existing_file(v):
+    if os.path.exists(v):
+        return v
+    raise ValueError, '%s is not an existing file' % v
+
+def existing_dirpath(v):
+    if not os.path.split(v)[0]:
+        # relative pathname
+        return v
+    dir = os.path.dirname(v)
+    if os.path.isdir(dir):
+        return v
+    raise ValueError, ('The directory named as part of the path %s '
+                       'does not exist.')
+
+def parse_constructor(v):
+    parenmsg = (
+        'Invalid constructor (unbalanced parenthesis in "%s")' % v
+        )
+    openparen = v.find('(')
+    if openparen < 0:
+        raise ValueError(parenmsg)
+    klass = v[:openparen]
+    if not v.endswith(')'):
+        raise ValueError(parenmsg)
+    arglist = v[openparen+1:-1]
+    return klass, arglist
+
+def get_arglist(s):
+    # someone could do a better job at this.
+    pos = []
+    kw = {}
+    args = s.split(',')
+    args = filter(None, args)
+    while args:
+        arg = args.pop(0)
+        try:
+            if '=' in arg:
+                k,v=arg.split('=', 1)
+                k = k.strip()
+                v = v.strip()
+                kw[k] = eval(v)
+            else:
+                arg = arg.strip()
+                pos.append(eval(arg))
+        except SyntaxError:
+            if not args:
+                raise
+            args[0] = '%s, %s' % (arg, args[0])
+    return pos, kw
+
+def constructor_conversion(v):
+    klass, arglist = parse_constructor(v)
+    pos, kw = get_arglist(arglist)
+    return klass, pos, kw
+
+def space_sep_key_value_conversion(v):
+    l = v.split(' ', 1)
+    if len(l) < 2:
+        l.append('')
+    return l
 
 stock_datatypes = {
     "boolean":       asBoolean,
@@ -202,6 +285,13 @@
     "logging-level": LogLevelConversion().__call__,
     "inet-address":  inet_address,
     "socket-address":socket_address,
+    "ipaddr-or-hostname":IpaddrOrHostname().__call__,
+    "existing-directory":existing_directory,
+    "existing-path":existing_path,
+    "existing-file":existing_file,
+    "existing-dirpath":existing_dirpath,
+    "constructor":constructor_conversion,
+    "key-value":space_sep_key_value_conversion,
     }
 
 class Registry: