[Checkins] SVN: grok/branches/snowsprint-viewlets2/src/grok/ Make it possible for viewlets to auto-associate with a viewlet manager.

Martijn Faassen faassen at infrae.com
Thu Jan 24 12:54:29 EST 2008


Log message for revision 83184:
  Make it possible for viewlets to auto-associate with a viewlet manager.
  Refactored the way context is determined into a more generic functionality
  that can also determine the module-level viewletmanager.
  

Changed:
  A   grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association.py
  A   grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association_templates/
  A   grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association_templates/index.pt
  U   grok/branches/snowsprint-viewlets2/src/grok/meta.py
  A   grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_ambiguous_manager.py
  U   grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_render_and_template.py
  U   grok/branches/snowsprint-viewlets2/src/grok/util.py

-=-
Added: grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association.py
===================================================================
--- grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association.py	                        (rev 0)
+++ grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association.py	2008-01-24 17:54:28 UTC (rev 83184)
@@ -0,0 +1,33 @@
+"""
+We check whether viewlets automatically associate with a viewletmanager (if
+only one of them is present).
+
+Set up the model object to view::
+
+  >>> root = getRootFolder()
+  >>> root['cave'] = Cave()
+
+Viewing the cave object should result in the viewlet being displayed::
+
+  >>> from zope.testbrowser.testing import Browser
+  >>> browser = Browser()
+  >>> browser.handleErrors = False
+  >>> browser.open("http://localhost/cave")
+  >>> print browser.contents
+  Me say HI
+
+"""
+import grok
+
+class CavemenViewletManager(grok.ViewletManager):
+    grok.name('manage.cavemen')
+
+class FredViewlet(grok.Viewlet):
+    def render(self):
+        return "Me say HI"
+
+class Cave(grok.Model):
+    pass
+
+class Index(grok.View):
+    pass

Added: grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association_templates/index.pt
===================================================================
--- grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association_templates/index.pt	                        (rev 0)
+++ grok/branches/snowsprint-viewlets2/src/grok/ftests/viewlet/viewlet_manager_association_templates/index.pt	2008-01-24 17:54:28 UTC (rev 83184)
@@ -0,0 +1 @@
+<tal:block replace="structure provider:manage.cavemen" />

Modified: grok/branches/snowsprint-viewlets2/src/grok/meta.py
===================================================================
--- grok/branches/snowsprint-viewlets2/src/grok/meta.py	2008-01-24 17:48:16 UTC (rev 83183)
+++ grok/branches/snowsprint-viewlets2/src/grok/meta.py	2008-01-24 17:54:28 UTC (rev 83184)
@@ -49,16 +49,20 @@
 import grok
 from grok import components, formlib, templatereg
 from grok.util import check_adapts, get_default_permission, make_checker
-from grok.util import check_context, determine_module_context
-from grok.util import determine_class_context
+from grok.util import check_module_component, determine_module_component
+from grok.util import determine_class_component
 from grok.util import determine_class_directive, public_methods_from_class
 from grok.rest import RestPublisher
 from grok.interfaces import IRESTSkinType
 
 def get_context(module_info, factory):
-    context = module_info.getAnnotation('grok.context', None)
-    return determine_class_context(factory, context)
+    return determine_class_component(module_info, factory,
+                                     'context', 'grok.context')
 
+def get_viewletmanager(module_info, factory):
+    return determine_class_component(module_info, factory,
+                                     'viewletmanager', 'grok.viewletmanager')
+
 def get_name_classname(factory):
     return get_name(factory, factory.__name__.lower())
 
@@ -76,13 +80,23 @@
     priority = 1001
 
     def grok(self, name, module, module_info, config, **kw):
-        possible_contexts = martian.scan_for_classes(module, [grok.Model,
-                                                              grok.Container])
-        context = determine_module_context(module_info, possible_contexts)
+        context = determine_module_component(module_info, 'grok.context',
+                                             [grok.Model, grok.Container])
         module.__grok_context__ = context
         return True
 
 
