[z3-checkins] r9209 - z3/Five/trunk

faassen at codespeak.net faassen at codespeak.net
Mon Feb 14 16:18:37 MET 2005


Author: faassen
Date: Mon Feb 14 16:18:37 2005
New Revision: 9209

Added:
   z3/Five/trunk/ReuseUtils.py
   z3/Five/trunk/TrustedExpression.py
   z3/Five/trunk/pagetemplatefile.py
Modified:
   z3/Five/trunk/CHANGES.txt
   z3/Five/trunk/COPYING.txt
   z3/Five/trunk/CREDITS.txt
   z3/Five/trunk/browserconfigure.py
Log:
* Use Zope 2 page templates, along the lines of Lennart's code.

* Integrate pieces of TrustedExecutables into Five, so no more dependency
  on TrustedExecutables exists.
  


Modified: z3/Five/trunk/CHANGES.txt
==============================================================================
--- z3/Five/trunk/CHANGES.txt	(original)
+++ z3/Five/trunk/CHANGES.txt	Mon Feb 14 16:18:37 2005
@@ -4,10 +4,20 @@
 Trunk
 -----
 
-* Five now supports the browser:menu, menuItem and menuItems directives.
+* Five now uses the Zope 2 page template engine, not the Zope 3
+  engine. This allows better integration with Zope 2-based page
+  templates, such as macros.
+
+  It uses TrustedExecutables technology (thanks to Dieter Maurer) to
+  turn off Zope 2 security in page templates, so Five's security
+  behavior is very similar to what it was before.
+
+* Five now supports the browser:menu, menuItem and menuItems
+  directives.
   
