[Checkins] SVN: grok/branches/darrylcousins-martian-layers/ Making a start working on viewlet/layer pattern used by form demo

Darryl Cousins darryl at darrylcousins.net.nz
Sat Jun 30 08:37:37 EDT 2007


Log message for revision 77268:
  Making a start working on viewlet/layer pattern used by form demo

Changed:
  U   grok/branches/darrylcousins-martian-layers/buildout.cfg
  U   grok/branches/darrylcousins-martian-layers/ftesting.zcml
  U   grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py
  U   grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt
  U   grok/branches/darrylcousins-martian-layers/setup.py
  U   grok/branches/darrylcousins-martian-layers/src/grok/__init__.py
  U   grok/branches/darrylcousins-martian-layers/src/grok/components.py
  U   grok/branches/darrylcousins-martian-layers/src/grok/directive.py
  U   grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py
  U   grok/branches/darrylcousins-martian-layers/src/grok/meta.py

-=-
Modified: grok/branches/darrylcousins-martian-layers/buildout.cfg
===================================================================
--- grok/branches/darrylcousins-martian-layers/buildout.cfg	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/buildout.cfg	2007-06-30 12:37:37 UTC (rev 77268)
@@ -1,5 +1,5 @@
 [buildout]
-develop = . grokwiki ldapaddressbook martian
+develop = . grokwiki ldapaddressbook martian demo
 parts = app data instance test devpython
 find-links = http://download.zope.org/distribution/
 
@@ -11,15 +11,18 @@
 eggs = grok
        grokwiki
        martian
+       demo
 recipe = zc.zope3recipes:app
 site.zcml = <include package="zope.security" file="meta.zcml" />
             <include package="zope.i18n" file="meta.zcml" />
             <include package="zope.app.securitypolicy" file="meta.zcml" />
             <include package="zope.app.zcmlfiles" file="meta.zcml" />
+            <include package="zope.viewlet" file="meta.zcml" />
             <include package="grok" file="meta.zcml" />
 
             <include package="zope.annotation" />
             <include package="zope.copypastemove" />
+            <include package="zope.contentprovider" />
             <include package="zope.formlib" />
             <include package="zope.i18n.locales" />
             <include package="zope.publisher" />
@@ -27,6 +30,7 @@
             <include package="zope.traversing" />
             <include package="zope.traversing.browser" />
             <include package="zope.publisher" />
+            <include package="zope.viewlet" />
             <include package="zope.app.zcmlfiles" />
             <include package="zope.app.securitypolicy" />
             <include package="zope.app.authentication" />
@@ -34,9 +38,9 @@
             <include package="zope.app.intid" />
             <include package="zope.app.keyreference" />
             <include package="zope.app.twisted" />
-            <include package="martian" />
             <include package="grok" />
             <include package="grokwiki" />
+            <include package="demo" />
 
             <securityPolicy 
                 component="zope.app.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
@@ -81,6 +85,7 @@
 recipe = zc.recipe.testrunner
 eggs = grok
        martian
+       demo
 defaults = ['--tests-pattern', '^f?tests$', '-v']
 
 # installs bin/devpython to do simple interpreter tests

Modified: grok/branches/darrylcousins-martian-layers/ftesting.zcml
===================================================================
--- grok/branches/darrylcousins-martian-layers/ftesting.zcml	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/ftesting.zcml	2007-06-30 12:37:37 UTC (rev 77268)
@@ -8,12 +8,14 @@
   <!-- used for functional testing setup -->
   <include package="zope.security" file="meta.zcml" />
   <include package="zope.i18n" file="meta.zcml" />
+  <include package="zope.viewlet" file="meta.zcml" />
   <include package="zope.app.securitypolicy" file="meta.zcml" />
   <include package="zope.app.zcmlfiles" file="meta.zcml" />
   <include package="grok" file="meta.zcml" />
 
   <include package="zope.annotation" />
   <include package="zope.copypastemove" />
+  <include package="zope.contentprovider" />
   <include package="zope.formlib" />
   <include package="zope.i18n.locales" />
   <include package="zope.publisher" />
@@ -21,6 +23,7 @@
   <include package="zope.traversing" />
   <include package="zope.traversing.browser" />
   <include package="zope.publisher" />
+  <include package="zope.viewlet" />
   <include package="zope.app.zcmlfiles" />
   <include package="zope.app.securitypolicy" />
   <include package="zope.app.authentication" />

