[Checkins] SVN: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/ - Add content providers lookup by adaptation

Jean-Francois Roche jfroche at jfroche.be
Fri Feb 12 12:47:27 EST 2010


Log message for revision 108957:
  - Add content providers lookup by adaptation
  - Rename form marker IWidgetsForm to IFieldsAndContentProviderForm
  - Remove unneeded code in FieldWidgetsAndProviders.update
  
  work in progress
  
  

Changed:
  U   z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.py
  U   z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.txt
  U   z3c.form/branches/fieldsandcontentproviders/src/z3c/form/field.py
  U   z3c.form/branches/fieldsandcontentproviders/src/z3c/form/interfaces.py
  U   z3c.form/branches/fieldsandcontentproviders/src/z3c/form/tests/test_doc.py
  U   z3c.form/branches/fieldsandcontentproviders/src/z3c/form/util.py

-=-
Modified: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.py
===================================================================
--- z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.py	2010-02-12 16:35:25 UTC (rev 108956)
+++ z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.py	2010-02-12 17:47:27 UTC (rev 108957)
@@ -2,75 +2,68 @@
 import zope.interface
 import zope.location
 import zope.schema.interfaces
+from zope.contentprovider.interfaces import IContentProvider
 
 from z3c.form.field import FieldWidgets
-from z3c.form import interfaces, util
-from z3c.form.widget import AfterWidgetUpdateEvent
+from z3c.form import interfaces
+from z3c.form.interfaces import IContentProviders
 
 
+class BaseProvider(object):
+    __slots__ = ('position')
+
+lookup_ = BaseProvider()
+
+
 class ContentProviders(dict):
+    zope.interface.implements(IContentProviders)
 
-    def __getitem__(self, key):
-        factory = super(ContentProviders, self).__getitem__(key)
-        return ContentProviderFactory(name=key, factory=factory)
+    def __init__(self, names=None):
+        super(ContentProviders, self).__init__()
+        if names is not None:
+            for position, name in enumerate(names):
+                self[name] = lookup_
+                self[name].position = position
 
+    def __setitem__(self, key, value):
+        factory = ContentProviderFactory(factory=value, name=key)
+        super(ContentProviders, self).__setitem__(key, factory)
 
+
 class ContentProviderFactory(object):
 
-    def __init__(self, factory, *args, **kwargs):
+    def __init__(self, factory, name):
         self.factory = factory
-        self.args = args
-        self.kwargs = kwargs
+        self.name = name
+        self.position = getattr(factory, 'position', None)
 
     def __call__(self, manager):
-        contentProvider = self.factory(manager.form, manager.request, manager.form)
+        if self.factory != lookup_:
+            contentProvider = self.factory(manager.content, manager.request, manager.form)
+        else:
+            contentProvider = zope.component.getMultiAdapter((manager.content, manager.request, manager.form),
+                                                             IContentProvider, self.name)
         return contentProvider
 
 
 class FieldWidgetsAndProviders(FieldWidgets):
     zope.component.adapts(
-        interfaces.IWidgetsForm, interfaces.IFormLayer, zope.interface.Interface)
+        interfaces.IFieldsAndContentProviderForm, interfaces.IFormLayer, zope.interface.Interface)
     zope.interface.implementsOnly(interfaces.IWidgets)
 
     def update(self):
         super(FieldWidgetsAndProviders, self).update()
-        prefix = util.expandPrefix(self.form.prefix)
-        prefix += util.expandPrefix(self.prefix)
 
         uniqueOrderedKeys = self._data_keys
         for name in self.form.contentProviders:
             factory = self.form.contentProviders[name]
             contentProvider = factory(self)
-            newWidget = True
-            ignoreContext = True
-            # Step 1: Determine the mode of the contentProvider.
-            mode = self.mode
-            # Step 2: Get the widget for the given field.
             shortName = name
-            #widget.name = prefix + shortName
-            contentProvider.id = (prefix + shortName).replace('.', '-')
-            # Step 4: Set the context
-            contentProvider.context = self.content
-            # Step 5: Set the form
-            contentProvider.form = self.form
-            # Optimization: Set both interfaces here, rather in step 4 and 5:
-            # ``alsoProvides`` is quite slow
-            zope.interface.alsoProvides(
-                contentProvider, interfaces.IContextAware, interfaces.IFormAware)
-            # Step 6: Set some variables
-            contentProvider.ignoreContext = ignoreContext
-            contentProvider.ignoreRequest = self.ignoreRequest
-            # Step 7: Set the mode of the widget
-            contentProvider.mode = mode
-            # Step 8: Update the widget
             contentProvider.update()
