[Checkins] SVN: z3c.layout/trunk/s Added plone.memoize to cache content providers for the duration of the request.

Malthe Borch mborch at gmail.com
Sun Aug 3 20:57:46 EDT 2008


Log message for revision 89335:
  Added plone.memoize to cache content providers for the duration of the request.

Changed:
  U   z3c.layout/trunk/setup.py
  U   z3c.layout/trunk/src/z3c/layout/README.txt
  U   z3c.layout/trunk/src/z3c/layout/browser/insertion.py
  U   z3c.layout/trunk/src/z3c/layout/browser/layout.py

-=-
Modified: z3c.layout/trunk/setup.py
===================================================================
--- z3c.layout/trunk/setup.py	2008-08-04 00:57:11 UTC (rev 89334)
+++ z3c.layout/trunk/setup.py	2008-08-04 00:57:46 UTC (rev 89335)
@@ -51,6 +51,7 @@
                         'zope.app.publisher',
                         'zope.contentprovider',
                         'zope.viewlet',
+                        'plone.memoize',
                         'lxml>=2.0',
                         ],
       include_package_data = True,

Modified: z3c.layout/trunk/src/z3c/layout/README.txt
===================================================================
--- z3c.layout/trunk/src/z3c/layout/README.txt	2008-08-04 00:57:11 UTC (rev 89334)
+++ z3c.layout/trunk/src/z3c/layout/README.txt	2008-08-04 00:57:46 UTC (rev 89335)
@@ -112,6 +112,12 @@
     >>> context = MockContext()
     >>> request = TestRequest()
 
+We need to have the request be annotatable.
+
+    >>> from zope.annotation.attribute import AttributeAnnotations
+    >>> component.provideAdapter(
+    ...     AttributeAnnotations, (TestRequest,))
+    
 The view expects the context to adapt to ``ILayout``.
     
     >>> from z3c.layout.interfaces import ILayout
@@ -123,9 +129,11 @@
 
 Verify that the layout view is able to get to these providers.
     
-    >>> tuple(view._get_content_providers())
-    ((<Region 'title' .//title (replace) 'title'>, <MockContentProvider 'title'>),
-     (<Region 'content' .//div (replace) None>, <MockContentProvider 'content'>))
+    >>> view.mapping
+    {'content':
+     (<Region 'content' .//div (replace) None>, <MockContentProvider 'content'>),
+     'title':
+     (<Region 'title' .//title (replace) 'title'>, <MockContentProvider 'title'>)}
 
 Now for the actual output.
 

Modified: z3c.layout/trunk/src/z3c/layout/browser/insertion.py
===================================================================
--- z3c.layout/trunk/src/z3c/layout/browser/insertion.py	2008-08-04 00:57:11 UTC (rev 89334)
+++ z3c.layout/trunk/src/z3c/layout/browser/insertion.py	2008-08-04 00:57:46 UTC (rev 89335)
@@ -1,3 +1,15 @@
+def insert(tree, region, provided):
+    # look up insertion method
+    try:
+        insert = _map[region.mode]
+    except KeyError:
+        raise ValueError("Invalid mode: %s" % repr(region.mode))
+
+    # insert provided content into nodes
+    nodes = tree.xpath(region.xpath)
+    for node in nodes:
+        insert(node, provided)
+
 def replace(node, provided):
     """Replace node with contents.
 
@@ -90,3 +102,10 @@
 
     if provided.text:
         node.tail = node.tail or "" + provided.text
+
+_map = dict(
+    replace=replace,
+    prepend=prepend,
+    append=append,
+    before=before,
+    after=after)

Modified: z3c.layout/trunk/src/z3c/layout/browser/layout.py
===================================================================
--- z3c.layout/trunk/src/z3c/layout/browser/layout.py	2008-08-04 00:57:11 UTC (rev 89334)
+++ z3c.layout/trunk/src/z3c/layout/browser/layout.py	2008-08-04 00:57:46 UTC (rev 89335)
@@ -9,28 +9,29 @@
 
 from z3c.layout import interfaces
 
+from plone.memoize.view import memoize
+
 import insertion
 
 class LayoutView(BrowserView):
     def __init__(self, context, request):
         BrowserView.__init__(self, context, request)
-        self.layout = interfaces.ILayout(context)
-                
-    def __call__(self):
-        tree = self.layout.parse()
-
-        # lookup content provider components
-        content_providers = self._get_content_providers()
         
-        # update content providers
-        for region, provider in content_providers:
-            provider.update()
+        self._layout = interfaces.ILayout(context)
+        self.mapping = self._get_region_provider_mapping()
 
+    def __call__(self):
+        # parse tree
+        tree = self._layout.parse()
+
         # render and insert content providers
-        for region, provider in content_providers:
+        for region, provider in self.mapping.values():
             self._insert_provider(tree, region, provider)
 
         return lxml.html.tostring(tree, pretty_print=True).rstrip('\n')
+
+    def get_context(self, region):
+        return region
     
     def _insert_provider(self, tree, region, provider):
         # render and wrap provided content
@@ -38,38 +39,36 @@
         provided = lxml.html.fromstring(
             u"<div>%s</div>" % html)
 
-        # look up insertion method
-        try:
-            insert = getattr(insertion, region.mode)
-        except AttributeError:
-            raise ValueError("Invalid mode: %s" % repr(region.mode))
+        insertion.insert(tree, region, provided)
 
-        # insert provided content into nodes
-        nodes = tree.xpath(region.xpath)
-        for node in nodes:
-            insert(node, provided)
+    def _get_provider(self, region):
+        """Lookup content provider for region."""
 
-    def _get_content_providers(self):
-        """Lookup content providers for regions."""
-        
-        results = []
-        
-        for region in self.layout.regions:
-            name = region.provider
+        name = region.provider
+        context = self.get_context(region)
 
-            if name is not None:
-                provider = component.queryMultiAdapter(
-                    (region, self.request, self), IContentProvider, name=name)
-            else:
-                provider = component.queryMultiAdapter(
-                    (region, self.request, self), IContentProvider)
+        if name is not None:
+            provider = component.queryMultiAdapter(
+                (context, self.request, self), IContentProvider, name=name)
+        else:
+            provider = component.queryMultiAdapter(
+                (context, self.request, self), IContentProvider)
 
-            if provider is None:
-                raise ValueError(
-                    "Unable to determine content "
-                    "provider for region '%s'." % region.name)
+        return provider
+    
+    @memoize
+    def _get_region_provider_mapping(self):
+        mapping = {}
 
-            provider.__name__ = region.name
-            results.append((region, provider))
+        for region in self._layout.regions:
+            provider = self._get_provider(region)
 
-        return results            
+            if provider is not None:
+                provider.__name__ = region.name
+                mapping[region.name] = (region, provider)
+
+        # update content providers
+        for region, provider in mapping.values():
+            provider.update()
+
+        return mapping



More information about the Checkins mailing list