[Checkins] SVN: Zope3/trunk/src/zope/ Make schema.Set accept py2.4 sets; add schema.FrozenSet field.

Gary Poster gary at zope.com
Wed Apr 5 16:05:00 EDT 2006


Log message for revision 66580:
  Make schema.Set accept py2.4 sets; add schema.FrozenSet field.
  

Changed:
  U   Zope3/trunk/src/zope/app/form/browser/itemswidgets.py
  U   Zope3/trunk/src/zope/schema/__init__.py
  U   Zope3/trunk/src/zope/schema/_field.py
  U   Zope3/trunk/src/zope/schema/interfaces.py
  U   Zope3/trunk/src/zope/schema/tests/test_setfield.py

-=-
Modified: Zope3/trunk/src/zope/app/form/browser/itemswidgets.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/itemswidgets.py	2006-04-05 19:42:44 UTC (rev 66579)
+++ Zope3/trunk/src/zope/app/form/browser/itemswidgets.py	2006-04-05 20:04:59 UTC (rev 66580)
@@ -191,9 +191,12 @@
 
         # All AbstractCollection fields have a `_type` attribute specifying
         # the type of collection. Use it to generate the correct type,
-        # otherwise return a list. 
+        # otherwise return a list.  TODO: this breaks encapsulation.
         if hasattr(self.context, '_type'):
-            return self.context._type(values)
+            _type = self.context._type
+            if isinstance(_type, tuple):
+                _type = _type[0]
+            return _type(values)
         else:
             return values
 

Modified: Zope3/trunk/src/zope/schema/__init__.py
===================================================================
--- Zope3/trunk/src/zope/schema/__init__.py	2006-04-05 19:42:44 UTC (rev 66579)
+++ Zope3/trunk/src/zope/schema/__init__.py	2006-04-05 20:04:59 UTC (rev 66580)
@@ -19,7 +19,7 @@
 from zope.schema._field import MinMaxLen, Choice
 from zope.schema._field import Bytes, ASCII, BytesLine, ASCIILine
 from zope.schema._field import Text, TextLine, Bool, Int, Float
-from zope.schema._field import Tuple, List, Set
+from zope.schema._field import Tuple, List, Set, FrozenSet
 from zope.schema._field import Password, Dict, Datetime, Date, Timedelta
 from zope.schema._field import SourceText
 from zope.schema._field import Object, URI, Id, DottedName

Modified: Zope3/trunk/src/zope/schema/_field.py
===================================================================
--- Zope3/trunk/src/zope/schema/_field.py	2006-04-05 19:42:44 UTC (rev 66579)
+++ Zope3/trunk/src/zope/schema/_field.py	2006-04-05 20:04:59 UTC (rev 66580)
@@ -30,7 +30,7 @@
 from zope.schema.interfaces import ISourceText
 from zope.schema.interfaces import IInterfaceField
 from zope.schema.interfaces import IBytes, IASCII, IBytesLine, IASCIILine
-from zope.schema.interfaces import IBool, IInt, IFloat, IDatetime
+from zope.schema.interfaces import IBool, IInt, IFloat, IDatetime, IFrozenSet
 from zope.schema.interfaces import IChoice, ITuple, IList, ISet, IDict
 from zope.schema.interfaces import IPassword, IObject, IDate, ITimedelta
 from zope.schema.interfaces import IURI, IId, IFromUnicode
@@ -370,13 +370,22 @@
 class Set(AbstractCollection):
     """A field representing a set."""
     implements(ISet)
-    _type = SetType
+    _type = SetType, set
     def __init__(self, **kw):
         if 'unique' in kw: # set members are always unique
             raise TypeError(
                 "__init__() got an unexpected keyword argument 'unique'")
         super(Set, self).__init__(unique=True, **kw)
 
+class FrozenSet(AbstractCollection):
+    implements(IFrozenSet)
+    _type = frozenset
+    def __init__(self, **kw):
+        if 'unique' in kw: # set members are always unique
+            raise TypeError(
+                "__init__() got an unexpected keyword argument 'unique'")
+        super(FrozenSet, self).__init__(unique=True, **kw)
+
 def _validate_fields(schema, value, errors=None):
     if errors is None:
         errors = []