-            zope.event.notify(AfterWidgetUpdateEvent(contentProvider))
-            # Step 9: Add the widget to the manager
-            uniqueOrderedKeys.append(shortName)
-            if newWidget:
-                self._data_values.append(contentProvider)
-                self._data[shortName] = contentProvider
-                zope.location.locate(contentProvider, self, shortName)
+            uniqueOrderedKeys.insert(factory.position, shortName)
+            self._data_values.insert(factory.position, contentProvider)
+            self._data[shortName] = contentProvider
+            zope.location.locate(contentProvider, self, shortName)
             # allways ensure that we add all keys and keep the order given from
             # button items
             self._data_keys = uniqueOrderedKeys

Modified: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.txt
===================================================================
--- z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.txt	2010-02-12 16:35:25 UTC (rev 108956)
+++ z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.txt	2010-02-12 17:47:27 UTC (rev 108957)
@@ -20,45 +20,54 @@
   >>> zope.component.provideAdapter(converter.FieldDataConverter)
   >>> zope.component.provideAdapter(converter.FieldWidgetDataConverter)
 
+Now that everything we need is defined. We can define a simple schema with fields::
+
   >>> import zope.interface
   >>> import zope.schema
 
   >>> class IPerson(zope.interface.Interface):
+  ...
   ...     id = zope.schema.TextLine(
   ...         title=u'ID',
   ...         description=u"The person's ID.",
-  ...         readonly=True,
   ...         required=True)
   ...
 
-We want to mix fields and content providers::
+We want to mix fields and a content provider. We define a very simple
+content provider that will print extra help text after a widget::
 
   >>> from z3c.form import field, form
-  >>> from z3c.form.interfaces import IWidgetsForm
+  >>> from z3c.form.interfaces import IFieldsAndContentProviderForm
   >>> from z3c.form import widget
   >>> from zope.contentprovider.provider import ContentProviderBase
+  >>> from zope.interface import implements
 
   >>> class ExtendedHelp(ContentProviderBase):
   ...
   ...   def update(self):
-  ...       pass
+  ...       self.person = self.context.id
   ...
   ...   def render(self):
-  ...       """see `z3c.form.interfaces.IWidget`
-  ...       """
-  ...       return '<div class="extendedhelp">Some very long help text ...</div>'
+  ...       return '<div class="extendedhelp">Some very long help text about person %s</div>' % self.person
 
   >>> from z3c.form.contentprovider import ContentProviders
+  >>> from z3c.form.testing import setupFormDefaults
+  >>> setupFormDefaults()
+
   >>> class PersonForm(form.Form):
-  ...     zope.interface.implements(IWidgetsForm)
+  ...     implements(IFieldsAndContentProviderForm)
   ...     prefix = 'form.'
   ...     fields = field.Fields(IPerson)
+  ...     ignoreContext = True
   ...     contentProviders = ContentProviders()
   ...     contentProviders['longHelp'] = ExtendedHelp
+  ...     contentProviders['longHelp'].position = 2
 
   >>> from z3c.form.testing import TestRequest
   >>> request = TestRequest()
-  >>> context = object()
+  >>> class Person(object):
+  ...    id = 'james'
+  >>> context = Person()
   >>> personForm = PersonForm(context, request)
 
   >>> from z3c.form.contentprovider import FieldWidgetsAndProviders
@@ -68,4 +77,32 @@
   >>> manager._data
   {'longHelp': <ExtendedHelp object at ...>, 'id': <Widget 'form.widgets.id'>}
   >>> manager.get('longHelp').render()
-  '<div class="extendedhelp">Some very long help text ...</div>'
+  '<div class="extendedhelp">Some very long help text about person james</div>'
+
+We can also define content provider by adaptation::
+
+  >>> from zope.component import provideAdapter
+  >>> from zope.contentprovider.interfaces import IContentProvider
+  >>> from z3c.form.interfaces import IFormLayer
+  >>> provideAdapter(ExtendedHelp,
+  ...                (zope.interface.Interface,
+  ...                 IFormLayer,
+  ...                 zope.interface.Interface),
+  ...                provides=IContentProvider, name='longHelp')
+
+  >>> class PersonForm(form.Form):
+  ...     implements(IFieldsAndContentProviderForm)
+  ...     prefix = 'form.'
+  ...     fields = field.Fields(IPerson)
+  ...     ignoreContext = True
+  ...     contentProviders = ContentProviders(['longHelp'])
+  ...     contentProviders['longHelp'].position = 2
+
+  >>> from z3c.form.contentprovider import FieldWidgetsAndProviders
+  >>> manager = FieldWidgetsAndProviders(personForm, request, context)
+  >>> manager.ignoreContext = True
+  >>> manager.update()
+  >>> manager._data
+  {'longHelp': <ExtendedHelp object at ...>, 'id': <Widget 'form.widgets.id'>}
+  >>> manager.get('longHelp').render()
+  '<div class="extendedhelp">Some very long help text about person james</div>'

