Author: ianb
Date: 2007-10-20 21:43:12 -0600 (Sat, 20 Oct 2007)
New Revision: 3105

Modified:
   FormEncode/trunk/docs/news.txt
   FormEncode/trunk/formencode/validators.py
Log:
Added MACAddress and and CADR from Chrisopher Haas.  Fixed strftime in 
DateValidator, which doesn't like unicode format strings.  Fixed some 
docstrings which had become out of date

Modified: FormEncode/trunk/docs/news.txt
===================================================================
--- FormEncode/trunk/docs/news.txt      2007-10-21 00:34:57 UTC (rev 3104)
+++ FormEncode/trunk/docs/news.txt      2007-10-21 03:43:12 UTC (rev 3105)
@@ -50,6 +50,9 @@
 * Minor fix to setup.py to make FormEncode more friendly with
   zc.buildout.
 
+* Added ``validators.CADR`` (for IP addresses with an optional range)
+  and ``validators.MACAddress`` (from Christoph Haas).
+
 0.7.1
 -----
 

Modified: FormEncode/trunk/formencode/validators.py
===================================================================
--- FormEncode/trunk/formencode/validators.py   2007-10-21 00:34:57 UTC (rev 
3104)
+++ FormEncode/trunk/formencode/validators.py   2007-10-21 03:43:12 UTC (rev 
3105)
@@ -818,14 +818,22 @@
         }
 
     def validate_python(self, value, state):
+        date_format = self.message('date_format', state)
+        if isinstance(date_format, unicode):
+            # strftime doesn't like unicode
+            encoding = 'utf8'
+            date_format = date_format.encode(encoding)
+        else:
+            encoding = None
         if self.earliest_date:
             if callable(self.earliest_date):
                 earliest_date = self.earliest_date()
             else:
                 earliest_date = self.earliest_date
             if value < earliest_date:
