[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/form/browser/ Added
some iterable source widgets that were missing.
Sam Stainsby
sam at sustainablesoftware.com.au
Sat Apr 29 02:25:48 EDT 2006
Log message for revision 67747:
Added some iterable source widgets that were missing.
Changed:
U Zope3/trunk/src/zope/app/form/browser/configure.zcml
U Zope3/trunk/src/zope/app/form/browser/source.py
U Zope3/trunk/src/zope/app/form/browser/source.txt
-=-
Modified: Zope3/trunk/src/zope/app/form/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/configure.zcml 2006-04-29 00:45:17 UTC (rev 67746)
+++ Zope3/trunk/src/zope/app/form/browser/configure.zcml 2006-04-29 06:25:47 UTC (rev 67747)
@@ -410,6 +410,15 @@
<view
type="zope.publisher.interfaces.browser.IBrowserRequest"
+ for="zope.schema.interfaces.ISet
+ zope.schema.interfaces.IIterableSource"
+ provides="zope.app.form.interfaces.IInputWidget"
+ factory=".source.SourceMultiSelectSetWidget"
+ permission="zope.Public"
+ />
+
+ <view
+ type="zope.publisher.interfaces.browser.IBrowserRequest"
for="zope.schema.interfaces.IChoice
zope.schema.interfaces.IIterableSource"
provides="zope.app.form.interfaces.IInputWidget"
@@ -417,6 +426,15 @@
permission="zope.Public"
/>
+ <view
+ type="zope.publisher.interfaces.browser.IBrowserRequest"
+ for="zope.schema.interfaces.IList
+ zope.schema.interfaces.IIterableSource"
+ provides="zope.app.form.interfaces.IInputWidget"
+ factory=".source.SourceOrderedMultiSelectWidget"
+ permission="zope.Public"
+ />
+
<!-- These widgets are minimal and only support lists with unique members,
without ordering capabilities -->
Modified: Zope3/trunk/src/zope/app/form/browser/source.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/source.py 2006-04-29 00:45:17 UTC (rev 67746)
+++ Zope3/trunk/src/zope/app/form/browser/source.py 2006-04-29 06:25:47 UTC (rev 67747)
@@ -15,21 +15,30 @@
$Id$
"""
+
+from itertools import imap
+
import xml.sax.saxutils
+from zope.component import adapts
+from zope.interface import implements
import zope.schema.interfaces
-from zope.schema.interfaces import ISourceQueriables, ValidationError
+from zope.schema.interfaces import \
+ ISourceQueriables, ValidationError, IVocabularyTokenized, IIterableSource
from zope.app import zapi
import zope.app.form.interfaces
import zope.app.form.browser.widget
import zope.app.form.browser.interfaces
from zope.app.i18n import ZopeMessageFactory as _
from zope.app.form.interfaces import WidgetInputError, MissingInputError
-from zope.app.form.browser.interfaces import IWidgetInputErrorView
+from zope.app.form.browser.interfaces import ITerms, IWidgetInputErrorView
+from zope.app.form.browser import \
+ SelectWidget, RadioWidget, MultiSelectWidget, OrderedMultiSelectWidget, \
+ MultiCheckBoxWidget, MultiSelectSetWidget
class SourceDisplayWidget(zope.app.form.Widget):
- zope.interface.implements(zope.app.form.interfaces.IDisplayWidget)
+ implements(zope.app.form.interfaces.IDisplayWidget)
def __init__(self, field, source, request):
super(SourceDisplayWidget, self).__init__(field, request)
@@ -109,7 +118,7 @@
_error = None
- zope.interface.implements(zope.app.form.interfaces.IInputWidget)
+ implements(zope.app.form.interfaces.IInputWidget)
def __init__(self, field, source, request):
super(SourceInputWidget, self).__init__(field, request)
@@ -496,73 +505,90 @@
# Input widgets for IIterableSource:
-class SourceSelectWidget(zope.app.form.browser.SelectWidget):
- """Select-box widget for iterable vocabularies."""
+# These widgets reuse the old-style vocabulary widgets via the class
+# IterableSourceVocabulary that adapts a source (and its ITerms object)
+# into a vocabulary. When/if vocabularies go away, these classes
+# should be updated into full implementations.
- # This is a very thin veneer over the vocabulary widget, but deals
- # with the only differences in retrieving information about values
- # that existing between sources and vocabularies.
- def __init__(self, field, source, request):
- super(SourceSelectWidget, self).__init__(field, source, request)
+class IterableSourceVocabulary(object):
+
+ """Adapts an iterable source into a legacy vocabulary.
+
+ This can be used to wrap sources to make them usable with widgets that
+ expect vocabularies. Note that there must be an ITerms implementation
+ registered to obtain the terms.
+ """
+
+ implements(IVocabularyTokenized)
+ adapts(IIterableSource);
+
+ def __init__(self, source, request):
+ self.source = source
self.terms = zapi.getMultiAdapter(
- (self.vocabulary, self.request),
- zope.app.form.browser.interfaces.ITerms,
- )
+ (source, request), zope.app.form.browser.interfaces.ITerms)
+
+ def getTerm(self, value):
+ return self.terms.getTerm(value)
+
+ def getTermByToken(self, token):
+ value = self.terms.getValue(token)
+ return self.getTerm(value)
+
+ def __iter__(self):
+ return imap(
+ lambda value: self.getTerm(value), self.source.__iter__())
+
+ def __len__(self):
+ return self.source.__len__()
+
+ def __contains__(self, value):
+ return self.source.__contains__(value)
- def convertTokensToValues(self, tokens):
- """Convert term tokens to the terms themselves.
- Tokens are used in the HTML form to represent terms. This method takes
- the form tokens and converts them back to terms.
- """
- values = []
- for token in tokens:
- try:
- value = self.terms.getValue(token)
- except LookupError, error:
- pass
- else:
- values.append(value)
- return values
+class SourceSelectWidget(SelectWidget):
+ """Provide a selection list for the item."""
+
+ def __init__(self, field, source, request):
+ super(SourceSelectWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
- def renderItemsWithValues(self, values):
- """Render the list of possible values, with those found in
- `values` being marked as selected."""
+class SourceDropdownWidget(SourceSelectWidget):
+ """Variation of the SourceSelectWidget that uses a drop-down list."""
+
+ size = 1
- cssClass = self.cssClass
+class SourceRadioWidget(RadioWidget):
+ """Radio widget for single item choices."""
+
+ def __init__(self, field, source, request):
+ super(SourceRadioWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
- # multiple items with the same value are not allowed from a
- # vocabulary, so that need not be considered here
- rendered_items = []
- count = 0
- for value in self.vocabulary:
- term = self.terms.getTerm(value)
- item_text = self.textForValue(term)
-
- if value in values:
- rendered_item = self.renderSelectedItem(count,
- item_text,
- term.token,
- self.name,
- cssClass)
- else:
- rendered_item = self.renderItem(count,
- item_text,
- term.token,
- self.name,
- cssClass)
-
- rendered_items.append(rendered_item)
- count += 1
-
- return rendered_items
-
- def textForValue(self, term):
- return term.title
-
-
-class SourceDropdownWidget(SourceSelectWidget):
- """Variant of the SourceSelectWidget that uses a drop-down list."""
-
- size = 1
+class SourceMultiSelectWidget(MultiSelectWidget):
+ """A multi-selection widget with ordering support."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiSelectWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceOrderedMultiSelectWidget(OrderedMultiSelectWidget):
+ """A multi-selection widget with ordering support."""
+
+ def __init__(self, field, source, request):
+ super(SourceOrderedMultiSelectWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceMultiSelectSetWidget(MultiSelectSetWidget):
+ """Provide a selection list for the set to be selected."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiSelectSetWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
+
+class SourceMultiCheckBoxWidget(MultiCheckBoxWidget):
+ """Provide a list of checkboxes that provide the choice for the list."""
+
+ def __init__(self, field, source, request):
+ super(SourceMultiCheckBoxWidget, self).__init__(
+ field, IterableSourceVocabulary(source, request), request)
Modified: Zope3/trunk/src/zope/app/form/browser/source.txt
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/source.txt 2006-04-29 00:45:17 UTC (rev 67746)
+++ Zope3/trunk/src/zope/app/form/browser/source.txt 2006-04-29 06:25:47 UTC (rev 67747)
@@ -29,12 +29,7 @@
>>> import zope.publisher.interfaces.browser
>>> import zope.app.form.browser.interfaces
-
- >>> class Term:
- ...
- ... def __init__(self, **kw):
- ... self.__dict__.update(kw)
-
+ >>> from zope.schema.vocabulary import SimpleTerm
>>> class ListTerms:
...
... zope.interface.implements(
@@ -49,11 +44,11 @@
... token = title.encode('base64').strip()
... except binascii.Error:
... raise LookupError(token)
- ... return Term(title=title, token=token)
+ ... return SimpleTerm(value, token=token, title=title)
...
... def getValue(self, token):
... return token.decode('base64')
-
+
This view just uses the unicode representations of values as titles
and the base-64 encoding of the titles as tokens. This is a very
simple strategy that's only approriate when the values have short and
@@ -158,7 +153,322 @@
<input name="field.dog-empty-marker" type="hidden" value="1" />
</div>
+Dropdown widgets are achieved with SourceDropdownWidget, which simply
+generates a selection list of size 1::
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceDropdownWidget(
+ ... dog, dog.source, request)
+ >>> print widget() # doctest: +ELLIPSIS
+ <div>
+ <div class="value">
+ <select id="field.dog" name="field.dog" size="1" >...
+
+An alternative to SourceSelectWidget for small numbers of items is
+SourceRadioWidget that provides a radio button group for the items::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceRadioWidget(
+ ... dog, dog.source, request)
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <label><input class="radioType" id="field.dog.0" name="field.dog"
+ type="radio" value="c3BvdA==" /> spot</label><br
+ /><label><input class="radioType" id="field.dog.1" name="field.dog"
+ type="radio" value="Ym93c2Vy" /> bowser</label><br
+ /><label><input class="radioType" id="field.dog.2" name="field.dog"
+ type="radio" value="cHJpbmNl" /> prince</label><br
+ /><label><input class="radioType" id="field.dog.3" name="field.dog"
+ type="radio" value="ZHVjaGVzcw==" /> duchess</label><br
+ /><label><input class="radioType" id="field.dog.4" name="field.dog"
+ type="radio" value="bGFzc2ll" /> lassie</label>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+We'll select an item by setting the appropriate fields in the request:
+
+ >>> request.form['field.dog-empty-marker'] = '1'
+ >>> request.form['field.dog'] = 'bGFzc2ll'
+ >>>
+ >>> widget = zope.app.form.browser.source.SourceRadioWidget(
+ ... dog, dog.source, request)
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <label><input class="radioType" id="field.dog.0" name="field.dog"
+ type="radio" value="c3BvdA==" /> spot</label><br
+ /><label><input class="radioType" id="field.dog.1" name="field.dog"
+ type="radio" value="Ym93c2Vy" /> bowser</label><br
+ /><label><input class="radioType" id="field.dog.2" name="field.dog"
+ type="radio" value="cHJpbmNl" /> prince</label><br
+ /><label><input class="radioType" id="field.dog.3" name="field.dog"
+ type="radio" value="ZHVjaGVzcw==" /> duchess</label><br
+ /><label><input class="radioType" checked="checked" id="field.dog.4"
+ name="field.dog" type="radio" value="bGFzc2ll" /> lassie</label>
+ </div>
+ <input name="field.dog-empty-marker" type="hidden" value="1" />
+ </div>
+
+For list-valued fields with items chosen from iterable sources, there are the
+SourceMultiSelectWidget and SourceOrderedMultiSelectWidget widgets.
+The latter widget includes support for re-ording the list items.
+SourceOrderedMultiSelectWidget is configured as the default widget
+for lists of choices.
+
+If you don't need ordering support through the web UI, then you can use
+the simpler SourceMultiSelectWidget::
+
+ >>> dogSource = SourceList([
+ ... u'spot', u'bowser', u'prince', u'duchess', u'lassie'])
+ >>> dogs = zope.schema.List(
+ ... __name__ = 'dogs',
+ ... title=u"Dogs",
+ ... value_type=zope.schema.Choice(
+ ... source=dogSource,
+ ... )
+ ... )
+ >>> dogs = dogs.bind(object()) # give the field a context
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceMultiSelectWidget(
+ ... dogs, dogSource, request)
+
+Let's look at the rendered widget:
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogs" multiple="multiple" name="field.dogs:list"
+ size="5" ><option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+We have no input yet:
+
+ >>> try:
+ ... widget.getInputValue()
+ ... except zope.app.form.interfaces.MissingInputError:
+ ... print 'no input'
+ no input
+
+Select an item:
+
+ >>> request.form['field.dogs-empty-marker'] = '1'
+ >>> request.form['field.dogs'] = ['bGFzc2ll']
+ >>> widget.getInputValue()
+ ['lassie']
+
+and another:
+
+ >>> request.form['field.dogs'] = ['cHJpbmNl', 'bGFzc2ll']
+ >>> widget.getInputValue()
+ ['prince', 'lassie']
+
+Finally, what does the widget look like now:
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogs" multiple="multiple" name="field.dogs:list"
+ size="5" ><option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option selected="selected" value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option selected="selected" value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+
+An alternative for small numbers of items is to use SourceMultiCheckBoxWidget::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceMultiCheckBoxWidget(
+ ... dogs, dogSource, request)
+
+The rendered widget:
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <input class="checkboxType" id="field.dogs.0" name="field.dogs"
+ type="checkbox" value="c3BvdA==" /> spot<br
+ /><input class="checkboxType" id="field.dogs.1"
+ name="field.dogs" type="checkbox" value="Ym93c2Vy" /> bowser<br
+ /><input class="checkboxType" id="field.dogs.2"
+ name="field.dogs" type="checkbox" value="cHJpbmNl" /> prince<br
+ /><input class="checkboxType" id="field.dogs.3"
+ name="field.dogs" type="checkbox"
+ value="ZHVjaGVzcw==" /> duchess<br
+ /><input class="checkboxType" id="field.dogs.4"
+ name="field.dogs" type="checkbox" value="bGFzc2ll" /> lassie
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+We have no input yet:
+
+ >>> try:
+ ... widget.getInputValue()
+ ... except zope.app.form.interfaces.MissingInputError:
+ ... print 'no input'
+ no input
+
+Select an item:
+
+ >>> request.form['field.dogs-empty-marker'] = '1'
+ >>> request.form['field.dogs'] = ['bGFzc2ll']
+ >>> widget.getInputValue()
+ ['lassie']
+
+and another:
+
+ >>> request.form['field.dogs'] = ['c3BvdA==', 'bGFzc2ll']
+ >>> widget.getInputValue()
+ ['spot', 'lassie']
+
+Finally, what does the widget look like now:
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <input class="checkboxType" checked="checked" id="field.dogs.0"
+ name="field.dogs" type="checkbox" value="c3BvdA==" /> spot<br
+ /><input class="checkboxType" id="field.dogs.1"
+ name="field.dogs" type="checkbox" value="Ym93c2Vy" /> bowser<br
+ /><input class="checkboxType" id="field.dogs.2"
+ name="field.dogs" type="checkbox" value="cHJpbmNl" /> prince<br
+ /><input class="checkboxType" id="field.dogs.3"
+ name="field.dogs" type="checkbox"
+ value="ZHVjaGVzcw==" /> duchess<br
+ /><input class="checkboxType" checked="checked" id="field.dogs.4"
+ name="field.dogs" type="checkbox" value="bGFzc2ll" /> lassie
+ </div>
+ <input name="field.dogs-empty-marker" type="hidden" value="1" />
+ </div>
+
+
+For list ordering support, use SourceOrderedMultiSelectWidget::
+
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceOrderedMultiSelectWidget(
+ ... dogs, dogSource, request)
+
+The widget is too complicated to show in complete rendered form here.
+Insted, we'll inspect the properties of the widget:
+
+ >>> from zope.app.form.interfaces import MissingInputError
+ >>> try:
+ ... widget.getInputValue()
+ ... except MissingInputError:
+ ... print 'no input'
+ no input
+
+ >>> widget.choices() == [
+ ... {'text': u'spot', 'value': 'c3BvdA=='},
+ ... {'text': u'bowser', 'value': 'Ym93c2Vy'},
+ ... {'text': u'prince', 'value': 'cHJpbmNl'},
+ ... {'text': u'duchess', 'value': 'ZHVjaGVzcw=='},
+ ... {'text': u'lassie', 'value': 'bGFzc2ll'}
+ ... ]
+ True
+
+ >>> widget.selected()
+ []
+
+Let's try out selecting items. Select one item:
+
+ >>> request.form['field.dogs-empty-marker'] = '1'
+ >>> request.form['field.dogs'] = ['bGFzc2ll']
+ >>> widget.selected() # doctest: +NORMALIZE_WHITESPACE
+ [{'text': u'lassie', 'value': 'bGFzc2ll'}]
+
+ >>> widget.getInputValue()
+ ['lassie']
+
+Select two items:
+
+ >>> request.form['field.dogs'] = ['c3BvdA==', 'bGFzc2ll']
+ >>> widget.selected() # doctest: +NORMALIZE_WHITESPACE
+ [{'text': u'spot', 'value': 'c3BvdA=='},
+ {'text': u'lassie', 'value': 'bGFzc2ll'}]
+
+ >>> widget.getInputValue()
+ ['spot', 'lassie']
+
+
+For set-valued fields, use SourceMultiSelectSetWidget::
+
+ >>> dogSet = zope.schema.Set(
+ ... __name__ = 'dogSet',
+ ... title=u"Dogs",
+ ... value_type=zope.schema.Choice(
+ ... source=dogSource,
+ ... )
+ ... )
+ >>> dogSet = dogSet.bind(object()) # give the field a context
+ >>> from sets import Set
+ >>> request = TestRequest()
+ >>> widget = zope.app.form.browser.source.SourceMultiSelectSetWidget(
+ ... dogSet, dogSource, request)
+
+ >>> try:
+ ... widget.getInputValue()
+ ... except zope.app.form.interfaces.MissingInputError:
+ ... print 'no input'
+ no input
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogSet" multiple="multiple"
+ name="field.dogSet:list" size="5" ><option value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogSet-empty-marker" type="hidden" value="1" />
+ </div>
+
+Let's try out selecting items. Select one item:
+
+ >>> request.form['field.dogSet-empty-marker'] = '1'
+ >>> request.form['field.dogSet'] = ['bGFzc2ll']
+ >>> widget.getInputValue()
+ Set(['lassie'])
+
+Select two items:
+
+ >>> request.form['field.dogSet'] = ['c3BvdA==', 'bGFzc2ll']
+ >>> widget.getInputValue()
+ Set(['spot', 'lassie'])
+
+The rendered widget (still with the two items selected) looks like this:
+
+ >>> print widget() # doctest: +NORMALIZE_WHITESPACE
+ <div>
+ <div class="value">
+ <select id="field.dogSet" multiple="multiple"
+ name="field.dogSet:list" size="5" ><option selected="selected"
+ value="c3BvdA==">spot</option>
+ <option value="Ym93c2Vy">bowser</option>
+ <option value="cHJpbmNl">prince</option>
+ <option value="ZHVjaGVzcw==">duchess</option>
+ <option selected="selected" value="bGFzc2ll">lassie</option></select>
+ </div>
+ <input name="field.dogSet-empty-marker" type="hidden" value="1" />
+ </div>
+
+
+
Source Widget Query Framework
-----------------------------
@@ -722,3 +1032,68 @@
</div> <!-- query -->
</div> <!-- queries -->
</div> <!-- value -->
+
+
+Using vocabulary-dependent widgets with sources
+------------------------------------------------
+
+if you have a widget that uses old-style vocabularies but don't have the
+time to rewrite it for sources, all is not lost! The wrapper
+IterableSourceVocabulary can be used to make sources and ITerms look like
+a vocabulary. This allows us to use vocabulary-based widgets with sources
+instead of vocabularies.
+
+Usage::
+
+ >>> from zope.schema.vocabulary import SimpleTerm
+
+ >>> values = [u'a', u'b', u'c']
+ >>> tokens = [ '0', '1', '2']
+ >>> titles = [u'A', u'B', u'C']
+
+ >>> terms = [SimpleTerm(values[i], token=tokens[i], title=titles[i]) \
+ ... for i in range(0,len(values))]
+
+ >>> class TestSource(list):
+ ... zope.interface.implements(zope.schema.interfaces.IIterableSource)
+ >>> source = TestSource(values)
+
+ >>> from zope.app.form.browser.interfaces import ITerms
+ >>> class TestTerms(object):
+ ... zope.interface.implements(ITerms)
+ ... def __init__(self, source, request):
+ ... pass
+ ... def getTerm(self, value):
+ ... index = values.index(value)
+ ... return terms[index]
+ ... def getValue(self, token):
+ ... index = tokens.index(token)
+ ... return values[index]
+
+ >>> zope.component.provideAdapter(
+ ... TestTerms,
+ ... (TestSource, zope.publisher.interfaces.browser.IBrowserRequest))
+
+ >>> from zope.app.form.browser.source import IterableSourceVocabulary
+ >>> request = TestRequest()
+ >>> vocab = IterableSourceVocabulary(source, request)
+ >>> from zope.interface.verify import verifyClass, verifyObject
+ >>> verifyClass(zope.schema.interfaces.IVocabularyTokenized, \
+ ... IterableSourceVocabulary)
+ True
+ >>> verifyObject(zope.schema.interfaces.IVocabularyTokenized, vocab)
+ True
+
+ >>> len(vocab)
+ 3
+ >>> (u'a' in vocab) and (u'b' in vocab) and (u'c' in vocab)
+ True
+ >>> [value for value in vocab] == terms
+ True
+ >>> term = vocab.getTerm(u'b')
+ >>> (term.value, term.token, term.title)
+ (u'b', '1', u'B')
+ >>> term = vocab.getTermByToken('2')
+ >>> (term.value, term.token, term.title)
+ (u'c', '2', u'C')
+
More information about the Zope3-Checkins
mailing list