Modified: Zope3/trunk/src/zope/schema/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/schema/interfaces.py	2006-04-05 19:42:44 UTC (rev 66579)
+++ Zope3/trunk/src/zope/schema/interfaces.py	2006-04-05 20:04:59 UTC (rev 66580)
@@ -396,6 +396,17 @@
 class IUnorderedCollection(ICollection):
     u"""Abstract interface specifying that the value cannot be ordered"""
 
+class IAbstractSet(IUnorderedCollection):
+    u"""An unordered collection of unique values."""
+    
+    unique = Attribute(u"This ICollection interface attribute must be True")
+
+class IAbstractBag(IUnorderedCollection):
+    u"""An unordered collection of values, with no limitations on whether
+    members are unique"""
+    
+    unique = Attribute(u"This ICollection interface attribute must be False")
+
 # Concrete
 
 class ITuple(ISequence):
@@ -406,12 +417,14 @@
     u"""Field containing a value that implements the API of a conventional 
     Python list."""
 
-class ISet(IUnorderedCollection):
+class ISet(IAbstractSet):
     u"""Field containing a value that implements the API of a conventional 
-    Python standard library sets.Set."""
-    
-    unique = Attribute(u"This ICollection interface attribute must be True")
+    Python standard library sets.Set or a Python 2.4+ set."""
 
+class IFrozenSet(IAbstractSet):
+    u"""Field containing a value that implements the API of a conventional 
+    Python 2.4+ frozenset."""
+
 # (end Collections)
 
 class IObject(IField):

Modified: Zope3/trunk/src/zope/schema/tests/test_setfield.py
===================================================================
--- Zope3/trunk/src/zope/schema/tests/test_setfield.py	2006-04-05 19:42:44 UTC (rev 66579)
+++ Zope3/trunk/src/zope/schema/tests/test_setfield.py	2006-04-05 20:04:59 UTC (rev 66580)
@@ -19,9 +19,10 @@
 import sets
 
 from zope.interface import implements, providedBy
-from zope.schema import Field, Set, Int
+from zope.schema import Field, Set, Int, FrozenSet
 from zope.schema.interfaces import IField
-from zope.schema.interfaces import ICollection, IUnorderedCollection, ISet
+from zope.schema.interfaces import (
+    ICollection, IUnorderedCollection, ISet, IFrozenSet, IAbstractSet)
 from zope.schema.interfaces import NotAContainer, RequiredMissing
 from zope.schema.interfaces import WrongContainedType, WrongType, NotUnique
 from zope.schema.interfaces import TooShort, TooLong
@@ -39,12 +40,16 @@
         field.validate(sets.Set())
         field.validate(sets.Set((1, 2)))
         field.validate(sets.Set((3,)))
+        field.validate(set())
+        field.validate(set((1, 2)))
+        field.validate(set((3,)))
 
         self.assertRaises(WrongType, field.validate, [1, 2, 3])
         self.assertRaises(WrongType, field.validate, 'abc')
         self.assertRaises(WrongType, field.validate, 1)
         self.assertRaises(WrongType, field.validate, {})
         self.assertRaises(WrongType, field.validate, (1, 2, 3))
+        self.assertRaises(WrongType, field.validate, frozenset((1, 2, 3)))
 
     def testValidateRequired(self):
         field = Set(title=u'Set field', description=u'',
@@ -52,6 +57,9 @@
         field.validate(sets.Set())
         field.validate(sets.Set((1, 2)))
         field.validate(sets.Set((3,)))
+        field.validate(set())
+        field.validate(set((1, 2)))
+        field.validate(set((3,)))
 
         self.assertRaises(RequiredMissing, field.validate, None)
 
@@ -59,6 +67,7 @@
         missing = object()
         field = Set(required=True, missing_value=missing)
         field.validate(sets.Set())
+        field.validate(set())
 
         self.assertRaises(RequiredMissing, field.validate, missing)
 
@@ -77,9 +86,13 @@
         field.validate(None)
         field.validate(sets.Set((1, 2)))
         field.validate(sets.Set((1, 2, 3)))
+        field.validate(set((1, 2)))
+        field.validate(set((1, 2, 3)))
 
         self.assertRaises(TooShort, field.validate, sets.Set(()))
         self.assertRaises(TooShort, field.validate, sets.Set((3,)))
+        self.assertRaises(TooShort, field.validate, set(()))
+        self.assertRaises(TooShort, field.validate, set((3,)))
 
     def testValidateMaxValues(self):
         field = Set(title=u'Set field', description=u'',
@@ -87,9 +100,13 @@
         field.validate(None)
         field.validate(sets.Set())
         field.validate(sets.Set((1, 2)))
+        field.validate(set())
+        field.validate(set((1, 2)))
 
         self.assertRaises(TooLong, field.validate, sets.Set((1, 2, 3, 4)))
         self.assertRaises(TooLong, field.validate, sets.Set((1, 2, 3)))
+        self.assertRaises(TooLong, field.validate, set((1, 2, 3, 4)))
+        self.assertRaises(TooLong, field.validate, set((1, 2, 3)))
 
     def testValidateMinValuesAndMaxValues(self):
         field = Set(title=u'Set field', description=u'',
@@ -98,9 +115,13 @@
         field.validate(None)
         field.validate(sets.Set((3,)))
         field.validate(sets.Set((1, 2)))
+        field.validate(set((3,)))
+        field.validate(set((1, 2)))
 
         self.assertRaises(TooShort, field.validate, sets.Set())
         self.assertRaises(TooLong, field.validate, sets.Set((1, 2, 3)))
+        self.assertRaises(TooShort, field.validate, set())
+        self.assertRaises(TooLong, field.validate, set((1, 2, 3)))
 
     def testValidateValueTypes(self):
         field = Set(title=u'Set field', description=u'',
@@ -109,13 +130,18 @@
         field.validate(None)
         field.validate(sets.Set((5,)))
         field.validate(sets.Set((2, 3)))
+        field.validate(set((5,)))
+        field.validate(set((2, 3)))
 
         self.assertRaises(WrongContainedType, field.validate, sets.Set(('',)))
         self.assertRaises(WrongContainedType, 
                           field.validate, sets.Set((3.14159,)))
+        self.assertRaises(WrongContainedType, field.validate, set(('',)))
+        self.assertRaises(WrongContainedType, 
+                          field.validate, set((3.14159,)))
 
     def testCorrectValueType(self):
-        # TODO: We should not allow for a None valeu type. 
+        # TODO: We should not allow for a None value type. 
         Set(value_type=None)
 
         # do not allow arbitrary value types
@@ -137,11 +163,128 @@
         field = Set()
         self.failUnless(ISet.providedBy(field))
         self.failUnless(IUnorderedCollection.providedBy(field))
+        self.failUnless(IAbstractSet.providedBy(field))
         self.failUnless(ICollection.providedBy(field))
 
+class FrozenSetTest(FieldTestBase):
+    """Test the Tuple Field."""
+
+    _Field_Factory = FrozenSet
+
+    def testValidate(self):
+        field = FrozenSet(title=u'Set field', description=u'',
+                    readonly=False, required=False)
+        field.validate(None)
+        field.validate(frozenset())
+        field.validate(frozenset((1, 2)))
+        field.validate(frozenset((3,)))
+
+        self.assertRaises(WrongType, field.validate, [1, 2, 3])
+        self.assertRaises(WrongType, field.validate, 'abc')
+        self.assertRaises(WrongType, field.validate, 1)
+        self.assertRaises(WrongType, field.validate, {})
+        self.assertRaises(WrongType, field.validate, (1, 2, 3))
+        self.assertRaises(WrongType, field.validate, set((1, 2, 3)))
+        self.assertRaises(WrongType, field.validate, sets.Set((1, 2, 3)))
+
+    def testValidateRequired(self):
+        field = FrozenSet(title=u'Set field', description=u'',
+                    readonly=False, required=True)
+        field.validate(frozenset())
+        field.validate(frozenset((1, 2)))
+        field.validate(frozenset((3,)))
+
+        self.assertRaises(RequiredMissing, field.validate, None)
+
+    def testValidateRequiredAltMissingValue(self):
+        missing = object()
+        field = FrozenSet(required=True, missing_value=missing)
+        field.validate(frozenset())
+
+        self.assertRaises(RequiredMissing, field.validate, missing)
+
+    def testValidateDefault(self):
+        field = FrozenSet(required=True)
+        field.default = None
+
+    def testValidateDefaultAltMissingValue(self):
+        missing = object()
+        field = FrozenSet(required=True, missing_value=missing)
+        field.default = missing
+
+    def testValidateMinValues(self):
+        field = FrozenSet(title=u'FrozenSet field', description=u'',
+                    readonly=False, required=False, min_length=2)
+        field.validate(None)
+        field.validate(frozenset((1, 2)))
+        field.validate(frozenset((1, 2, 3)))
+
+        self.assertRaises(TooShort, field.validate, frozenset(()))
+        self.assertRaises(TooShort, field.validate, frozenset((3,)))
+
+    def testValidateMaxValues(self):
+        field = FrozenSet(title=u'FrozenSet field', description=u'',
+                          readonly=False, required=False, max_length=2)
+        field.validate(None)
+        field.validate(frozenset())
+        field.validate(frozenset((1, 2)))
+
+        self.assertRaises(TooLong, field.validate, frozenset((1, 2, 3, 4)))
+        self.assertRaises(TooLong, field.validate, frozenset((1, 2, 3)))
+
+    def testValidateMinValuesAndMaxValues(self):
+        field = FrozenSet(title=u'FrozenSet field', description=u'',
+                          readonly=False, required=False,
+                          min_length=1, max_length=2)
+        field.validate(None)
+        field.validate(frozenset((3,)))
+        field.validate(frozenset((1, 2)))
+
+        self.assertRaises(TooShort, field.validate, frozenset())
+        self.assertRaises(TooLong, field.validate, frozenset((1, 2, 3)))
+
+    def testValidateValueTypes(self):
+        field = FrozenSet(title=u'FrozenSet field', description=u'',
+                          readonly=False, required=False,
+                          value_type=Int())
+        field.validate(None)
+        field.validate(frozenset((5,)))
+        field.validate(frozenset((2, 3)))
+
+        self.assertRaises(WrongContainedType, field.validate, frozenset(('',)))
+        self.assertRaises(WrongContainedType, 
+                          field.validate, frozenset((3.14159,)))
+
+    def testCorrectValueType(self):
+        # TODO: We should not allow for a None value type. 
+        FrozenSet(value_type=None)
+
+        # do not allow arbitrary value types
+        self.assertRaises(ValueError, FrozenSet, value_type=object())
+        self.assertRaises(ValueError, FrozenSet, value_type=Field)
+
+        # however, allow anything that implements IField
+        FrozenSet(value_type=Field())
+        class FakeField(object):
+            implements(IField)
+        FrozenSet(value_type=FakeField())
+    
+    def testNoUniqueArgument(self):
+        self.assertRaises(TypeError, FrozenSet, unique=False)
+        self.assertRaises(TypeError, FrozenSet, unique=True)
+        self.failUnless(FrozenSet().unique)
+    
+    def testImplements(self):
+        field = FrozenSet()
+        self.failUnless(IFrozenSet.providedBy(field))
+        self.failUnless(IAbstractSet.providedBy(field))
+        self.failUnless(IUnorderedCollection.providedBy(field))
+        self.failUnless(ICollection.providedBy(field))
+
 def test_suite():
     suite = TestSuite()
     suite.addTest(makeSuite(SetTest))
+    suite.addTest(makeSuite(FrozenSetTest))
     return suite
 
 if __name__ == '__main__':



More information about the Checkins mailing list