Modified: grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -161,7 +161,17 @@
     Directive that accepts a single unicode/ASCII value, only once.
     """
 
+class SingleIntegerDirective(SingleValue, OnceDirective):
+    """
+    Directive that accepts a single integer value, only once.
+    """
 
+    def check_arguments(self, value):
+        if not int(value) == value:
+            raise GrokImportError("You can only pass an integer to "
+                                  "%s." % self.name)
+
+
 class MultipleTextDirective(BaseTextDirective, SingleValue,
                             MultipleTimesDirective):
     """

Modified: grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt
===================================================================
--- grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/martian/src/martian/directive.txt	2007-06-30 12:37:37 UTC (rev 77268)
@@ -80,6 +80,23 @@
   >>> classormodulecontext.__grok_qux__
   'hello world'
 
+Now let's define an integer directive::
+
+  >>> from martian.directive import SingleIntegerDirective
+  >>> weight = SingleIntegerDirective('grok.weight', ClassDirectiveContext())
+  >>> class Test(object):
+  ...   weight('2')
+  Traceback (most recent call last):
+    ...
+  GrokImportError: You can only pass an integer to grok.weight.
+
+Integers only are allowed::
+
+  >>> class Test(object):
+  ...   weight(2)
+  >>> Test.__grok_weight__
+  2
+
 Calling a directive once or multiple times
 ------------------------------------------
 

Modified: grok/branches/darrylcousins-martian-layers/setup.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/setup.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/setup.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -30,6 +30,7 @@
                       'zope.app.publisher',
                       'zope.app.testing',
                       'zope.component',
+                      'zope.contentprovider',
                       'zope.configuration',
                       'zope.dottedname',
                       'zope.event',
@@ -42,10 +43,14 @@
                       'zope.security',
                       'zope.testing',
                       'zope.traversing',
+                      'zope.viewlet',
 
+                      'z3c.viewlet',
+
                       # needed for ftests and typical deployments
                       'zope.testbrowser',
                       'zope.app.twisted',
                       'zope.app.securitypolicy',
-                      'zope.app.zcmlfiles'],
+                      'zope.app.zcmlfiles',
+                      ],
 )

Modified: grok/branches/darrylcousins-martian-layers/src/grok/__init__.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/__init__.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/__init__.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -35,9 +35,11 @@
 from grok.components import Site, GlobalUtility, LocalUtility, Annotation
 from grok.components import Application, Form, AddForm, EditForm, DisplayForm
 from grok.components import Indexes, Skin, ILayer
+from grok.components import Viewlet, ViewletManager, ContentProvider
 from grok.directive import (context, name, template, templatedir, provides,
                             baseclass, global_utility, local_utility,
-                            define_permission, require, site, layer)
+                            define_permission, require, site, layer,
+                            viewletmanager, talnamespace, weight)
 from grok._grok import do_grok as grok  # Avoid name clash within _grok
 from grok._grok import grok_component
 from grok._grok import SubscribeDecorator as subscribe

Modified: grok/branches/darrylcousins-martian-layers/src/grok/components.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/components.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/components.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -51,6 +51,11 @@
 from zope.app.container.interfaces import IReadContainer
 from zope.app.component.site import SiteManagerContainer
 
+from zope.viewlet.manager import ViewletManagerBase
+from zope.viewlet.viewlet import ViewletBase
+
+from z3c.viewlet.manager import WeightOrderedViewletManager
+
 from martian import util
 
 from grok import interfaces, formlib
@@ -97,46 +102,40 @@
     pass
 
 
-class View(BrowserPage):
-    interface.implements(interfaces.IGrokView)
+class ViewBase(object):
 
-    def __init__(self, context, request):
-        super(View, self).__init__(context, request)
-        self.static = component.queryAdapter(
-            self.request,
-            interface.Interface,
-            name=self.module_info.package_dotted_name
-            )
-
-    @property
-    def response(self):
-        return self.request.response
-
-    def __call__(self):
-        mapply(self.update, (), self.request)
-        if self.request.response.getStatus() in (302, 303):
-            # A redirect was triggered somewhere in update().  Don't
-            # continue rendering the template or doing anything else.
-            return
-
-        template = getattr(self, 'template', None)
-        if template is not None:
-            return self._render_template()
-        return mapply(self.render, (), self.request)
-
     def _render_template(self):
         namespace = self.template.pt_getContext()
         namespace['request'] = self.request
         namespace['view'] = self
         namespace['context'] = self.context
