[Checkins] SVN: five.grok/trunk/ Correct form AutoFields to be usuable.

Sylvain Viollon sylvain at infrae.com
Sat Nov 22 19:11:05 EST 2008


Log message for revision 93265:
  Correct form AutoFields to be usuable.
  
  

Changed:
  U   five.grok/trunk/docs/HISTORY.txt
  U   five.grok/trunk/src/five/grok/__init__.py
  U   five.grok/trunk/src/five/grok/components.py
  A   five.grok/trunk/src/five/grok/formlib.py
  A   five.grok/trunk/src/five/grok/ftests/form/autofields.py
  A   five.grok/trunk/src/five/grok/ftests/form/autofields2.py
  U   five.grok/trunk/src/five/grok/ftests/test_grok_functional.py
  U   five.grok/trunk/src/five/grok/meta.py

-=-
Modified: five.grok/trunk/docs/HISTORY.txt
===================================================================
--- five.grok/trunk/docs/HISTORY.txt	2008-11-23 00:05:33 UTC (rev 93264)
+++ five.grok/trunk/docs/HISTORY.txt	2008-11-23 00:11:04 UTC (rev 93265)
@@ -7,15 +7,24 @@
 * Added support for viewlets with `grokcore.viewlet`_.
   [thefunny42]
 
+* Added support for the DirectoryResource component (new in
+  `grokcore.view`_ 1.2).
+  [thefunny42]
+
 * Added support for using Zope 2 templates by default when doing ``from
   five import grok`` and using grok.PageTemplateFile (being consistent
   with grok.PageTemplate).
   [thefunny42]
 
-* Added support for the DirectoryResource component (new in
-  `grokcore.view`_ 1.2).
+* Added a convenient grok.Container.
   [thefunny42]
 
+* Fix AutoFields (and form grokker) not to include OFS Zope 2 defined
+  fields by default. This use to add a lot of buggy and wanted
+  fields.
+  [thefunny42]
+
+
 five.grok - 1.0a1 (2008-10-22)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

Modified: five.grok/trunk/src/five/grok/__init__.py
===================================================================
--- five.grok/trunk/src/five/grok/__init__.py	2008-11-23 00:05:33 UTC (rev 93264)
+++ five.grok/trunk/src/five/grok/__init__.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -18,9 +18,11 @@
 from grokcore.viewlet import *
 from grokcore.formlib import *
 
-from five.grok.components import View, Model, Form, AddForm
+from five.grok.components import Model, Container
+from five.grok.components import View, Form, AddForm
 from five.grok.components import EditForm, DisplayForm
 from five.grok.components import ViewletManager, Viewlet
+from five.grok.formlib import AutoFields
 
 # Temporary import explicitly path from grokcore.view (it was missing
 # in its API interface)

Modified: five.grok/trunk/src/five/grok/components.py
===================================================================
--- five.grok/trunk/src/five/grok/components.py	2008-11-23 00:05:33 UTC (rev 93264)
+++ five.grok/trunk/src/five/grok/components.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -24,7 +24,8 @@
 
 from grokcore.component.interfaces import IContext
 from grokcore.formlib.components import GrokForm as BaseGrokForm
-from grokcore.formlib.components import default_display_template, default_form_template
+from grokcore.formlib.components import default_display_template, \
+    default_form_template
 from grokcore.view.components import PageTemplate
 from grokcore.viewlet.components import Viewlet as BaseViewlet
 from grokcore.viewlet.components import ViewletManager as BaseViewletManager
@@ -41,17 +42,19 @@
 from Products.PageTemplates.Expressions import SecureModuleImporter
 from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
 from OFS.SimpleItem import SimpleItem
+from OFS.Folder import Folder
 
 import Acquisition
 
 
 class Model(SimpleItem):
-    # XXX Inheritance order is important here. If we reverse this,
-    # then containers can't be models anymore because no unambigous MRO
-    # can be established.
     interface.implements(IAttributeAnnotatable, IContext)
 
 
+class Container(Folder):
+    interface.implements(IAttributeAnnotatable, IContext)
+
+
 class View(grokcore.view.View, Acquisition.Explicit):
 
     def __init__(self, *args):

