[Zope-Checkins] SVN: Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Engine.py Greatly sanify the way we marry Zope 3 ZPTs and Zope 2 traversal.

Philipp von Weitershausen philikon at philikon.de
Mon May 8 15:18:43 EDT 2006


Log message for revision 68038:
  Greatly sanify the way we marry Zope 3 ZPTs and Zope 2 traversal.
  
  Basically, zope.app's path expressions use ITraversable adapters to
  traverse through the object graph. This is the only sane thing to do,
  really. However, we still want to take care of Zope2's OFS.Traversable
  which most promimently allowes the __bobo_traverse__ hook.  (The irony
  is that OFS.Traversable uses Zope 3-style *URL* traversal these days;
  yes, *URL* traversal, not *object graph* traversal).
  
  Still confused?
  
  Basically, if we encounter something that is OFS.Traversable'ish, use
  restrictedTraverse. Use Zope3-style object graph traversal in all other
  cases....
  

Changed:
  U   Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Engine.py

-=-
Modified: Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Engine.py
===================================================================
--- Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Engine.py	2006-05-08 19:02:45 UTC (rev 68037)
+++ Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Engine.py	2006-05-08 19:18:42 UTC (rev 68038)
@@ -18,52 +18,49 @@
 from zope.tales.pythonexpr import PythonExpr
 from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined, Context 
 from zope.i18n import translate
+from zope.traversing.adapters import traversePathElement
 
+from zExceptions import NotFound
+from OFS.interfaces import ITraversable
 from Products.PageTemplates.GlobalTranslationService import getGlobalTranslationService
 
 _marker = object()
 
-def BoboTraverseAwareSimpleTraverse(object, path_items, econtext):
+def boboTraverseAwareSimpleTraverse(object, path_items, econtext):
     """ a slightly modified version of zope.tales.expressions.simpleTraverse()
         that interacts correctly with objects implementing bobo_traverse().
     """
+    request = getattr(econtext, 'request', None)
+    path_items = list(path_items)
+    path_items.reverse()
 
-    for name in path_items:
-        next = getattr(object, name, _marker)
-        if next is not _marker:
-            object = next
-        else:
+    while path_items:
+        name = path_items.pop()
+        if ITraversable.providedBy(object):
             try:
                 object = object.restrictedTraverse(name)
-            except (KeyError, AttributeError):
-                try:
-                    object = object[name]
-                except:
-                    object = getattr(object, name)
-
+            except NotFound, e:
+                # OFS.Traversable.restrictedTraverse spits out
+                # NotFound (the Zope 2 version) which Zope 3's ZPT
+                # implementation obviously doesn't know as an
+                # exception indicating failed traversal.  Perhaps Zope
+                # 2's NotFound should be made to extend LookupError at
+                # some point (or it should just be replaced with Zope
+                # 3's version).  For the time being, however, we
+                # simply converting NotFounds into LookupErrors:
+                raise LookupError(*e.args)
+        else:
+            object = traversePathElement(object, name, path_items,
+                                         request=request)
     return object
 
 
-class PathExpr(PathExpr):
-    """We need to subclass PathExpr at this point since there is no other
-       away to pass our own traverser because we do not instantiate 
-       PathExpr on our own...this sucks!
-    """
+class ZopePathExpr(PathExpr):
+    """Zope2-aware path expression implementation"""
 
-    def __init__(self, name, expr, engine, traverser=BoboTraverseAwareSimpleTraverse):
-        self._s = expr
-        self._name = name
-        paths = expr.split('|')
-        self._subexprs = []
-        add = self._subexprs.append
-        for i in range(len(paths)):
-            path = paths[i].lstrip()
-            if _parse_expr(path):
-                # This part is the start of another expression type,
-                # so glue it back together and compile it.
-                add(engine.compile('|'.join(paths[i:]).lstrip()))
-                break
-            add(SubPathExpr(path, traverser, engine)._eval)
+    def __init__(self, name, expr, engine):
+        super(ZopePathExpr, self).__init__(name, expr, engine,
+                                           boboTraverseAwareSimpleTraverse)
 
 class Context(Context):
 
@@ -91,13 +88,12 @@
 
 def Engine():
     e = ExpressionEngine()
-    reg = e.registerType
-    for pt in PathExpr._default_type_names:
-        reg(pt, PathExpr)
-    reg('string', StringExpr)
-    reg('python', PythonExpr)
-    reg('not', NotExpr)
-    reg('defer', DeferExpr)
+    for pt in ZopePathExpr._default_type_names:
+        e.registerType(pt, ZopePathExpr)
+    e.registerType('string', StringExpr)
+    e.registerType('python', PythonExpr)
+    e.registerType('not', NotExpr)
+    e.registerType('defer', DeferExpr)
     e.registerBaseName('modules', SimpleModuleImporter())
     return e
 



More information about the Zope-Checkins mailing list