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....
parent 8b0d7d2b
...@@ -18,52 +18,49 @@ from zope.tales.expressions import SimpleModuleImporter ...@@ -18,52 +18,49 @@ from zope.tales.expressions import SimpleModuleImporter
from zope.tales.pythonexpr import PythonExpr from zope.tales.pythonexpr import PythonExpr
from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined, Context from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined, Context
from zope.i18n import translate 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 from Products.PageTemplates.GlobalTranslationService import getGlobalTranslationService
_marker = object() _marker = object()
def BoboTraverseAwareSimpleTraverse(object, path_items, econtext): def boboTraverseAwareSimpleTraverse(object, path_items, econtext):
""" a slightly modified version of zope.tales.expressions.simpleTraverse() """ a slightly modified version of zope.tales.expressions.simpleTraverse()
that interacts correctly with objects implementing bobo_traverse(). 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: while path_items:
next = getattr(object, name, _marker) name = path_items.pop()
if next is not _marker: if ITraversable.providedBy(object):
object = next
else:
try: try:
object = object.restrictedTraverse(name) object = object.restrictedTraverse(name)
except (KeyError, AttributeError): except NotFound, e:
try: # OFS.Traversable.restrictedTraverse spits out
object = object[name] # NotFound (the Zope 2 version) which Zope 3's ZPT
except: # implementation obviously doesn't know as an
object = getattr(object, name) # 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 return object
class PathExpr(PathExpr): class ZopePathExpr(PathExpr):
"""We need to subclass PathExpr at this point since there is no other """Zope2-aware path expression implementation"""
away to pass our own traverser because we do not instantiate
PathExpr on our own...this sucks!
"""
def __init__(self, name, expr, engine, traverser=BoboTraverseAwareSimpleTraverse): def __init__(self, name, expr, engine):
self._s = expr super(ZopePathExpr, self).__init__(name, expr, engine,
self._name = name boboTraverseAwareSimpleTraverse)
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)
class Context(Context): class Context(Context):
...@@ -91,13 +88,12 @@ class ExpressionEngine(ExpressionEngine): ...@@ -91,13 +88,12 @@ class ExpressionEngine(ExpressionEngine):
def Engine(): def Engine():
e = ExpressionEngine() e = ExpressionEngine()
reg = e.registerType for pt in ZopePathExpr._default_type_names:
for pt in PathExpr._default_type_names: e.registerType(pt, ZopePathExpr)
reg(pt, PathExpr) e.registerType('string', StringExpr)
reg('string', StringExpr) e.registerType('python', PythonExpr)
reg('python', PythonExpr) e.registerType('not', NotExpr)
reg('not', NotExpr) e.registerType('defer', DeferExpr)
reg('defer', DeferExpr)
e.registerBaseName('modules', SimpleModuleImporter()) e.registerBaseName('modules', SimpleModuleImporter())
return e return e
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment