[Checkins] SVN: z3c.form/branches/zagy-sources/s - added tests for zagy's support of sources

Michael Howitz mh at gocept.com
Thu Aug 28 05:07:37 EDT 2008


Log message for revision 90534:
  - added tests for zagy's support of sources
  - support sources for collections, too
  

Changed:
  U   z3c.form/branches/zagy-sources/setup.py
  U   z3c.form/branches/zagy-sources/src/z3c/form/browser/checkbox.txt
  U   z3c.form/branches/zagy-sources/src/z3c/form/browser/radio.txt
  U   z3c.form/branches/zagy-sources/src/z3c/form/configure.zcml
  U   z3c.form/branches/zagy-sources/src/z3c/form/converter.txt
  U   z3c.form/branches/zagy-sources/src/z3c/form/interfaces.py
  U   z3c.form/branches/zagy-sources/src/z3c/form/term.py
  U   z3c.form/branches/zagy-sources/src/z3c/form/term.txt
  U   z3c.form/branches/zagy-sources/src/z3c/form/testing.py

-=-
Modified: z3c.form/branches/zagy-sources/setup.py
===================================================================
--- z3c.form/branches/zagy-sources/setup.py	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/setup.py	2008-08-28 09:07:37 UTC (rev 90534)
@@ -75,7 +75,7 @@
     namespace_packages = ['z3c'],
     extras_require = dict(
         test = ['zope.app.container', 'zope.testing',
-                'z3c.coverage', 'z3c.template'],
+                'z3c.coverage', 'z3c.template', 'zc.sourcefactory'],
         adding = ['zope.app.container'],
         ),
     install_requires = [

Modified: z3c.form/branches/zagy-sources/src/z3c/form/browser/checkbox.txt
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/browser/checkbox.txt	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/browser/checkbox.txt	2008-08-28 09:07:37 UTC (rev 90534)
@@ -55,9 +55,9 @@
   >>> print widget.render()
   <input name="widget.name-empty-marker" type="hidden" value="1" />
 
-Let's provide some values for this widget. We can do this by defining a source
-providing ``ITerms``. This source uses descriminators wich will fit for our
-setup.
+Let's provide some values for this widget. We can do this by defining
+a vocabulary providing ``ITerms``. This vocabulary uses descriminators
+wich will fit for our setup.
 
   >>> import zope.schema.interfaces
   >>> from zope.schema.vocabulary import SimpleVocabulary

Modified: z3c.form/branches/zagy-sources/src/z3c/form/browser/radio.txt
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/browser/radio.txt	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/browser/radio.txt	2008-08-28 09:07:37 UTC (rev 90534)
@@ -9,7 +9,7 @@
   >>> from z3c.form import interfaces
   >>> from z3c.form.browser import radio
 
-The TextWidget is a widget:
+The RadioWidget is a widget:
 
  >>> verifyClass(interfaces.IWidget, radio.RadioWidget)
   True
@@ -54,11 +54,14 @@
 providing ITerms. This source uses descriminators wich will fit for our setup.
 
   >>> import zope.schema.interfaces
-  >>> from zope.schema.vocabulary import SimpleVocabulary
   >>> import z3c.form.term
-  >>> class MyTerms(z3c.form.term.ChoiceTermsVocabulary):
+  >>> from zc.sourcefactory.basic import BasicSourceFactory
+  >>> class YesNoSourceFactory(BasicSourceFactory):
+  ...     def getValues(self):
+  ...         return ['yes', 'no']
+  >>> class MyTerms(z3c.form.term.ChoiceTermsSource):
   ...     def __init__(self, context, request, form, field, widget):
-  ...         self.terms = SimpleVocabulary.fromValues(['yes', 'no'])
+  ...         self.terms = YesNoSourceFactory()
   >>> zope.component.provideAdapter(z3c.form.term.BoolTerms,
   ...     adapts=(zope.interface.Interface,
   ...             interfaces.IFormLayer, zope.interface.Interface,

Modified: z3c.form/branches/zagy-sources/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/configure.zcml	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/configure.zcml	2008-08-28 09:07:37 UTC (rev 90534)
@@ -81,9 +81,15 @@
       factory=".term.ChoiceTermsSource"
       />
   <adapter
-      factory=".term.CollectionTerms"
+      factory=".term.collection_terms_multiplexer"
       />
   <adapter
+      factory=".term.CollectionTermsVocabulary"
+      />
+  <adapter
+      factory=".term.CollectionTermsSource"
+      />
+  <adapter
       factory=".term.BoolTerms"
       />
 

Modified: z3c.form/branches/zagy-sources/src/z3c/form/converter.txt
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/converter.txt	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/converter.txt	2008-08-28 09:07:37 UTC (rev 90534)
@@ -463,14 +463,26 @@
 
 For widgets and fields that work with choices of a sequence, a special data
 converter is required that works with terms. A prime example is a choice
-field. Before we can use the converter, we have to register the terms adapter:
+field. Before we can use the converter, we have to register some adapters:
 
   >>> from z3c.form import term
+  >>> import zc.sourcefactory.browser.source
+  >>> import zc.sourcefactory.browser.token
   >>> zope.component.provideAdapter(term.ChoiceTermsVocabulary)
+  >>> zope.component.provideAdapter(term.ChoiceTermsSource)
   >>> zope.component.provideAdapter(term.choice_terms_multiplexer)
+  >>> zope.component.provideAdapter(
+  ...     zc.sourcefactory.browser.source.FactoredTerms)
+  >>> zope.component.provideAdapter(
+  ...     zc.sourcefactory.browser.token.fromInteger)
 
-Let's now create a choice field and a widget:
+The choice fields can be used together with vocabularies and sources.
 
+Using vocabulary
+~~~~~~~~~~~~~~~~
+
+Let's now create a choice field (using a vocabulary) and a widget:
+
   >>> from zope.schema.vocabulary import SimpleVocabulary
 
   >>> gender = zope.schema.Choice(
@@ -520,19 +532,82 @@
   >>> sdv.toFieldValue([])
   'missing'
 
+Using source
+~~~~~~~~~~~~
 
+Let's now create a choice field (using a source) and a widget:
+
+  >>> from zc.sourcefactory.basic import BasicSourceFactory 
+  >>> class GenderSourceFactory(BasicSourceFactory):
+  ...     _mapping = {0: u'male', 1: u'female'}
+  ...     def getValues(self):
+  ...         return self._mapping.keys()
+  ...     def getTitle(self, value):
+  ...         return self._mapping[value]
+  >>> gender_source = zope.schema.Choice(
+  ...     source = GenderSourceFactory())
+
+  >>> seqWidget = widget.SequenceWidget(TestRequest())
+  >>> seqWidget.field = gender_source
+
+We now use the field and widget to instantiate the converter:
+
+  >>> sdv = converter.SequenceDataConverter(gender, seqWidget)
+
+We can now convert a real value to a widget value, which will be the term's
+token:
+
+  >>> sdv.toWidgetValue(0)
+  ['0']
+
+The result is always a sequence, since sequence widgets only deal collections
+of values. Of course, we can convert the widget value back to an internal
+value:
+
+  >>> sdv.toFieldValue(['0'])
+  0
+
+Sometimes a field is not required. In those cases, the internalvalue is the
+missing value of the field. The converter interprets that as no value being
+selected:
+
+  >>> gender.missing_value = 'missing'
+
+  >>> sdv.toWidgetValue(gender.missing_value)
+  []
+
+If "no value" has been specified in the widget, the missing value
+of the field is returned:
+
+  >>> sdv.toFieldValue([u'--NOVALUE--'])
+  'missing'
+
+An empty list will also cause the missing value to be returned:
+
+  >>> sdv.toFieldValue([])
+  'missing'
+
+
 Collection Sequence Data Converter
 ----------------------------------
 
 For widgets and fields that work with a sequence of choices, another data
 converter is required that works with terms. A prime example is a list
-field. Before we can use the converter, we have to register the terms adapter:
+field. Before we can use the converter, we have to register the terms adapters:
 
   >>> from z3c.form import term
-  >>> zope.component.provideAdapter(term.CollectionTerms)
+  >>> zope.component.provideAdapter(term.collection_terms_multiplexer)
+  >>> zope.component.provideAdapter(term.CollectionTermsVocabulary)
+  >>> zope.component.provideAdapter(term.CollectionTermsSource)
 
-Let's now create a set field and a widget:
+Collections can also use either vocabularies or sources.
 
+Using vocabulary
+~~~~~~~~~~~~~~~~
+
+Let's now create a list field (using the previously defined field using
+a vocabulary) and a widget:
+
   >>> genders = zope.schema.List(value_type=gender)
   >>> seqWidget = widget.SequenceWidget(TestRequest())
   >>> seqWidget.field = genders
@@ -570,7 +645,7 @@
   set([0])
 
 Getting Terms
-~~~~~~~~~~~~~
++++++++++++++
 
 As an optimization of this converter, the converter actually does not look up
 the terms itself but uses the widget's ``terms`` attribute. If the terms are
@@ -588,7 +663,7 @@
   ['m']
 
   >>> seqWidget.terms
-  <z3c.form.term.CollectionTerms object ...>
+  <z3c.form.term.CollectionTermsVocabulary object ...>
 
 The same is true when getting the field value:
 
@@ -602,9 +677,90 @@
   set([0])
 
   >>> seqWidget.terms
-  <z3c.form.term.CollectionTerms object ...>
+  <z3c.form.term.CollectionTermsVocabulary object ...>
 
+Using source
+~~~~~~~~~~~~
 
+Let's now create a list field (using the previously defined field using
+a source) and a widget:
+
+  >>> genders_source = zope.schema.List(value_type=gender_source)
+  >>> seqWidget = widget.SequenceWidget(TestRequest())
+  >>> seqWidget.field = genders_source
+
+We now use the field and widget to instantiate the converter:
+
+  >>> csdv = converter.CollectionSequenceDataConverter(
+  ...     genders_source, seqWidget)
+
+We can now convert a real value to a widget value, which will be the term's
+token:
+
+  >>> csdv.toWidgetValue([0])
+  ['0']
+
+The result is always a sequence, since sequence widgets only deal collections
+of values. Of course, we can convert the widget value back to an internal
+value:
+
+  >>> csdv.toFieldValue(['0'])
+  [0]
+
+For some field, like the ``Set``, the collection type is a tuple. Sigh. In
+these cases we use the last entry in the tuple as the type to use:
+
+  >>> genders_source = zope.schema.Set(value_type=gender_source)
+  >>> seqWidget = widget.SequenceWidget(TestRequest())
+  >>> seqWidget.field = genders_source
+
+  >>> csdv = converter.CollectionSequenceDataConverter(
+  ...     genders_source, seqWidget)
+
+  >>> csdv.toWidgetValue(set([0]))
+  ['0']
+
+  >>> csdv.toFieldValue(['0'])
+  set([0])
+
+Getting Terms
++++++++++++++
+
+As an optimization of this converter, the converter actually does not look up
+the terms itself but uses the widget's ``terms`` attribute. If the terms are
+not yet retrieved, the converter will ask the widget to do so when in need.
+
+So let's see how this works when getting the widget value:
+
+  >>> seqWidget = widget.SequenceWidget(TestRequest())
+  >>> seqWidget.field = genders_source
+
+  >>> seqWidget.terms
+
+  >>> csdv = converter.CollectionSequenceDataConverter(
+  ...     genders_source, seqWidget)
+  >>> csdv.toWidgetValue([0])
+  ['0']
+
+  >>> seqWidget.terms
+  <z3c.form.term.CollectionTermsSource object ...>
+
+The same is true when getting the field value:
+
+  >>> seqWidget = widget.SequenceWidget(TestRequest())
+  >>> seqWidget.field = genders_source
+
+  >>> seqWidget.terms
+
+  >>> csdv = converter.CollectionSequenceDataConverter(
+  ...     genders_source, seqWidget)
+  >>> csdv.toFieldValue(['0'])
+  set([0])
+
+  >>> seqWidget.terms
+  <z3c.form.term.CollectionTermsSource object ...>
+
+
 Boolean to Single Checkbox Data Converter
 -----------------------------------------
 

Modified: z3c.form/branches/zagy-sources/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/interfaces.py	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/interfaces.py	2008-08-28 09:07:37 UTC (rev 90534)
@@ -273,7 +273,7 @@
 
 # term interfaces
 class ITerms(zope.interface.Interface):
-    """"""
+    """ """
 
     context = zope.schema.Field()
     request = zope.schema.Field()
@@ -300,6 +300,16 @@
         LookupError is raised if there isn't a value in the source.
         """
 
+    def __iter__():
+        """Iterate over terms."""
+
+    def __len__():
+        """Return number of terms."""
+
+    def __contains__(value):
+        """Check wether terms containes the ``value``."""
+
+
 class IBoolTerms(ITerms):
     """A specialization that handles boolean choices."""
 

Modified: z3c.form/branches/zagy-sources/src/z3c/form/term.py
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/term.py	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/term.py	2008-08-28 09:07:37 UTC (rev 90534)
@@ -27,7 +27,7 @@
 
 
 class Terms(object):
-    """Base implementationf or custom ITerms."""
+    """Base implementation for custom ITerms."""
 
     zope.interface.implements(interfaces.ITerms)
 
@@ -49,7 +49,43 @@
     def __contains__(self, value):
         return self.terms.__contains__(value)
 
+class SourceTerms(Terms):
+    """Base implementation for ITerms using a source instead of a vocabulary."""
 
+    zope.interface.implements(interfaces.ITerms)
+
+    def __init__(self, context, request, form, field, source, widget):
+        self.context = context
+        self.request = request
+        self.form = form
+        self.field = field
+        self.widget = widget
+        self.source = source
+        self.terms = zope.component.getMultiAdapter(
+            (self.source, self.request),
+            zope.app.form.browser.interfaces.ITerms)
+
+    def getTermByToken(self, token):
+        # This is rather expensive
+        for value in self.source:
+            term = self.getTerm(value)
+            if term.token == token:
+                return term
+
+    def getValue(self, token):
+        return self.terms.getValue(token)
+
+    def __iter__(self):
+        for value in self.source:
+            yield self.terms.getTerm(value)
+
+    def __len__(self):
+        return len(self.source)
+
+    def __contains__(self, value):
+        return value in self.source
+
+
 @zope.interface.implementer(interfaces.ITerms)
 @zope.component.adapter(
     zope.interface.Interface,
@@ -67,7 +103,8 @@
 
 
 class ChoiceTermsVocabulary(Terms):
-    """ITerms adapter for zope.schema.IChoice based implementations."""
+    """ITerms adapter for zope.schema.IChoice based implementations using 
+    vocabulary."""
 
     zope.component.adapts(
         zope.interface.Interface,
@@ -88,7 +125,8 @@
         self.terms = vocabulary
 
 
-class ChoiceTermsSource(object):
+class ChoiceTermsSource(SourceTerms):
+    "ITerms adapter for zope.schema.IChoice based implementations using source."
 
     zope.component.adapts(
         zope.interface.Interface,
@@ -100,45 +138,7 @@
 
     zope.interface.implements(interfaces.ITerms)
 
-    def __init__(self, context, request, form, field, source, widget):
-        self.context = context
-        self.request = request
-        self.form = form
-        self.field = field
-        self.widget = widget
-        self.source = source
-        self.terms = zope.component.getMultiAdapter(
-            (self.source, self.request),
-            zope.app.form.browser.interfaces.ITerms)
 
-    def getTerm(self, value):
-        return self.terms.getTerm(value)
-
-    def getTermByToken(self, token):
-        # This is rather expensive
-        for value in self.source:
-            term = self.getTerm(value)
-            if term.token == token:
-                return term
-
-    def getValue(self, token):
-        return self.terms.getValue(token)
-
-    def __iter__(self):
-        # XXX Not defined in interface
-        for value in self.source:
-            yield self.terms.getTerm(value)
-
-    def __len__(self):
-        # XXX Not defined in interface
-        return len(self.source)
-
-    def __contains__(self, value):
-        # XXX Not defined in interface
-        # XXX value or term?
-        return value in self.source
-
-
 class BoolTerms(Terms):
     """Default yes and no terms are used by default for IBool fields."""
 
@@ -165,21 +165,49 @@
                               (False, 'false', self.falseLabel)]]
         self.terms = vocabulary.SimpleVocabulary(terms)
 
+ at zope.interface.implementer(interfaces.ITerms)
+ at zope.component.adapter(
+    zope.interface.Interface,
+    interfaces.IFormLayer,
+    zope.interface.Interface,
+    zope.schema.interfaces.ICollection,
+    interfaces.IWidget)
+def collection_terms_multiplexer(context, request, form, field, widget):
+    terms = field.value_type.bind(context).vocabulary
+    return zope.component.queryMultiAdapter(
+        (context, request, form, field, terms, widget),
+        interfaces.ITerms)
 
-class CollectionTerms(Terms):
-    """ITerms adapter for zope.schema.ICollection based implementations."""
+class CollectionTermsVocabulary(Terms):
+    """ITerms adapter for zope.schema.ICollection based implementations using 
+    vocabulary."""
 
     zope.component.adapts(
         zope.interface.Interface,
         interfaces.IFormLayer,
         zope.interface.Interface,
         zope.schema.interfaces.ICollection,
+        zope.schema.interfaces.IBaseVocabulary,
         interfaces.IWidget)
 
-    def __init__(self, context, request, form, field, widget):
+    def __init__(self, context, request, form, field, vocabulary, widget):
         self.context = context
         self.request = request
         self.form = form
         self.field = field
         self.widget = widget
-        self.terms = field.value_type.bind(self.context).vocabulary
+        self.terms = vocabulary
+
+class CollectionTermsSource(SourceTerms):
+    """ITerms adapter for zope.schema.ICollection based implementations using
+    source."""
+
+    zope.component.adapts(
+        zope.interface.Interface,
+        interfaces.IFormLayer,
+        zope.interface.Interface,
+        zope.schema.interfaces.ICollection,
+        zope.schema.interfaces.IIterableSource,
+        interfaces.IWidget)
+
+    zope.interface.implements(interfaces.ITerms)

Modified: z3c.form/branches/zagy-sources/src/z3c/form/term.txt
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/term.txt	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/term.txt	2008-08-28 09:07:37 UTC (rev 90534)
@@ -6,6 +6,9 @@
 needing them. Since Zope 3 already has sources and vocabularies, the base
 terms class simply builds on them.
 
+Vocabularies
+============
+
 Thus, let's create a vocabulary first:
 
   >>> from zope.schema import vocabulary
@@ -15,6 +18,9 @@
   ...     vocabulary.SimpleVocabulary.createTerm(2, '2', u'good')
   ...     ])
 
+Terms
+-----
+
 Now we can create the terms object:
 
   >>> from z3c.form import term
@@ -70,8 +76,11 @@
 
 Now, there are several terms implementations that were designed for particular
 fields. Within the framework, terms are used as adapters with the follwoing
-discriminators: context, request, form, field, and widget.
+discriminators: context, request, form, field, vocabulary/source and widget.
 
+Choice field
+============
+
 The first terms implementation is for ``Choice`` fields. Choice fields
 unfortunately can have a vocabulary and a source which behave differently.
 Let's have a look a the vocabulary first:
@@ -125,6 +134,9 @@
   >>> [entry.title for entry in terms]
   [u'bad', u'okay', u'good']
 
+Bool fields
+-----------
+
 A similar terms implementation exists for a ``Bool`` field:
 
   >>> truthField = zope.schema.Bool()
@@ -144,12 +156,106 @@
   >>> [entry.title for entry in terms]
   [u'True', u'False']
 
-Finally, there is a terms adapter for all collections:
+Collections
+-----------
 
+Finally, there are a terms adapters for all collections. But we have to
+register some adapters before using it:
+
+  >>> from z3c.form import term
+  >>> zope.component.provideAdapter(term.collection_terms_multiplexer)
+  >>> zope.component.provideAdapter(term.CollectionTermsVocabulary)
+  >>> zope.component.provideAdapter(term.CollectionTermsSource)
+
   >>> ratingsField = zope.schema.List(
   ...     title=u'Ratings',
   ...     value_type=ratingField)
 
-  >>> terms = term.CollectionTerms(None, None, None, ratingsField, None)
+  >>> terms = term.collection_terms_multiplexer(
+  ...     None, request, None, ratingsField, widget)
   >>> [entry.title for entry in terms]
   [u'bad', u'okay', u'good']
+
+
+Sources
+=======
+
+Let's create a source first:
+
+  >>> from zc.sourcefactory.basic import BasicSourceFactory 
+  >>> class RatingSourceFactory(BasicSourceFactory):
+  ...     _mapping = {10: u'ugly', 20: u'nice', 30: u'great'}
+  ...     def getValues(self):
+  ...         return self._mapping.keys()
+  ...     def getTitle(self, value):
+  ...         return self._mapping[value]
+
+As we did not include the configure.zcml of zc.sourcefactory we have
+to register some required adapters manually. We also need the
+ChoiceTermsSource adapter:
+
+  >>> import zope.component
+  >>> import zc.sourcefactory.browser.source
+  >>> import zc.sourcefactory.browser.token
+  >>> zope.component.provideAdapter(
+  ...     zc.sourcefactory.browser.source.FactoredTerms)
+  >>> zope.component.provideAdapter(
+  ...     zc.sourcefactory.browser.token.fromInteger)
+  >>> zope.component.provideAdapter(term.ChoiceTermsSource)
+
+Choice fields
+-------------
+
+Sources can be used with ``Choice`` fields like vocabularies.  First
+we create a field based on the source:
+
+  >>> sourceRatingField = zope.schema.Choice(
+  ...     title=u'Sourced Rating',
+  ...     source=RatingSourceFactory())
+
+We connect the field to a widget to see the ITerms adapter for sources
+at work:
+
+  >>> terms = term.choice_terms_multiplexer(
+  ...     None, request, None, sourceRatingField, widget)
+
+Iterating over the terms adapter returnes the term objects:
+
+  >>> [entry for entry in terms]
+  [<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
+   <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>, 
+   <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>]
+  >>> len(terms)
+  3
+  >>> [entry.token for entry in terms]
+  ['10', '20', '30']
+  >>> [entry.title for entry in terms]
+  [u'ugly', u'nice', u'great']
+
+Using a token it is possible to look up the term and the value:
+
+  >>> terms.getTermByToken('20').title
+  u'nice'
+  >>> terms.getValue('30')
+  30
+
+With can test if a value is in the source:
+
+  >>> 30 in terms
+  True
+  >>> 25 in terms
+  False 
+
+Collections
+-----------
+
+Finally, there are terms adapters for all collections:
+
+  >>> sourceRatingsField = zope.schema.List(
+  ...     title=u'Sourced Ratings',
+  ...     value_type=sourceRatingField)
+
+  >>> terms = term.collection_terms_multiplexer(
+  ...     None, request, None, sourceRatingsField, widget)
+  >>> [entry.title for entry in terms]
+  [u'ugly', u'nice', u'great']

Modified: z3c.form/branches/zagy-sources/src/z3c/form/testing.py
===================================================================
--- z3c.form/branches/zagy-sources/src/z3c/form/testing.py	2008-08-28 09:07:30 UTC (rev 90533)
+++ z3c.form/branches/zagy-sources/src/z3c/form/testing.py	2008-08-28 09:07:37 UTC (rev 90534)
@@ -136,6 +136,10 @@
     # Adapter for providing terms to radio list and other widgets
     zope.component.provideAdapter(term.choice_terms_multiplexer)
     zope.component.provideAdapter(term.ChoiceTermsVocabulary)
+    zope.component.provideAdapter(term.ChoiceTermsSource)
+    zope.component.provideAdapter(term.collection_terms_multiplexer)
+    zope.component.provideAdapter(term.CollectionTermsVocabulary)
+    zope.component.provideAdapter(term.CollectionTermsSource)
     zope.component.provideAdapter(term.BoolTerms)
     # Adapter to create an action from a button
     zope.component.provideAdapter(



More information about the Checkins mailing list