-        # XXX need to check whether we really want to put None here if missing
         namespace['static'] = self.static
         return self.template.pt_render(namespace)
 
-    def __getitem__(self, key):
-        # XXX give nice error message if template is None
-        return self.template.macros[key]
+    def application(self):
+        obj = self.context
+        while obj is not None:
+            if isinstance(obj, Application):
+                return obj
+            obj = obj.__parent__
+        raise ValueErrror("No application found.")
 
+    def site(self):
+        obj = self.context
+        while obj is not None:
+            if isinstance(obj, grok.Site):
+                return obj
+            obj = obj.__parent__
+        raise ValueErrror("No site found.")
+
+    def application_url(self, name=None):
+        obj = self.context
+        while obj is not None:
+            if isinstance(obj, Application):
+                return self.url(obj, name)
+            obj = obj.__parent__
+        raise ValueErrror("No application found.")
+
     def url(self, obj=None, name=None):
         # if the first argument is a string, that's the name. There should
         # be no second argument
@@ -155,18 +154,42 @@
             # create URL to view on context
             obj = self.context
         return url(self.request, obj, name)
-
-    def application_url(self, name=None):
-        obj = self.context
-        while obj is not None:
-            if isinstance(obj, Application):
-                return self.url(obj, name)
-            obj = obj.__parent__
-        raise ValueError("No application found.")
-
+        
     def redirect(self, url):
         return self.request.response.redirect(url)
+        
+    @property
+    def response(self):
+        return self.request.response
 
+
+class View(BrowserPage, ViewBase):
+    interface.implements(interfaces.IGrokView)
+
+    def __init__(self, context, request):
+        super(View, self).__init__(context, request)
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+
+    def __call__(self):
+        mapply(self.update, (), self.request)
+        if self.request.response.getStatus() in (302, 303):
+            # A redirect was triggered somewhere in update().  Don't
+            # continue rendering the template or doing anything else.
+            return
+
+        template = getattr(self, 'template', None)
+        if template is not None:
+            return self._render_template()
+        return mapply(self.render, (), self.request)
+
+    def __getitem__(self, key):
+        # XXX give nice error message if template is None
+        return self.template.macros[key]
+
     def update(self):
         pass
 
@@ -472,3 +495,69 @@
 class Skin(object):
     pass
 
+class TemplateContentBase(object):
+    """Mixin class to provide render method using given template"""
+
+    def render(self):
+        mapply(self.update, (), self.request)
+        if self.request.response.getStatus() in (302, 303):
+            # A redirect was triggered somewhere in update().  Don't
+            # continue rendering the template or doing anything else.
+            return
+
+        template = getattr(self, 'template', None)
+        if template is not None:
+            return self._render_template()
+
+
+class ContentProvider(ViewBase, TemplateContentBase):
+
+    def __init__(self, context, request, view):
+        self.__parent__ = view
+        self.context = context
+        self.request = request
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )        
+        return self.request.response
+
+# use z3c orderedviewletmanager
+class ViewletManager(WeightOrderedViewletManager, ViewBase):
+    """  A grok.View-like ViewletManager
+    """
+    template = None
+
+    def __init__(self, context, request, view):
+        super(ViewletManager, self).__init__(context, request, view)
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+
+    def update(self):
+        super(WeightOrderedViewletManager, self).update()
+
+    def render(self):
+        # Now render the view
+        template = getattr(self, 'template', None)
+        if template is not None:
+            return self._render_template()
+        else:
+            return u'\n'.join([viewlet.render() for viewlet in self.viewlets])
+
+
+class Viewlet(ViewletBase, ViewBase, TemplateContentBase):
+    """ A grok.View-like viewlet
+    """
+
+    def __init__(self, context, request, view, manager):
+        super(Viewlet, self).__init__(context, request, view, manager)
+        self.static = component.queryAdapter(
+            self.request,
+            interface.Interface,
+            name=self.module_info.package_dotted_name
+            )
+

Modified: grok/branches/darrylcousins-martian-layers/src/grok/directive.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/directive.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/directive.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -19,6 +19,7 @@
 from martian.error import GrokImportError
 from martian.directive import (MultipleTimesDirective, BaseTextDirective,
                                SingleValue, SingleTextDirective,
+                               SingleIntegerDirective,
                                MultipleTextDirective,
                                MarkerDirective,
                                InterfaceDirective,
@@ -112,3 +113,8 @@
                                  ClassDirectiveContext())
 layer = InterfaceOrClassDirective('grok.layer',
                            ClassOrModuleDirectiveContext())
