[Checkins] SVN: five.pt/trunk/ Continued work on CMF bindings.

Malthe Borch mborch at gmail.com
Sat Nov 15 20:18:27 EST 2008


Log message for revision 92996:
  Continued work on CMF bindings.

Changed:
  U   five.pt/trunk/CHANGES.txt
  U   five.pt/trunk/src/five/pt/__init__.py
  A   five.pt/trunk/src/five/pt/cmf.py
  U   five.pt/trunk/src/five/pt/configure.zcml
  A   five.pt/trunk/src/five/pt/expressions.py
  U   five.pt/trunk/src/five/pt/pagetemplate.py

-=-
Modified: five.pt/trunk/CHANGES.txt
===================================================================
--- five.pt/trunk/CHANGES.txt	2008-11-16 00:27:21 UTC (rev 92995)
+++ five.pt/trunk/CHANGES.txt	2008-11-16 01:18:27 UTC (rev 92996)
@@ -4,6 +4,12 @@
 HEAD
 ----
 
+- Register custom file-system page template class for use with CMF
+  form controllers. [malthe]
+
+- Register custom file-system page template class for use with CMF
+  directory views. [malthe]
+
 - Added meta-directives to register browser views, viewlets and
   viewlet managers using Chameleon templates. [malthe]
 

Modified: five.pt/trunk/src/five/pt/__init__.py
===================================================================
--- five.pt/trunk/src/five/pt/__init__.py	2008-11-16 00:27:21 UTC (rev 92995)
+++ five.pt/trunk/src/five/pt/__init__.py	2008-11-16 01:18:27 UTC (rev 92996)
@@ -1 +1 @@
-#
\ No newline at end of file
+#

Added: five.pt/trunk/src/five/pt/cmf.py
===================================================================
--- five.pt/trunk/src/five/pt/cmf.py	                        (rev 0)
+++ five.pt/trunk/src/five/pt/cmf.py	2008-11-16 01:18:27 UTC (rev 92996)
@@ -0,0 +1,111 @@
+import sys
+import Globals
+
+from Products.CMFCore.FSObject import FSObject
+from Products.CMFCore import DirectoryView
+from Products.CMFCore import permissions
+
+from Products.CMFFormController.BaseControllerPageTemplate import \
+     BaseControllerPageTemplate as BaseCPT
+from Products.CMFFormController.FSControllerBase import FSControllerBase
+
+from Shared.DC.Scripts.Script import Script
+from AccessControl import ClassSecurityInfo
+from RestrictedPython import Utilities
+
+from pagetemplate import PageTemplateFile
+from pagetemplate import FiveTemplateFile
+
+_marker = object()
+
+class EContext(object):
+    vars = None
+    
+    def setLocal(self, name, value):
+        if self.vars is None:
+            frame = sys._getframe()
+            vars = _marker
+            while vars is _marker and frame is not None:
+                vars = frame.f_locals.get('_scope', _marker)
+                frame = frame.f_back
+            if vars is _marker:
+                raise RuntimeError, 'Context not found'
+            self.vars = vars
+        self.vars[name] = value
+
+class CMFTemplateFile(FiveTemplateFile):
+    @property
+    def utility_builtins(self):
+        builtins = dict(
+            econtext=EContext())
+        builtins.update(        
+            Utilities.utility_builtins)
+        return builtins
+
+class CMFPageTemplateFile(PageTemplateFile):
+    template_class = CMFTemplateFile
+    
+class FSPageTemplate(FSObject, Script):
+    meta_type = 'Filesystem Page Template'
+    
+    security = ClassSecurityInfo()
+    security.declareObjectProtected(permissions.View)
+
+    _default_bindings = {'name_subpath': 'traverse_subpath'}
+    
+    template = None
+    
+    def __init__(self, id, filepath, fullname=None, properties=None):
+        FSObject.__init__(self, id, filepath, fullname, properties)
+        self.ZBindings_edit(self._default_bindings)
+
+        # instantiate page template
+        self.template = CMFPageTemplateFile(filepath)
+        
+    def _readFile(self, reparse):
+        # templates are lazy
+        if reparse:
+            self.template.read()
+
+    def __call__(self, *args, **kwargs):
+        kwargs['args'] = args
+        return self.template(self, **kwargs)
+
+    @property
+    def macros(self):
+        return self.template.macros
+
+class FSControllerPageTemplate(FSControllerBase, FSPageTemplate, BaseCPT):
+    def __init__(self, id, filepath, fullname=None, properties=None):
+        FSPageTemplate.__init__(self, id, filepath, fullname, properties)  
+        self.filepath = filepath
+      
+        self._read_action_metadata(self.getId(), filepath)
+        self._read_validator_metadata(self.getId(), filepath)
+
+    def _readFile(self, reparse):
+        FSPageTemplate._readFile(self, reparse)
+        self._readMetadata()
+
+    def _updateFromFS(self):
+        # workaround for Python 2.1 multiple inheritance lameness
+        return self._baseUpdateFromFS()
+
+    def _readMetadata(self):
+        # workaround for Python 2.1 multiple inheritance lameness
+        return self._baseReadMetadata()
+
+    def __call__(self, *args, **kwargs):
+        return self._call(FSControllerPageTemplate.__call__, *args, **kwargs)
+
+Globals.InitializeClass(FSPageTemplate)
+Globals.InitializeClass(FSControllerPageTemplate)
+
+DirectoryView.registerFileExtension('pt', FSPageTemplate)
+DirectoryView.registerFileExtension('zpt', FSPageTemplate)
+DirectoryView.registerFileExtension('html', FSPageTemplate)
+DirectoryView.registerFileExtension('htm', FSPageTemplate)
+DirectoryView.registerFileExtension('cpt', FSControllerPageTemplate)
+
+DirectoryView.registerMetaType('Page Template', FSPageTemplate)
+DirectoryView.registerMetaType('Controller Page Template', FSControllerPageTemplate)