+class ViewletManagerContextGrokker(martian.GlobalGrokker):
+
+    priority = 1001
+
+    def grok(self, name, module, module_info, config, **kw):
+        viewletmanager = determine_module_component(module_info,
+                                                    'grok.viewletmanager',
+                                                    [grok.ViewletManager])
+        module.__grok_viewletmanager__ = viewletmanager
+        return True
+    
 class AdapterGrokker(martian.ClassGrokker):
     component_class = grok.Adapter
 
@@ -454,7 +468,8 @@
             if interfaces is None:
                 # There's no explicit interfaces defined, so we assume the
                 # module context to be the thing adapted.
-                check_context(module_info.getModule(), context)
+                check_module_component(module_info.getModule(), context,
+                                       'context', 'grok.context')
                 interfaces = (context, )
 
             config.action(
@@ -887,15 +902,15 @@
 
         view = determine_class_directive('grok.view', factory,
                                          module_info, default=IBrowserView)
-        view_layer = determine_class_directive('grok.layer', factory,
-                                               module_info,
-                                               default=IDefaultBrowserLayer)
+        viewlet_layer = determine_class_directive('grok.layer', factory,
+                                                  module_info,
+                                                  default=IDefaultBrowserLayer)
 
         config.action(
-            discriminator = ('viewletManager', view_context, view_layer,
+            discriminator = ('viewletManager', view_context, viewlet_layer,
                              view, name),
             callable = component.provideAdapter,
-            args = (factory, (view_context, view_layer, view),
+            args = (factory, (view_context, viewlet_layer, view),
                     IViewletManager, name)
             )
 
@@ -906,7 +921,7 @@
 
     def grok(self, name, factory, module_info, config, **kw):
         viewlet_name = get_name_classname(factory)
-        view_context = get_context(module_info, factory)
+        viewlet_context = get_context(module_info, factory)
 
         factory.module_info = module_info # to make /static available
 
@@ -920,20 +935,16 @@
     
         view = determine_class_directive('grok.view', factory,
                                          module_info, default=IBrowserView)
-        view_layer = determine_class_directive('grok.layer', factory,
-                                               module_info,
-                                               default=IDefaultBrowserLayer)
-        viewletmanager = determine_class_directive('grok.viewletmanager',
-                                                   factory, module_info,
-                                                   None)
-        if viewletmanager is None:
-            raise GrokError("XXX This is a temporary grok error")
+        viewlet_layer = determine_class_directive('grok.layer', factory,
+                                                  module_info,
+                                                  default=IDefaultBrowserLayer)
+        viewletmanager = get_viewletmanager(module_info, factory)
     
         config.action(
-            discriminator = ('viewlet', view_context, view_layer,
+            discriminator = ('viewlet', viewlet_context, viewlet_layer,
                              view, viewletmanager, viewlet_name),
             callable = component.provideAdapter,
-            args = (factory, (view_context, view_layer, view,
+            args = (factory, (viewlet_context, viewlet_layer, view,
                     viewletmanager), IViewlet, viewlet_name)
             )
 

Added: grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_ambiguous_manager.py
===================================================================
--- grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_ambiguous_manager.py	                        (rev 0)
+++ grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_ambiguous_manager.py	2008-01-24 17:54:28 UTC (rev 83184)
@@ -0,0 +1,29 @@
+"""
+When there are two or more viewletmanagers available in the module,
+a viewlet will not auto-associate but instead raise an error.
+
+  >>> grok.testing.grok(__name__)
+  Traceback (most recent call last):
+    ...
+  GrokError: Multiple possible viewletmanagers for <class 'grok.tests.viewlet.viewlet_ambiguous_manager.Viewlet'>, please use grok.viewletmanager.
+
+"""
+
+import grok
+from zope.interface import Interface
+
+class ViewletManager(grok.ViewletManager):
+    grok.name('foo')
+    grok.context(Interface)
+
+class ViewletManager2(grok.ViewletManager):
+    grok.name('bar')
+    grok.context(Interface)
+    
+class Viewlet(grok.Viewlet):
+    grok.context(Interface)
+    
+    def render(self):
+        return "Render method"
+
+

Modified: grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_render_and_template.py
===================================================================
--- grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_render_and_template.py	2008-01-24 17:48:16 UTC (rev 83183)
+++ grok/branches/snowsprint-viewlets2/src/grok/tests/viewlet/viewlet_render_and_template.py	2008-01-24 17:54:28 UTC (rev 83184)
@@ -1,5 +1,5 @@
 """
-We viewlet is not allowed to define its own render method and have a template
+A viewlet is not allowed to define its own render method and have a template
 associated with it at the same time.
 
   >>> grok.testing.grok(__name__)

Modified: grok/branches/snowsprint-viewlets2/src/grok/util.py
===================================================================
--- grok/branches/snowsprint-viewlets2/src/grok/util.py	2008-01-24 17:48:16 UTC (rev 83183)
+++ grok/branches/snowsprint-viewlets2/src/grok/util.py	2008-01-24 17:54:28 UTC (rev 83184)
@@ -25,7 +25,7 @@
 from zope.security.interfaces import IPermission
 
 from martian.error import GrokError, GrokImportError
-from martian.util import class_annotation, methods_from_class
+from martian.util import class_annotation, methods_from_class, scan_for_classes
 
 def check_adapts(class_):
     if component.adaptedBy(class_) is None:
@@ -125,32 +125,66 @@
     # if components have a grok.order directive, sort by that
     return sorted(components, key=_sort_key)
 
-AMBIGUOUS_CONTEXT = object()
-def check_context(component, context):
-    if context is None:
-        raise GrokError("No module-level context for %r, please use "
-                        "grok.context." % component, component)
-    elif context is AMBIGUOUS_CONTEXT:
-        raise GrokError("Multiple possible contexts for %r, please use "
-                        "grok.context." % component, component)
+AMBIGUOUS_COMPONENT = object()
+def check_module_component(factory, component,
+                           component_name, component_directive):
+    """Raise error if module-level component cannot be determined.
 
-def determine_module_context(module_info, models):
-    if len(models) == 0:
-        context = None
-    elif len(models) == 1:
-        context = models[0]
-    else:
-        context = AMBIGUOUS_CONTEXT
+    If the module-level component is None, it's never been specified;
+    raise error telling developer to specify.
 
-    module_context = module_info.getAnnotation('grok.context', None)
-    if module_context:
-        context = module_context
+    if the module-level component is AMBIGUOUS_COMPONENT, raise
+    an error telling developer to specify which one to use.
+    """
+    if component is None:
+        raise GrokError("No module-level %s for %r, please use "
+                        "%s." % (component_name, factory, component_directive),
+                        factory)
+    elif component is AMBIGUOUS_COMPONENT:
+        raise GrokError("Multiple possible %ss for %r, please use "
+                        "%s." % (component_name, factory, component_directive),
+                        factory)
+    
+def determine_module_component(module_info, annotation, classes):
+    """Determine module-level component.
 
-    return context
+    The module-level component can be set explicitly using the
+    annotation (such as grok.context).
 
+    If there is no annotation, the module-level component is determined
+    by scanning for subclasses of any in the list of classes.
 
-def determine_class_context(class_, module_context):
-    context = class_annotation(class_, 'grok.context', module_context)
-    check_context(class_, context)
-    return context
+    If there is no module-level component, the module-level component is
+    None.
 
+    If there is one module-level component, it is returned.
+
+    If there are more than one module-level component, AMBIGUOUS_COMPONENT
+    is returned.
+    """
+    components = scan_for_classes(module_info.getModule(), classes)
+    if len(components) == 0:
+        component = None
+    elif len(components) == 1:
+        component = components[0]
+    else:
+        component= AMBIGUOUS_COMPONENT
+        
+    module_component = module_info.getAnnotation(annotation, None)
+    if module_component:
+        component = module_component
+    return component
+
+
+def determine_class_component(module_info, class_,
+                              component_name, component_directive):
+    """Determine component for a class.
+
+    Determine a component for a class. If no class-specific component exists,
+    try falling back on module-level component.
+    """
+    module_component = module_info.getAnnotation(component_directive, None)
+    component = class_annotation(class_, component_directive, module_component)
+    check_module_component(class_, component,
+                           component_name, component_directive)
+    return component



More information about the Checkins mailing list