[Checkins] SVN: grok/trunk/src/grok/ * first stab at grok.EditForm

Wolfgang Schnerring wosc at wosc.de
Thu Oct 19 08:09:14 EDT 2006


Log message for revision 70805:
   * first stab at grok.EditForm
   * refactored View to have module_info directly, not get it from the PageTemplate

Changed:
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/_grok.py
  U   grok/trunk/src/grok/components.py
  A   grok/trunk/src/grok/ftests/form/
  A   grok/trunk/src/grok/ftests/form/__init__.py
  A   grok/trunk/src/grok/ftests/form/form.py
  U   grok/trunk/src/grok/ftests/test_grok_functional.py
  U   grok/trunk/src/grok/interfaces.py
  A   grok/trunk/src/grok/tests/form/
  A   grok/trunk/src/grok/tests/form/__init__.py
  A   grok/trunk/src/grok/tests/form/form.py
  U   grok/trunk/src/grok/tests/test_grok.py

-=-
Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/__init__.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -30,6 +30,7 @@
 
 from grok.components import Model, Adapter, MultiAdapter, View, XMLRPC
 from grok.components import PageTemplate, Utility, Container, Traverser
+from grok.components import EditForm
 from grok.directive import context, name, template, templatedir
 from grok._grok import do_grok as grok  # Avoid name clash within _grok
 from grok._grok import SubscribeDecorator as subscribe

Modified: grok/trunk/src/grok/_grok.py
===================================================================
--- grok/trunk/src/grok/_grok.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/_grok.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -106,7 +106,7 @@
     register_views(context, views, templates)
     register_xmlrpc(context, xmlrpc_views)
     register_traversers(context, traversers)
-    register_unassociated_templates(context, templates)
+    register_unassociated_templates(context, templates, module_info)
     register_subscribers(subscribers)
 
 
@@ -132,8 +132,13 @@
 
         if isinstance(obj, grok.PageTemplate):
             templates.register(name, obj)
-            obj._annotateGrokInfo(module_info, name, module_info.dotted_name)
+            obj._annotateGrokInfo(name, module_info.dotted_name)
             continue
+        # XXX refactor
+        elif util.check_subclass(obj, grok.View):
+            obj.module_info = module_info
+            components[grok.View].append(obj)
+            continue
 
         for candidate_class, found_list in components.items():
             if util.check_subclass(obj, candidate_class):
@@ -168,10 +173,7 @@
             f.close()
 
             template = grok.PageTemplate(contents)
-            template._annotateGrokInfo(module_info, template_name,
-                                       template_path)
-            #template.__grok_name__ = template_name
-            #template.__grok_location__ = template_path
+            template._annotateGrokInfo(template_name, template_path)
 
             inline_template = templates.get(template_name)
             if inline_template:
@@ -282,12 +284,14 @@
                                  adapts=(factory_context, IBrowserRequest),
                                  provides=IBrowserPublisher)
 
-def register_unassociated_templates(context, templates):
+def register_unassociated_templates(context, templates, module_info):
     for name, unassociated in templates.listUnassociatedTemplates():
         util.check_context(unassociated, context)
 
+        module_info_ = module_info
         class TemplateView(grok.View):
             template = unassociated
+            module_info = module_info_
 
         templates.markAssociated(name)
 

Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/components.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -17,12 +17,16 @@
 import persistent
 from zope import component
 from zope import interface
+from zope import schema
 from zope.security.proxy import removeSecurityProxy
 from zope.publisher.browser import BrowserPage
 from zope.publisher.interfaces import NotFound
 from zope.publisher.interfaces.browser import (IBrowserPublisher,
                                                IBrowserRequest)
 from zope.pagetemplate import pagetemplate
+from zope.formlib import form
+from zope.formlib.namedtemplate import INamedTemplate
+from zope.schema.interfaces import IField
 
 from zope.app.pagetemplate.engine import TrustedAppPT
 from zope.app.publisher.browser import getDefaultViewName
@@ -34,9 +38,14 @@
 from grok import util, security
 
 class Model(persistent.Persistent):
-    pass
+    def __new__(class_, *args, **kw):
+        instance = super(Model, class_).__new__(class_, args, kw)
 
+        for field in schema_fields(instance):
+            setattr(instance, field.__name__, None)
 
+        return instance
+
 class Container(BTreeContainer):
     pass
 
@@ -61,6 +70,8 @@
         # Jim would say: WAAAAAAAAAAAAH!
         self.context = removeSecurityProxy(context)
         self.request = removeSecurityProxy(request)
+        self.directory_resource = component.queryAdapter(self.request,
+                interface.Interface, name=self.module_info.package_dotted_name)
 
     def __call__(self):
         self.before()
@@ -73,12 +84,8 @@
         namespace['request'] = self.request
         namespace['view'] = self
         namespace['context'] = self.context
-
-        module_info = template.__grok_module_info__
-        directory_resource = component.queryAdapter(self.request,
-                interface.Interface, name=module_info.package_dotted_name)
-        # XXX need to check whether we really want None here
-        namespace['static'] = directory_resource
+        # XXX need to check whether we really want to put None here if missing
+        namespace['static'] = self.directory_resource
         return template.pt_render(namespace)
 
     def __getitem__(self, key):
@@ -113,8 +120,7 @@
         return '<%s template in %s>' % (self.__grok_name__,
                                         self.__grok_location__)
 
-    def _annotateGrokInfo(self, module_info, name, location):
-        self.__grok_module_info__ = module_info
+    def _annotateGrokInfo(self, name, location):
         self.__grok_name__ = name
         self.__grok_location__ = location
 
@@ -147,7 +153,6 @@
         resource.__name__ = self.__name
         return resource
 