-  Also supports the menu parameter for page directives and subdirectives,
-  as well as editform directives. [XXX this doesn't seem to work yet]
+  Also supports the menu parameter for page directives and
+  subdirectives, as well as editform directives. [XXX this doesn't
+  seem to work yet]
 
 * A new Five-specific directive has been added:
   five:pagesFromDirectory.  This adds one page for each .pt file in a

Modified: z3/Five/trunk/COPYING.txt
==============================================================================
--- z3/Five/trunk/COPYING.txt	(original)
+++ z3/Five/trunk/COPYING.txt	Mon Feb 14 16:18:37 2005
@@ -22,3 +22,6 @@
 - metaclass.py is derived from PEAK, copyright (C) 1996-2004 by
   Phillip J. Eby and Tyler C. Sarna. PEAK may be used under the same
   terms as Zope.
+
+- TrustedExecutables. Dieter Mauer kindly allow licensing this under the
+  ZPL 2.1.
\ No newline at end of file

Modified: z3/Five/trunk/CREDITS.txt
==============================================================================
--- z3/Five/trunk/CREDITS.txt	(original)
+++ z3/Five/trunk/CREDITS.txt	Mon Feb 14 16:18:37 2005
@@ -17,11 +17,21 @@
 
 - Simon Eisenmann (simon at struktur.de)
 
+- Dieter Maurer (dieter at handshake.de)
+
 Thank you
 ---------
 
+Infrae for the initial development and continuing support.
+
 Martijn Faassen would like to thank ETH Zurich for their support and
-encouragement during the initial development of Five.
+encouragement during the initial development of Five. 
+
+Nuxeo for significant contributions to making Five usable in the real
+world.
+
+Dieter Maurer for use of code from TrustedExecutables within Five
+under the ZPL.
 
 The Five developers would like to thank the Zope 3 developers, in
 particular Jim Fulton, for the mountain to stand on.

Added: z3/Five/trunk/ReuseUtils.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/ReuseUtils.py	Mon Feb 14 16:18:37 2005
@@ -0,0 +1,17 @@
+# Copyright (C) 2004 by Dr. Dieter Maurer, Eichendorffstr. 23, D-66386 St. Ingbert, Germany
+
+from new import function
+
+def rebindFunction(f,rebindDir=None,**rebinds):
+  '''return *f* with some globals rebound.'''
+  d= {}
+  if rebindDir : d.update(rebindDir)
+  if rebinds: d.update(rebinds)
+  if not d: return f
+  f= getattr(f,'im_func',f)
+  fd= f.func_globals.copy()
+  fd.update(d)
+  nf= function(f.func_code,fd,f.func_name,f.func_defaults or ())
+  nf.__doc__= f.__doc__
+  if f.__dict__ is not None: nf.__dict__= f.__dict__.copy()
+  return nf

Added: z3/Five/trunk/TrustedExpression.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/TrustedExpression.py	Mon Feb 14 16:18:37 2005
@@ -0,0 +1,97 @@
+# Copyright (C) 2004 by Dr. Dieter Maurer, Eichendorffstr. 23, D-66386 St. Ingbert, Germany
+
+from sys import modules
+
+from Products.PageTemplates.PythonExpr import PythonExpr
+
+from Products.PageTemplates.Expressions import \
+     SubPathExpr, PathExpr, \
+     StringExpr, \
+     getEngine, installHandlers
+
+from ReuseUtils import rebindFunction
+
+
+class _ModuleImporter:
+  def __getitem__(self, module):
+    __import__(module)
+    return modules[module]
+ModuleImporter = _ModuleImporter()
+
+
+def trustedTraverse(ob, path, ignored,):
+  if not path: return self
+
+  get = getattr
+  has = hasattr
+  N = None
+  M = rebindFunction # artifical marker
+
+  if isinstance(path, str): path = path.split('/')
+  else: path=list(path)
+  
+  REQUEST={'TraversalRequestNameStack': path}
+  path.reverse()
+  pop=path.pop
+
+  if len(path) > 1 and not path[0]:
+    # Remove trailing slash
+    path.pop(0)
+
+  if not path[-1]:
+    # If the path starts with an empty string, go to the root first.
+    pop()
+    self=ob.getPhysicalRoot()
+
+  object = ob
+  while path:
+    name=pop()
+    __traceback_info__ = path, name
+
+    if name == '..':
+      o=getattr(object, 'aq_parent', M)
+      if o is not M:
+        object=o
+        continue
+
+    t=get(object, '__bobo_traverse__', M)
+    if t is not M: o=t(REQUEST, name)
+    else:
+      o = get(object, name, M)
+      if o is M:
+        try: o = object[name]
+        except AttributeError: # better exception
+          raise AttributeError(name)
+    object = o
+
+  return object
+
+
+class SubPathExpr(SubPathExpr):
+  _eval = rebindFunction(SubPathExpr._eval.im_func,
+                         restrictedTraverse=trustedTraverse,
+                         )
+
+class PathExpr(PathExpr):
+  __init__ = rebindFunction(PathExpr.__init__.im_func,
+                            SubPathExpr=SubPathExpr,
+                            )
+
+class StringExpr(StringExpr):
+  __init__ = rebindFunction(StringExpr.__init__.im_func,
+                            PathExpr=PathExpr,
+                            )
+  
+installHandlers = rebindFunction(installHandlers,
+                                 PathExpr=PathExpr,
+                                 StringExpr=StringExpr,
+                                 PythonExpr=PythonExpr,
+                                 )
+
+_engine=None
+getEngine = rebindFunction(getEngine,
+                           _engine=_engine,
+                           installHandlers=installHandlers
+                           )
+
+

Modified: z3/Five/trunk/browserconfigure.py
==============================================================================
--- z3/Five/trunk/browserconfigure.py	(original)
+++ z3/Five/trunk/browserconfigure.py	Mon Feb 14 16:18:37 2005
@@ -20,10 +20,9 @@
 from zope.configuration.exceptions import ConfigurationError
 from zope.component.servicenames import Presentation
 from zope.publisher.interfaces.browser import IBrowserRequest
-from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
-from zope.app.pagetemplate.viewpagetemplatefile import ViewMapper
 from zope.app.publisher.browser.viewmeta import pages as zope_app_pages
-from zope.app.publisher.browser.globalbrowsermenuservice import menuItemDirective
+from zope.app.publisher.browser.globalbrowsermenuservice import\
+     menuItemDirective
 from zope.app.component.metaconfigure import handler
 from zope.app.component.interface import provideInterface
 from zope.app.form.browser.metaconfigure import BaseFormDirective
@@ -33,15 +32,9 @@
 from resource import DirectoryResourceFactory
 from browser import BrowserView, EditView
 from metaclass import makeClass
-from security import getSecurityInfo, protectClass, protectName, initializeClass
-
-class FivePageTemplateFile(ViewPageTemplateFile):
-
-    def pt_getContext(self, instance, request, **_kw):
-        # instance is a View component
-        namespace = super(FivePageTemplateFile, self).pt_getContext(instance, request, **_kw)
-        namespace['here'] = namespace['context']
-        return namespace
+from security import getSecurityInfo, protectClass, protectName,\
+     initializeClass
+from pagetemplatefile import ZopeTwoPageTemplateFile
 
 
 def page(_context, name, permission, for_,
@@ -339,7 +332,7 @@
 
     class_.fulledit_label = fulledit_label
 
-    class_.generated_form = ViewPageTemplateFile(default_template)
+    class_.generated_form = ZopeTwoPageTemplateFile(default_template)
 
     # Not the prettiest solution, but it works...
     class_.__init__ = EditView.__init__
@@ -409,7 +402,7 @@
     # XXX needs to deal with security from the bases?
     if cdict is None:
         cdict = {}
-    cdict.update({'index': FivePageTemplateFile(src, template)})
+    cdict.update({'index': ZopeTwoPageTemplateFile(src, template)})
     bases += (ViewMixinForTemplates,)
     class_ = makeClass("SimpleViewClass from %s" % src, bases, cdict)
 

Added: z3/Five/trunk/pagetemplatefile.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/pagetemplatefile.py	Mon Feb 14 16:18:37 2005
@@ -0,0 +1,95 @@
+'''A 'PageTemplateFile' without security restrictions.'''
+
+import os, sys
+
+# Zope 2
+from Globals import package_home
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+# Zope 3
+from zope.app.pagetemplate.viewpagetemplatefile import ViewMapper
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+# Five
+from ReuseUtils import rebindFunction
+from TrustedExpression import getEngine, ModuleImporter
+
+class ZopeTwoPageTemplateFile(PageTemplateFile):
+    """A strange hybrid between Zope 2 and Zope 3 page template.
+
+    Uses Zope 2's engine, but with security disabled and with some
+    initialization and API from Zope 3.
+    """
+        
+    def __init__(self, filename, _prefix=None, content_type=None):
+        # XXX doesn't use content_type yet
+        
+        self.ZBindings_edit(self._default_bindings)
+
+        path = self.get_path_from_prefix(_prefix)
+        self.filename = os.path.join(path, filename)
+        if not os.path.isfile(self.filename):
+            raise ValueError("No such file", self.filename)
+
+        basepath, ext = os.path.splitext(self.filename)
+        self.__name__ = os.path.basename(basepath)
+ 
+    def get_path_from_prefix(self, _prefix):
+        if isinstance(_prefix, str):
+            path = _prefix
+        else:
+            if _prefix is None:
+                _prefix = sys._getframe(2).f_globals
+            path = package_home(_prefix)
+        return path 
+
+    _cook = rebindFunction(PageTemplateFile._cook,
+                           getEngine=getEngine)
+    
+    pt_render = rebindFunction(PageTemplateFile.pt_render,
+                               getEngine=getEngine)
+
+    def _pt_getContext(self):
+        view = self._getContext()
+        try:
+            root = self.getPhysicalRoot()
+            here = view.context
+        except AttributeError:
+            # self has no attribute getPhysicalRoot.
+            # This typically happens when the template has
+            # no proper acquisition context. That means it has no view,
+            # since that's the normal context for a template in Five. /regebro
+            root = self.context.getPhysicalRoot()
+            here = self.context
+            view = None
+
+        request = getattr(root, 'REQUEST', None)
+        c = {'template': self,
+             'here': here,
+             'context': here,
+             'container': self._getContainer(),
+             'nothing': None,
+             'options': {},
+             'root': root,
+             'request': request,
+             'modules': ModuleImporter,
+             }
+        if view:
+            c['view'] = view
+            c['views'] = ViewMapper(here, request)
+
+        return c
+
+    pt_getContext = rebindFunction(_pt_getContext,
+                                   SecureModuleImporter=ModuleImporter)
+
+# this is not in use right now, but would be how to integrate Zope 3 page
+# templates instead of Zope 2 page templates
+class FivePageTemplateFile(ViewPageTemplateFile):
+    
+    def pt_getContext(self, instance, request, **_kw):
+        # instance is a View component
+        namespace = super(FivePageTemplateFile, self).pt_getContext(
+            instance, request, **_kw)
+        namespace['here'] = namespace['context']
+        return namespace


More information about the z3-checkins mailing list