+viewletmanager = InterfaceOrClassDirective('grok.viewletmanager',
+                                           ClassDirectiveContext())
+talnamespace = InterfaceDirective('grok.talnamespace',
+                               ClassDirectiveContext())
+weight = SingleIntegerDirective('grok.weight', ClassDirectiveContext())

Modified: grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/ftests/test_grok_functional.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -42,6 +42,7 @@
 
 def suiteFromPackage(name):
     files = resource_listdir(__name__, name)
+    files = ['viewletmanager.py']
     suite = unittest.TestSuite()
     for filename in files:
         if not filename.endswith('.py'):
@@ -55,10 +56,12 @@
         suite.addTest(test)
     return suite
 
+all = ['view', 'static', 'xmlrpc', 'traversal', 'form', 'url',
+                 'security', 'utility', 'catalog', 'admin']
+all = ['view']
 def test_suite():
     suite = unittest.TestSuite()
-    for name in ['view', 'static', 'xmlrpc', 'traversal', 'form', 'url',
-                 'security', 'utility', 'catalog', 'admin']:
+    for name in all:
         suite.addTest(suiteFromPackage(name))
     return suite
 

Modified: grok/branches/darrylcousins-martian-layers/src/grok/meta.py
===================================================================
--- grok/branches/darrylcousins-martian-layers/src/grok/meta.py	2007-06-30 12:13:56 UTC (rev 77267)
+++ grok/branches/darrylcousins-martian-layers/src/grok/meta.py	2007-06-30 12:37:37 UTC (rev 77268)
@@ -4,6 +4,7 @@
 from zope import interface, component
 from zope.publisher.interfaces.browser import (IDefaultBrowserLayer,
                                                IBrowserRequest,
+                                               IBrowserView,
                                                IBrowserPublisher,
                                                IBrowserSkinType)
 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
@@ -22,6 +23,7 @@
 from zope.app.catalog.interfaces import ICatalog
 
 from zope.exceptions.interfaces import DuplicationError
+from zope.contentprovider.interfaces import IContentProvider
 
 import martian
 from martian.error import GrokError
@@ -196,7 +198,62 @@
                                 % (method.__name__, factory), factory)
         return True
 
+class ContentProviderGrokker(martian.ClassGrokker):
+    component_class = grok.ContentProvider
 
+    def grok(self, name, factory, context, module_info, templates):
+        view_context = util.determine_class_context(factory, context)
+
+        factory.module_info = module_info
+        factory_name = factory.__name__.lower()
+
+        # find templates
+        template_name = util.class_annotation(factory, 'grok.template',
+                                              factory_name)
+        template = templates.get(template_name)
+
+        if factory_name != template_name:
+            # grok.template is being used
+            if templates.get(factory_name):
+                raise GrokError("Multiple possible templates for view %r. It "
+                                "uses grok.template('%s'), but there is also "
+                                "a template called '%s'."
+                                % (factory, template_name, factory_name),
+                                factory)
+
+        if template:
+            templates.markAssociated(template_name)
+            factory.template = template
+
+        view_layer = util.class_annotation(factory, 'grok.layer',
+                                           None) or module_info.getAnnotation('grok.layer',
+                                               None) or IDefaultBrowserLayer
+
+        view_name = util.class_annotation(factory, 'grok.name',
+                                          factory_name)
+        # __view_name__ is needed to support IAbsoluteURL on views
+        factory.__view_name__ = view_name
+        component.provideAdapter(factory,
+                                 adapts=(view_context, view_layer, IBrowserView),
+                                 provides=IContentProvider,
+                                 name=view_name)
+
+        # protect view, public by default
+        default_permission = get_default_permission(factory)
+        make_checker(factory, factory, default_permission)
+
+        # safety belt: make sure that the programmer didn't use
+        # @grok.require on any of the view's methods.
+        methods = util.methods_from_class(factory)
+        for method in methods:
+            if getattr(method, '__grok_require__', None) is not None:
+                raise GrokError('The @grok.require decorator is used for '
+                                'method %r in view %r. It may only be used '
+                                'for XML-RPC methods.'
+                                % (method.__name__, factory), factory)
+        return True
+
+
 class JSONGrokker(martian.ClassGrokker):
     component_class = grok.JSON
 
@@ -614,3 +671,4 @@
         zope.component.interface.provideInterface(name, layer, IBrowserSkinType)
 
         return True
+



More information about the Checkins mailing list