-
 class Traverser(object):
     interface.implements(IBrowserPublisher)
 
@@ -184,3 +189,30 @@
         traverser = util.class_annotation(self.context, 'grok.traverse', None)
         if traverser:
             return traverser(name)
+
+class EditForm(View, form.EditForm):
+    def __init__(self, context, request):
+        super(EditForm, self).__init__(context, request)
+
+        fields = schema_fields(self.context)
+        self.form_fields = form.Fields(*fields)
+            
+        self.template = component.getAdapter(self, INamedTemplate,
+                                             name='default')
+
+    def __call__(self):
+        self.before()
+        self.update()
+        return self.render()
+
+def schema_fields(obj):
+    fields = []
+    fields_class = getattr(obj, 'fields', None)
+    if fields_class is not None:
+        for name in dir(fields_class):
+            field = getattr(fields_class, name)
+            if IField.providedBy(field):
+                if not getattr(field, '__name__', None):
+                    field.__name__ = name
+                fields.append(field)
+    return fields

Added: grok/trunk/src/grok/ftests/form/__init__.py
===================================================================
--- grok/trunk/src/grok/ftests/form/__init__.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/ftests/form/__init__.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -0,0 +1 @@
+# this is a package

Added: grok/trunk/src/grok/ftests/form/form.py
===================================================================
--- grok/trunk/src/grok/ftests/form/form.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/ftests/form/form.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -0,0 +1,32 @@
+"""
+A grok.EditForm is a special grok.View that renders an edit form.
+
+  >>> import grok
+  >>> from grok.ftests.form.form import Mammoth
+  >>> grok.grok('grok.ftests.form.form')
+  >>> getRootFolder()["manfred"] = Mammoth()
+
+  >>> from zope.testbrowser.testing import Browser
+  >>> browser = Browser()
+  >>> browser.handleErrors = False
+  >>> browser.open("http://localhost/manfred/@@edit")
+  >>> browser.getControl(name="form.name").value = "Manfred the Mammoth"
+  >>> browser.getControl(name="form.size").value = "Really big"
+  >>> browser.getControl("Apply").click()
+  >>> print browser.contents
+  <!DOCTYPE ...
+  ...Manfred the Mammoth...
+  ...Really big...
+  ...
+
+"""
+import grok
+from zope import schema
+
+class Mammoth(grok.Model):
+    class fields:
+        name = schema.TextLine(title=u"Name")
+        size = schema.TextLine(title=u"Size")
+
+class Edit(grok.EditForm):
+    pass

Modified: grok/trunk/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/trunk/src/grok/ftests/test_grok_functional.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/ftests/test_grok_functional.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -56,7 +56,7 @@
 
 def test_suite():
     suite = unittest.TestSuite()
-    for name in ['view', 'static', 'xmlrpc', 'traversal']:
+    for name in ['view', 'static', 'xmlrpc', 'traversal', 'form']:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/interfaces.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -26,6 +26,7 @@
     View = interface.Attribute("Base class for browser views.")
     XMLRPC = interface.Attribute("Base class for XML-RPC methods.")
     Traverser = interface.Attribute("Base class for custom traversers.")
+    EditForm = interface.Attribute("Base class for edit forms.")
 
 class IGrokErrors(interface.Interface):
 

Added: grok/trunk/src/grok/tests/form/__init__.py
===================================================================
--- grok/trunk/src/grok/tests/form/__init__.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/tests/form/__init__.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -0,0 +1 @@
+# this is a package

Added: grok/trunk/src/grok/tests/form/form.py
===================================================================
--- grok/trunk/src/grok/tests/form/form.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/tests/form/form.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -0,0 +1,45 @@
+"""
+A grok.Model may contain a nested class named 'fields'. All attributes of
+'fields' that provide IField will cause attributes of the same name to appear on
+the grok.Model:
+
+  >>> grok.grok(__name__)
+  >>> manfred = Mammoth()
+  >>> print manfred.name
+  None
+  >>> print manfred.size
+  None
+  >>> manfred.somethingelse
+  Traceback (most recent call last):
+    ...
+  AttributeError: 'Mammoth' object has no attribute 'somethingelse'
+
+A grok.EditForm is a special grok.View that renders an edit form.
+
+We need to set up the default formlib template first, because even though we
+don't use the formlib NamedTemplates directly they need to be present to create
+a formlib form.
+
+  >>> from zope import component
+  >>> from zope.formlib import form
+  >>> component.provideAdapter(form.default_page_template, name='default')
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+  >>> view = component.getMultiAdapter((manfred, request), name='edit')
+  >>> len(view.form_fields)
+  2
+  >>> [w.__name__ for w in view.form_fields]
+  ['name', 'size']
+"""
+import grok
+from zope import schema
+
+class Mammoth(grok.Model):
+    class fields:
+        name = schema.TextLine(title=u"Name")
+        size = schema.TextLine(title=u"Size")
+        somethingelse = None
+
+class Edit(grok.EditForm):
+    pass

Modified: grok/trunk/src/grok/tests/test_grok.py
===================================================================
--- grok/trunk/src/grok/tests/test_grok.py	2006-10-19 11:57:45 UTC (rev 70804)
+++ grok/trunk/src/grok/tests/test_grok.py	2006-10-19 12:09:13 UTC (rev 70805)
@@ -34,7 +34,7 @@
     suite = unittest.TestSuite()
     for name in ['adapter', 'error', 'view', 'security', 'scan', 'event',
                  'zcml', 'static', 'utility', 'xmlrpc', 'container',
-                 'traversal']:
+                 'traversal', 'form']:
         suite.addTest(suiteFromPackage(name))
     return suite
 



More information about the Checkins mailing list