Modified: five.pt/trunk/src/five/pt/configure.zcml
===================================================================
--- five.pt/trunk/src/five/pt/configure.zcml	2008-11-16 00:27:21 UTC (rev 92995)
+++ five.pt/trunk/src/five/pt/configure.zcml	2008-11-16 01:18:27 UTC (rev 92996)
@@ -1,5 +1,16 @@
 <configure xmlns="http://namespaces.zope.org/zope">
 
+  <include package="five.pt" file="meta.zcml" />
+  <include package="five.pt.cmf" />
+  
   <include package="z3c.pt" />
 
+  <utility
+     name="path"
+     component=".expressions.path_translator" />
+
+  <utility
+     name="exists"
+     component=".expressions.exists_translator" />
+
 </configure>

Added: five.pt/trunk/src/five/pt/expressions.py
===================================================================
--- five.pt/trunk/src/five/pt/expressions.py	                        (rev 0)
+++ five.pt/trunk/src/five/pt/expressions.py	2008-11-16 01:18:27 UTC (rev 92996)
@@ -0,0 +1,57 @@
+from z3c.pt.expressions import PathTranslator
+from z3c.pt.expressions import ExistsTranslator
+from z3c.pt.expressions import ZopeExistsTraverser
+
+from zExceptions import NotFound, Unauthorized
+
+from zope.traversing.adapters import traversePathElement
+from zope.traversing.interfaces import TraversalError
+
+from Products.PageTemplates.Expressions import render
+
+_marker = object()
+
+class FiveTraverser(object):
+    def __call__(self, base, request, call, *path_items):
+        """See ``zope.app.pagetemplate.engine``."""
+
+        ob = base
+        
+        length = len(path_items)
+        if length:
+            i = 0
+            while i < length:
+                name = path_items[i]
+                i += 1
+                next = getattr(base, name, _marker)
+                if next is not _marker:
+                    base = next
+                    continue
+                else:
+                    # special-case dicts for performance reasons
+                    if isinstance(base, dict):
+                        base = base[name]
+                    else:
+                        base = traversePathElement(
+                            base, name, path_items[i:], request=request)
+
+        if call and getattr(base, '__call__', _marker) is not _marker:
+            # here's where we're different from the standard path
+            # traverser
+            return render(base, ob)
+
+        return base
+
+class PathTranslator(PathTranslator):
+    path_traverse = FiveTraverser()
+
+path_translator = PathTranslator()
+
+class FiveExistsTraverser(ZopeExistsTraverser):
+    exceptions = AttributeError, LookupError, TypeError, \
+                 NotFound, Unauthorized, TraversalError
+
+class ExistsTranslator(ExistsTranslator):
+    path_traverse = FiveExistsTraverser()
+
+exists_translator = ExistsTranslator()

