[Zope3-checkins] CVS: Zope3/src/zope/schema - _field.py:1.19

Jim Fulton jim@zope.com
Mon, 28 Jul 2003 18:22:19 -0400


Update of /cvs-repository/Zope3/src/zope/schema
In directory cvs.zope.org:/tmp/cvs-serv30650/src/zope/schema

Modified Files:
	_field.py 
Log Message:
Added URI and Id fields.
Added IFromUnicode implementations to a number of fields.


=== Zope3/src/zope/schema/_field.py 1.18 => 1.19 ===
--- Zope3/src/zope/schema/_field.py:1.18	Sun Jul 13 02:47:28 2003
+++ Zope3/src/zope/schema/_field.py	Mon Jul 28 18:22:14 2003
@@ -17,6 +17,7 @@
 __metaclass__ = type
 
 import warnings
+import re
 
 from zope.interface import classImplements, implements
 from zope.interface.interfaces import IInterface
@@ -33,6 +34,8 @@
 from zope.schema.interfaces import IPassword, IObject
 from zope.schema.interfaces import IEnumeratedDatetime, IEnumeratedTextLine
 from zope.schema.interfaces import IEnumeratedInt, IEnumeratedFloat
+from zope.schema.interfaces import IURI, IId
+from zope.schema.interfaces import IFromUnicode
 
 from zope.schema._bootstrapfields import Field, Container, Iterable, Orderable
 from zope.schema._bootstrapfields import MinMaxLen, Enumerated
@@ -67,10 +70,26 @@
 
 class Bytes(Enumerated, MinMaxLen, Field):
     __doc__ = IBytes.__doc__
-    implements(IBytes)
+    implements(IBytes, IFromUnicode)
 
     _type = str
 
+    def fromUnicode(self, u):
+        """
+        >>> b = Bytes(constraint=lambda v: 'x' in v)
+
+        >>> b.fromUnicode(u" foo x.y.z bat")
+        ' foo x.y.z bat'
+        >>> b.fromUnicode(u" foo y.z bat")
+        Traceback (most recent call last):
+        ...
+        ValidationError: (u'Constraint not satisfied', ' foo y.z bat')
+        
+        """
+        v = str(u)
+        self.validate(v)
+        return v
+
 class BytesLine(Bytes):
     """A Text field with no newlines."""
 
@@ -83,7 +102,7 @@
 
 class Float(Enumerated, Orderable, Field):
     __doc__ = IFloat.__doc__
-    implements(IFloat)
+    implements(IFloat, IFromUnicode)
     _type = float
 
     def __init__(self, *args, **kw):
@@ -95,6 +114,20 @@
                           DeprecationWarning, stacklevel=2)
         super(Float, self).__init__(*args, **kw)
 
+    def fromUnicode(self, u):
+        """
+        >>> f = Float()
+        >>> f.fromUnicode("1.25")
+        1.25
+        >>> f.fromUnicode("1.25.6")
+        Traceback (most recent call last):
+        ...
+        ValueError: invalid literal for float(): 1.25.6
+        """
+        v = float(u)
+        self.validate(v)
+        return v
+
 class EnumeratedFloat(Float):
     __doc__ = IEnumeratedFloat.__doc__
     implements(IEnumeratedFloat)
@@ -245,3 +278,103 @@
 
         finally:
             errors = None
+
+
+_isuri = re.compile(
+    r"[a-zA-z0-9+.-]+://" # scheme
+    r"\S+$"               # non space (should be pickier)
+    ).match
+class URI(BytesLine):
+    """URI schema field
+    """
+
+    implements(IURI, IFromUnicode)
+
+    def _validate(self, value):
+        """
+        >>> uri = URI(__name__='test')
+        >>> uri.validate("http://www.python.org/foo/bar")
+        >>> uri.validate("www.python.org/foo/bar")
+        Traceback (most recent call last):
+        ...
+        ValidationError: ('Invalid uri', 'www.python.org/foo/bar')
+        """
+    
+        super(URI, self)._validate(value)
+        if _isuri(value):
+            return
+
+        raise ValidationError("Invalid uri", value)
+
+    def fromUnicode(self, value):
+        """
+        >>> uri = URI(__name__='test')
+        >>> uri.fromUnicode("http://www.python.org/foo/bar")
+        'http://www.python.org/foo/bar'
+        >>> uri.fromUnicode("          http://www.python.org/foo/bar")
+        'http://www.python.org/foo/bar'
+        >>> uri.fromUnicode("      \\n    http://www.python.org/foo/bar\\n")
+        'http://www.python.org/foo/bar'
+        >>> uri.fromUnicode("http://www.python.org/ foo/bar")
+        Traceback (most recent call last):
+        ...
+        ValidationError: ('Invalid uri', 'http://www.python.org/ foo/bar')
+        """
+        v = str(value.strip())
+        self.validate(v)
+        return v
+
+_isdotted = re.compile(
+    r"([a-zA-Z][a-zA-z0-9_]*)"
+    r"([.][a-zA-Z][a-zA-z0-9_]*)+"
+    r"$" # use the whole line
+    ).match
+class Id(BytesLine):
+    """Id field
+
+    Values of id fields must be either uris or dotted names.
+    """
+
+    implements(IId, IFromUnicode)
+
+    def _validate(self, value):
+        """
+        >>> id = Id(__name__='test')
+        >>> id.validate("http://www.python.org/foo/bar")
+        >>> id.validate("zope.app.content")
+        >>> id.validate("zope.app.content/a")
+        Traceback (most recent call last):
+        ...
+        ValidationError: ('Invalid id', 'zope.app.content/a')
+        >>> id.validate("http://zope.app.content x y")
+        Traceback (most recent call last):
+        ...
+        ValidationError: ('Invalid id', 'http://zope.app.content x y')
+        """
+        super(Id, self)._validate(value)
+        if _isuri(value):
+            return
+        if _isdotted(value):
+            return
+
+        raise ValidationError("Invalid id", value)
+
+    def fromUnicode(self, value):
+        """
+        >>> id = Id(__name__='test')
+        >>> id.fromUnicode("http://www.python.org/foo/bar")
+        'http://www.python.org/foo/bar'
+        >>> id.fromUnicode("http://www.python.org/ foo/bar")
+        Traceback (most recent call last):
+        ...
+        ValidationError: ('Invalid id', 'http://www.python.org/ foo/bar')
+        >>> id.fromUnicode("      \\n x.y.z \\n")
+        'x.y.z'
+
+        """
+        v = str(value.strip())
+        self.validate(v)
+        return v
+
+    
+