[Zope3-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 Zope3-Checkins
mailing list