Modified: five.pt/trunk/src/five/pt/pagetemplate.py
===================================================================
--- five.pt/trunk/src/five/pt/pagetemplate.py	2008-11-16 00:27:21 UTC (rev 92995)
+++ five.pt/trunk/src/five/pt/pagetemplate.py	2008-11-16 01:18:27 UTC (rev 92996)
@@ -5,22 +5,72 @@
 
 from Acquisition import aq_get
 from Acquisition import aq_inner
+from Acquisition import aq_parent
 
 from Products.PageTemplates.Expressions import SecureModuleImporter
 
 from z3c.pt import pagetemplate
 
+def get_physical_root(context):
+    method = aq_get(context, 'getPhysicalRoot', None)
+    if method is not None:
+        return method()
+
+class FiveTemplateFile(pagetemplate.PageTemplateFile.template_class):
+    utility_builtins = {}
+
+    def prepare_builtins(self, kwargs):
+        for key, value in self.utility_builtins.items():
+            kwargs.setdefault(key, value)
+
+    def render_macro(self, macro, global_scope=False, parameters=None):
+        if parameters is None:
+            parameters = {}
+        self.prepare_builtins(parameters)
+        return super(FiveTemplateFile, self).render_macro(
+            macro, global_scope=global_scope, parameters=parameters)
+
+class PageTemplateFile(pagetemplate.PageTemplateFile):
+    template_class = FiveTemplateFile
+    
+    def bind(self, parent, macro=None, global_scope=True):
+        context = aq_parent(parent)
+        request = aq_get(parent, 'REQUEST')
+        root = get_physical_root(context)
+
+        template = self.template
+
+        def render(**kwargs):
+            parameters = dict(
+                context=context,
+                request=request,
+                template=parent,
+                here=context,
+                container=context,
+                nothing=None,
+                root=root,
+                modules=SecureModuleImporter,
+                options=kwargs)
+
+            template.prepare_builtins(parameters)
+            
+            if macro is None:
+                return template.render(**parameters)
+            else:
+                return template.render_macro(
+                    macro, global_scope=global_scope, parameters=parameters)
+            
+        return render
+
+    def __call__(self, parent, **kwargs):
+        template = self.bind(parent)
+        return template(**kwargs)
+
 class ViewPageTemplate(pagetemplate.ViewPageTemplate):
     def bind(self, view, request=None, macro=None, global_scope=True):
         context = aq_inner(view.context)
         request = view.request
-        
-        # locate physical root
-        method = aq_get(context, 'getPhysicalRoot', None)
-        if method is not None:
-            root = method()
-        else:
-            root = None
+        root = get_physical_root(context)
 
         def render(**kwargs):
             parameters = dict(
@@ -47,3 +97,8 @@
 class ViewPageTemplateFile(ViewPageTemplate, pagetemplate.ViewPageTemplateFile):
     """If ``filename`` is a relative path, the module path of the
     class where the instance is used to get an absolute path."""
+
+    def getId(self):
+        return os.path.basename(self.filename)
+    
+    id = property(getId)



More information about the Checkins mailing list