-                date_formatted = earliest_date.strftime(
-                    self.message('date_format', state))
+                date_formatted = earliest_date.strftime(date_format)
+                if encoding:
+                    date_formatted = date_formatted.decode(encoding)
                 raise Invalid(
                     self.message('after', state,
                                  date=date_formatted),
@@ -836,8 +844,9 @@
             else:
                 latest_date = self.latest_date
             if value > latest_date:
-                date_formatted = latest_date.strftime(
-                    self.message('date_format', state))
+                date_formatted = latest_date.strftime(date_format)
+                if encoding:
+                    date_formatted = date_formatted.decode(encoding)
                 raise Invalid(
                     self.message('before', state,
                                  date=date_formatted),
@@ -846,8 +855,9 @@
             dt_mod = import_datetime(self.datetime_module)
             now = datetime_now(dt_mod)
             if value < now:
-                date_formatted = now.strftime(
-                    self.message('date_format', state))
+                date_formatted = now.strftime(date_format)
+                if encoding:
+                    date_formatted = date_formatted.decode(encoding)
                 raise Invalid(
                     self.message('future', state,
                                  date=date_formatted),
@@ -860,8 +870,9 @@
             value_as_date = datetime_makedate(
                 dt_mod, value.year, value.month, value.day)
             if value_as_date < today:
-                date_formatted = now.strftime(
-                    self.message('date_format', state))
+                date_formatted = now.strftime(date_format)
+                if encoding:
+                    date_formatted = date_formatted.decode(encoding)
                 raise Invalid(
                     self.message('future', state,
                                  date=date_formatted),
@@ -1090,7 +1101,7 @@
     ::
     
         >>> UnicodeString().to_python(None)
-        ''
+        u''
         >>> UnicodeString().to_python([])
         u''
         >>> UnicodeString(encoding='utf-7').to_python('Ni Ni Ni')
@@ -1322,9 +1333,7 @@
         >>> u.to_python('foo.com')
         'http://foo.com'
         >>> u.to_python('http://hahaha/bar.html')
-        Traceback (most recent call last):
-            ...
-        Invalid: That is not a valid URL
+        'http://hahaha/bar.html'
         >>> u.to_python('https://test.com')
         'https://test.com'
         >>> u = URL(add_http=False, check_exists=True)
@@ -2181,6 +2190,9 @@
                           valueDict, state)
         return field, v
 
+    def is_empty(self, value):
+        ## Empty dictionaries don't really apply here
+        return False
 
 class StringBool(FancyValidator):
     # Originally from TurboGears
@@ -2291,6 +2303,109 @@
             chr(random.randrange(256))
             for i in range(self.nonce_length)])
 
+class CIDR(FancyValidator):
+    """
+    Formencode validator to check whether a string is in correct CIDR
+    notation (IP address, or IP address plus /mask)
+
+    Examples::
+
+        >>> cidr = CIDR()
+        >>> cidr.to_python('127.0.0.1')
+        '127.0.0.1'
+        >>> cidr.to_python('299.0.0.1')
+        Traceback (most recent call last):
+            ...
+        Invalid: The octets must be within the range of 0-255 (not '299')
+        >>> cidr.to_python('192.168.0.1/1')
+        Traceback (most recent call last):
+            ...
+        Invalid: The network size (bits) must be within the range of 8-32 (not 
'1')
+        >>> cidr.to_python('asdf')
+        Traceback (most recent call last):
+            ...
+        Invalid: Please enter a valid IP address (a.b.c.d) or IP network 
(a.b.c.d/e)
+    """
+    messages = {
+            'not_cidr_format' : u'Please enter a valid IP address (a.b.c.d) or 
IP network (a.b.c.d/e)',
+            'illegal_octets' : u'The octets must be within the range of 0-255 
(not %(octet)r)',
+            'illegal_bits' : u'The network size (bits) must be within the 
range of 8-32 (not %(bits)r)',
+            }
+
+    def validate_python(self, value, state):
+        try:
+            # Split into octets and bits
+            if '/' in value: # a.b.c.d/e
+                addr, bits = value.split('/')
+            else: # a.b.c.d
+                addr, bits = value, 32
+                
+            octets = addr.split('.')
+
+            # Only 4 octets?
+            if len(octets) != 4:
+                raise Invalid(self.message("not_cidr_format", state, 
value=value), value, state)
+
+            # Correct octets?
+            for octet in octets:
+                if int(octet) < 0 or int(octet) > 255:
+                    raise Invalid(self.message("illegal_octets", state, 
octet=octet), value, state)
+
+            # Bits (netmask) correct?
+            if int(bits) < 8 or int(bits) > 32:
+                    raise Invalid(self.message("illegal_bits", state, 
bits=bits), value, state)
+
+        # Splitting faild: wrong syntax
+        except ValueError:
+            raise Invalid(self.message("not_cidr_format", state), value, state)
+
+class MACAddress(FancyValidator):
+    """
+    Formencode validator to check whether a string is a correct hardware
+    (MAC) address.
+
+    Examples::
+
+        >>> mac = MacAddress()
+        >>> mac.to_python('aa:bb:cc:dd:ee:ff')
+        'aabbccddeeff'
+        >>> mac.to_python('aa:bb:cc:dd:ee:ff:e')
+        Traceback (most recent call last):
+            ...
+        Invalid: A MAC address must contain 12 digits and A-F; the value you 
gave has 13 characters
+        >>> mac.to_python('aa:bb:cc:dd:ee:fx')
+        Traceback (most recent call last):
+            ...
+        Invalid: MAC addresses may only contain 0-9 and A-F (and optionally 
:), not 'x'
+        >>> MacAddress(add_colons=True).to_python('aabbccddeeff')
+        'aa:bb:cc:dd:ee:ff'
+    """
+
+    strip=True
+    valid_characters = '0123456789abcdefABCDEF'
+    add_colons = False
+    
+    messages = {
+        'bad_length': _(u'A MAC address must contain 12 digits and A-F; the 
value you gave has %(length)s characters'),
+        'bad_character': _(u'MAC addresses may only contain 0-9 and A-F (and 
optionally :), not %(char)r'),
+        }
+
+    def _to_python(self, value, state):
+        address = value.replace(':','') # remove colons
+        address = address.lower()
+        if len(address)!=12:
+            raise Invalid(self.message("bad_length", state, 
length=len(address)), address, state)
+        for char in address:
+            if char not in self.valid_characters:
+                raise Invalid(self.message("bad_character", state, char=char), 
address, state)
+        if self.add_colons:
+            address = '%s:%s:%s:%s:%s:%s' % (
+                address[0:2], address[2:4], address[4:6],
+                address[6:8], address[8:10], address[10:12])
+        return address
+
+    _from_python = _to_python
+
 class FormValidator(FancyValidator):
     """
     A FormValidator is something that can be chained with a


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
FormEncode-CVS mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/formencode-cvs

Reply via email to