Added: five.grok/trunk/src/five/grok/formlib.py
===================================================================
--- five.grok/trunk/src/five/grok/formlib.py	                        (rev 0)
+++ five.grok/trunk/src/five/grok/formlib.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -0,0 +1,71 @@
+#############################################################################
+#
+# Copyright (c) 2008 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope import interface
+from zope.interface.interfaces import IInterface
+from zope.formlib import form
+from grokcore.formlib.formlib import interface_seen
+
+
+FORBIDDEN_PACKAGES = ['OFS.interfaces', 'webdav.interfaces',]
+
+
+def get_auto_fields(context):
+    """Get the form fields for context.
+    """
+    # for an interface context, we generate them from that interface
+    if IInterface.providedBy(context):
+        return form.Fields(context)
+    # if we have a non-interface context, we're autogenerating them
+    # from any schemas defined by the context
+    fields = form.Fields(*most_specialized_interfaces(context))
+    # we pull in this field by default, but we don't want it in our form
+    fields = fields.omit('__name__')
+    return fields
+
+
+AutoFields = get_auto_fields
+
+
+def most_specialized_interfaces(context):
+    """Get interfaces for an object without any duplicates.
+
+    Interfaces in a declaration for an object may already have been seen
+    because it is also inherited by another interface. Don't return the
+    interface twice, as that would result in duplicate names when creating
+    the form.
+
+    Don't return any interface from OFS.interfaces, since they
+    contains form fields that we don't want.
+    """
+    declaration = interface.implementedBy(context)
+    seen = []
+    for iface in declaration.flattened():
+        if interface_is_forbidden(iface):
+            continue
+        if interface_seen(seen, iface):
+            continue
+        seen.append(iface)
+    return seen
+
+
+def interface_is_forbidden(iface):
+    """Return true if the interface is coming from a Zope 2 one,
+    defining bad form fields.
+    """
+    for bad_name in FORBIDDEN_PACKAGES:
+        if iface.__identifier__.startswith(bad_name):
+            return True
+    return False
+

Added: five.grok/trunk/src/five/grok/ftests/form/autofields.py
===================================================================
--- five.grok/trunk/src/five/grok/ftests/form/autofields.py	                        (rev 0)
+++ five.grok/trunk/src/five/grok/ftests/form/autofields.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -0,0 +1,66 @@
+"""
+  >>> from five.grok.ftests.form.autofields import *
+  >>> id = getRootFolder()._setObject("manfred", Mammoth(id='manfred'))
+
+  >>> from Products.Five.testbrowser import Browser
+  >>> browser = Browser()
+  >>> browser.handleErrors = False
+
+  We can test the display form as default view:
+
+  >>> browser.open("http://localhost/manfred")
+  >>> print browser.contents
+  <html>...
+  ... Name ...
+  ... Age ...
+  </html>
+
+  But we have an edition form:
+
+  >>> browser.open("http://localhost/manfred/edit")
+  >>> browser.getControl('Name').value = 'Arthur'
+  >>> browser.getControl('Age').value = '325'
+  >>> browser.getControl('Apply').click()
+  >>> 'Updated' in browser.contents
+  True
+
+  And if we look back to the display form, we will see new values:
+
+  >>> browser.open("http://localhost/manfred")
+  >>> print browser.contents
+  <html>...
+  ... Name ...
+  ... Arthur ...
+  ... Age ...
+  ... 325 ...
+  </html>
+
+"""
+
+from five import grok
+from zope import interface, schema
+from zope.schema.fieldproperty import FieldProperty
+
+
+class IMammoth(interface.Interface):
+
+    name = schema.TextLine(title=u"Name")
+    age = schema.Int(title=u"Age")
+
+
+class Mammoth(grok.Model):
+
+    grok.implements(IMammoth)
+
+    name = FieldProperty(IMammoth['name'])
+    age = FieldProperty(IMammoth['age'])
+
+
+class Edit(grok.EditForm):
+    grok.context(Mammoth)
+
+
+class Index(grok.DisplayForm):
+    pass
+
+