Modified: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/field.py
===================================================================
--- z3c.form/branches/fieldsandcontentproviders/src/z3c/form/field.py	2010-02-12 16:35:25 UTC (rev 108956)
+++ z3c.form/branches/fieldsandcontentproviders/src/z3c/form/field.py	2010-02-12 17:47:27 UTC (rev 108957)
@@ -280,7 +280,7 @@
                 self.hasRequiredFields = True
             uniqueOrderedKeys.append(shortName)
             if newWidget:
-                self._data_values.append(widget)
+            #    self._data_values.append(widget)
                 self._data[shortName] = widget
                 zope.location.locate(widget, self, shortName)
             # allways ensure that we add all keys and keep the order given from

Modified: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/branches/fieldsandcontentproviders/src/z3c/form/interfaces.py	2010-02-12 16:35:25 UTC (rev 108956)
+++ z3c.form/branches/fieldsandcontentproviders/src/z3c/form/interfaces.py	2010-02-12 17:47:27 UTC (rev 108957)
@@ -228,6 +228,11 @@
         specification.
         """
 
+class IContentProviders(IManager):
+    """
+    A content provider manager
+    """
+
 # ----[ Data Managers ]------------------------------------------------------
 
 class IDataManager(zope.interface.Interface):
@@ -1007,14 +1012,14 @@
                       'the form.'),
         schema=IFields)
 
-class IWidgetsForm(IForm):
-    """A form that is based upon defined fields."""
+class IFieldsAndContentProviderForm(IForm):
+    """A form that is based upon defined fields and content providers"""
 
-    widgetsItems = zope.schema.Object(
-        title=_('Widgets'),
-        description=_('A field manager describing the fields to be used for '
+    contentProviders = zope.schema.Object(
+        title=_('Content providers'),
+        description=_('A manager describing the content providers to be used for '
                       'the form.'),
-        schema=IFields)
+        schema=IContentProviders)
 
 class IButtonForm(IForm):
     """A form that is based upon defined buttons."""

Modified: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/tests/test_doc.py
===================================================================
--- z3c.form/branches/fieldsandcontentproviders/src/z3c/form/tests/test_doc.py	2010-02-12 16:35:25 UTC (rev 108956)
+++ z3c.form/branches/fieldsandcontentproviders/src/z3c/form/tests/test_doc.py	2010-02-12 17:47:27 UTC (rev 108957)
@@ -58,7 +58,7 @@
         doctest.DocFileSuite(
             '../contentprovider.txt',
             setUp=setUp, tearDown=testing.tearDown,
-            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE,
             checker=checker,
             ),
         doctest.DocFileSuite(

Modified: z3c.form/branches/fieldsandcontentproviders/src/z3c/form/util.py
===================================================================
--- z3c.form/branches/fieldsandcontentproviders/src/z3c/form/util.py	2010-02-12 16:35:25 UTC (rev 108956)
+++ z3c.form/branches/fieldsandcontentproviders/src/z3c/form/util.py	2010-02-12 17:47:27 UTC (rev 108957)
@@ -138,7 +138,14 @@
             raise ValueError(value)
         self.data.append(value)
 
+    def insert(self, position, value):
+        if value in self.data:
+            raise ValueError(value)
+        self.data.insert(position, value)
 
+    #XXX TODO: Inherit from list
+
+
 class Manager(object):
     """Non-persistent IManager implementation."""
     zope.interface.implements(interfaces.IManager)
@@ -192,6 +199,10 @@
     def __contains__(self, name):
         return bool(self.get(name))
 
+    #XXX TODO:
+    # Add __setitem__ that will add key, value at the end of both lists as in PEP0372
+    # Add insertBefore(key)
+    #     insertAfter(key)
 
 class SelectionManager(Manager):
     """Non-persisents ISelectionManager implementation."""



More information about the checkins mailing list