[Zope3-checkins] CVS: Zope3/src/zope/schema - interfaces.py:1.20 vocabulary.py:1.6
Fred L. Drake, Jr.
fred@zope.com
Fri, 30 May 2003 02:10:58 -0400
Update of /cvs-repository/Zope3/src/zope/schema
In directory cvs.zope.org:/tmp/cvs-serv32178/schema
Modified Files:
interfaces.py vocabulary.py
Log Message:
Refactoring of the multi-select vocabulary field:
- define 4 concrete types covering uniqueness constraints (whether a value
may appear multiple times) and ordering support (whether theres
=== Zope3/src/zope/schema/interfaces.py 1.19 => 1.20 ===
--- Zope3/src/zope/schema/interfaces.py:1.19 Wed May 28 13:09:03 2003
+++ Zope3/src/zope/schema/interfaces.py Fri May 30 02:10:58 2003
@@ -398,27 +398,6 @@
)
-class IBaseVocabulary(Interface):
- """Representation of a vocabulary.
-
- At this most basic level, a vocabulary only need to support a test
- for containment. This can be implemented either by __contains__()
- or by sequence __getitem__() (the later only being useful for
- vocabularies which are intrinsically ordered).
- """
-
- def getQuery():
- """Return an IVocabularyQuery object for this vocabulary.
-
- Vocabularies which do not support query must return None.
- """
-
- def getTerm(value):
- """Return the ITerm object for the term 'value'.
-
- If 'value' is not a valid term, this method raises LookupError.
- """
-
class IVocabularyQuery(Interface):
"""Query object for a vocabulary.
@@ -459,18 +438,26 @@
""")
-class IVocabularyTokenized(Interface):
- """Vocabulary that provides support for tokenized representation.
-
- This interface must be used as a mix-in with IBaseVocabulary.
+class IBaseVocabulary(Interface):
+ """Representation of a vocabulary.
- Terms returned from getTerm() and provided by iteration must
- conform to ITokenizedTerm.
+ At this most basic level, a vocabulary only need to support a test
+ for containment. This can be implemented either by __contains__()
+ or by sequence __getitem__() (the later only being useful for
+ vocabularies which are intrinsically ordered).
"""
- def getTermByToken(token):
- """Return an ITokenizedTerm for the passed-in token."""
+ def getQuery():
+ """Return an IVocabularyQuery object for this vocabulary.
+
+ Vocabularies which do not support query must return None.
+ """
+
+ def getTerm(value):
+ """Return the ITerm object for the term 'value'.
+ If 'value' is not a valid term, this method raises LookupError.
+ """
class IIterableVocabulary(Interface):
"""Vocabulary which supports iteration over allowed values.
@@ -497,6 +484,19 @@
"""Vocabulary which is iterable."""
+class IVocabularyTokenized(Interface):
+ """Vocabulary that provides support for tokenized representation.
+
+ This interface must be used as a mix-in with IBaseVocabulary.
+
+ Terms returned from getTerm() and provided by iteration must
+ conform to ITokenizedTerm.
+ """
+
+ def getTermByToken(token):
+ """Return an ITokenizedTerm for the passed-in token."""
+
+
class IVocabularyFieldMixin(Interface):
# Mix-in interface that defines interesting things common to all
# vocabulary fields.
@@ -526,11 +526,45 @@
"""
-class IVocabularyMultiField(IVocabularyFieldMixin, IField):
+class IVocabularyMultiField(IVocabularyFieldMixin, IMinMaxLen, IField):
+ # XXX This is really a base class used in the more specific
+ # IVocabulary*Field interfaces.
"""Field with a value containing selections from a vocabulary..
The value for fields of this type need to support at least
containment checks using 'in' and iteration.
+
+ The length constraint provided by IMinMaxLen constrains the number
+ of elements in the value.
+ """
+
+
+class IVocabularyBagField(IVocabularyMultiField):
+ """Field representing an unordered collection of values from a
+ vocabulary.
+
+ Specific values may be represented more than once.
+ """
+
+class IVocabularyListField(IVocabularyMultiField):
+ """Field representing an ordered collection of values from a
+ vocabulary.
+
+ Specific values may be represented more than once.
+ """
+
+class IVocabularySetField(IVocabularyMultiField):
+ """Field representing an unordered collection of values from a
+ vocabulary.
+
+ Specific values may be represented at most once.
+ """
+
+class IVocabularyUniqueListField(IVocabularyMultiField):
+ """Field representing an ordered collection of values from a
+ vocabulary.
+
+ Specific values may be represented at most once.
"""
=== Zope3/src/zope/schema/vocabulary.py 1.5 => 1.6 ===
--- Zope3/src/zope/schema/vocabulary.py:1.5 Wed May 28 17:23:20 2003
+++ Zope3/src/zope/schema/vocabulary.py Fri May 30 02:10:58 2003
@@ -18,10 +18,14 @@
from zope.schema import errornames
from zope.schema.interfaces import ValidationError
from zope.schema.interfaces import IVocabularyRegistry
-from zope.schema.interfaces import IVocabularyField, IVocabularyMultiField
-from interfaces import IVocabulary, IVocabularyTokenized, ITokenizedTerm
+from zope.schema.interfaces import IVocabularyField
+from zope.schema.interfaces import IVocabularyBagField, IVocabularyListField
+from zope.schema.interfaces import IVocabularySetField
+from zope.schema.interfaces import IVocabularyUniqueListField
+from zope.schema.interfaces import IVocabulary, IVocabularyTokenized
+from zope.schema.interfaces import ITokenizedTerm
from zope.interface.declarations import directlyProvides
-from zope.schema import TextLine
+from zope.schema import MinMaxLen, TextLine
try:
basestring # new in Python 2.3
@@ -68,12 +72,19 @@
return clone
-class VocabularyMultiField(VocabularyField):
+class VocabularyMultiField(MinMaxLen, VocabularyField):
"""Field that adds support for use of an external vocabulary.
The value is a collection of values from the vocabulary.
+
+ This class cannot be used directly; a subclass must be used to
+ specify concrete behavior.
"""
- __implements__ = IVocabularyMultiField
+ def __init__(self, **kw):
+ if self.__class__ is VocabularyMultiField:
+ raise NotImplementedError(
+ "The VocabularyMultiField class cannot be used directly.")
+ super(VocabularyMultiField, self).__init__(**kw)
def _validate(self, value):
vocab = self.vocabulary
@@ -82,6 +93,34 @@
for v in value:
if v not in vocab:
raise ValidationError(errornames.ConstraintNotSatisfied, v)
+
+class UniqueElements(object):
+ """Mix-in class that checks that each contained element is unique."""
+
+ def _validate(self, value):
+ d = {}
+ for v in value:
+ if v in d:
+ raise ValidationError()
+ d[v] = v
+ super(UniqueElements, self)._validate(value)
+
+class VocabularyBagField(VocabularyMultiField):
+ __implements__ = IVocabularyBagField
+ __doc__ = IVocabularyBagField.__doc__
+
+class VocabularyListField(VocabularyMultiField):
+ __implements__ = IVocabularyListField
+ __doc__ = IVocabularyListField.__doc__
+
+class VocabularySetField(UniqueElements, VocabularyMultiField):
+ __implements__ = IVocabularySetField
+ __doc__ = IVocabularySetField.__doc__
+
+class VocabularyUniqueListField(UniqueElements, VocabularyMultiField):
+ __implements__ = IVocabularyUniqueListField
+ __doc__ = IVocabularyUniqueListField.__doc__
+
# simple vocabularies performing enumerated-like tasks