Added: five.grok/trunk/src/five/grok/ftests/form/autofields2.py
===================================================================
--- five.grok/trunk/src/five/grok/ftests/form/autofields2.py	                        (rev 0)
+++ five.grok/trunk/src/five/grok/ftests/form/autofields2.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -0,0 +1,67 @@
+"""
+  >>> from five.grok.ftests.form.autofields2 import *
+  >>> id = getRootFolder()._setObject("montparnasse", House(id='montparnasse'))
+
+  >>> from Products.Five.testbrowser import Browser
+  >>> browser = Browser()
+  >>> browser.handleErrors = False
+
+  We can test the display form as default view:
+
+  >>> browser.open("http://localhost/montparnasse")
+  >>> print browser.contents
+  <html>...
+  ... Name of the building ...
+  ... Number of floors ...
+  </html>
+
+  But we have an edition form:
+
+  >>> browser.open("http://localhost/montparnasse/edit")
+  >>> browser.getControl('Name of the building').value = 'Tour Montparnasse'
+  >>> browser.getControl('Number of floors').value = '56'
+  >>> browser.getControl('Apply').click()
+  >>> 'Updated' in browser.contents
+  True
+
+  And if we look back to the display form, we will see new values:
+
+  >>> browser.open("http://localhost/montparnasse")
+  >>> print browser.contents
+  <html>...
+  ... Name of the building ...
+  ... Tour Montparnasse ...
+  ... Number of floors ...
+  ... 56 ...
+  </html>
+
+"""
+
+from five import grok
+from zope import interface, schema
+from zope.schema.fieldproperty import FieldProperty
+
+
+class IHouse(interface.Interface):
+
+    name = schema.TextLine(title=u"Name of the building")
+    height = schema.Int(title=u"Number of floors")
+
+
+class House(grok.Container):
+
+    grok.implements(IHouse)
+
+    name = FieldProperty(IHouse['name'])
+    height = FieldProperty(IHouse['height'])
+
+
+class Edit(grok.EditForm):
+
+    form_fields = grok.AutoFields(House)
+
+
+class Index(grok.DisplayForm):
+    pass
+
+

Modified: five.grok/trunk/src/five/grok/ftests/test_grok_functional.py
===================================================================
--- five.grok/trunk/src/five/grok/ftests/test_grok_functional.py	2008-11-23 00:05:33 UTC (rev 93264)
+++ five.grok/trunk/src/five/grok/ftests/test_grok_functional.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -39,6 +39,10 @@
             continue
         if filename == '__init__.py':
             continue
+        if filename[0] in ('.', '#'):
+            # Some editor create temporary files which can be
+            # annoying.
+            continue
 
         dottedname = 'five.grok.ftests.%s.%s' % (name, filename[:-3])
         test = FunctionalDocTestSuite(

Modified: five.grok/trunk/src/five/grok/meta.py
===================================================================
--- five.grok/trunk/src/five/grok/meta.py	2008-11-23 00:05:33 UTC (rev 93264)
+++ five.grok/trunk/src/five/grok/meta.py	2008-11-23 00:11:04 UTC (rev 93265)
@@ -20,7 +20,7 @@
 
 from zope import interface, component
 from zope.publisher.interfaces.browser import IDefaultBrowserLayer
-from five.grok import components
+from five.grok import components, formlib
 from grokcore.view.meta.directoryresource import _get_resource_path
 from martian.error import GrokError
 
@@ -29,6 +29,21 @@
 
 import os.path
 
+
+class FormGrokker(martian.ClassGrokker):
+
+    martian.component(components.GrokForm)
+    martian.directive(grokcore.component.context)
+    martian.priority(800)       # Must be run before real formlib grokker.
+
+    def execute(self, factory, config, context, **kw):
+        # Set up form_fields from context class if they haven't been
+        # configured manually already using our version of get_auto_fields
+        if getattr(factory, 'form_fields', None) is None:
+            factory.form_fields = formlib.get_auto_fields(context)
+        return True
+
+
 class ViewSecurityGrokker(martian.ClassGrokker):
     martian.component(five.grok.View)
     martian.directive(grokcore.security.require, name='permission')



More information about the Checkins mailing list