Move Engine.py (which was added on this branch) to Expressions.py which contain(ed)

the old-style expressions. We now use the ones from Zope 3. If we can. Not sure yet :)
parent 20f56e7a
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
from zope.tales.tales import ExpressionEngine
from zope.tales.expressions import PathExpr, StringExpr, NotExpr
from zope.tales.expressions import DeferExpr, SubPathExpr
from zope.tales.expressions import SimpleModuleImporter
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):
""" 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()
while path_items:
name = path_items.pop()
if ITraversable.providedBy(object):
try:
object = object.restrictedTraverse(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 ZopePathExpr(PathExpr):
"""Zope2-aware path expression implementation"""
def __init__(self, name, expr, engine):
super(ZopePathExpr, self).__init__(name, expr, engine,
boboTraverseAwareSimpleTraverse)
class Context(Context):
def translate(self, msgid, domain, mapping=None,
context=None, target_language=None, default=None):
if context is None:
context = self.contexts.get('context')
return getGlobalTranslationService().translate(
domain, msgid, mapping=mapping,
context=context,
default=default,
target_language=target_language)
class ExpressionEngine(ExpressionEngine):
def getContext(self, contexts=None, **kwcontexts):
if contexts is not None:
if kwcontexts:
kwcontexts.update(contexts)
else:
kwcontexts = contexts
return Context(self, kwcontexts)
def Engine():
e = ExpressionEngine()
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
Engine = Engine()
...@@ -17,12 +17,20 @@ for Python expressions, string literals, and paths. ...@@ -17,12 +17,20 @@ for Python expressions, string literals, and paths.
$Id$ $Id$
""" """
import re, sys from zope.tales.tales import ExpressionEngine, Context
from TALES import Engine, CompilerError, NAME_RE, Undefined, Default from zope.tales.expressions import PathExpr, StringExpr, NotExpr
from TALES import _parse_expr, _valid_name from zope.tales.expressions import DeferExpr, SubPathExpr
from Acquisition import aq_base, aq_inner, aq_parent from zope.tales.expressions import SimpleModuleImporter
from DeferExpr import LazyWrapper, LazyExpr from zope.tales.pythonexpr import PythonExpr
from zope.tales.expressions import DeferWrapper, DeferExpr, StringExpr, NotExpr from zope.i18n import translate
from zope.traversing.adapters import traversePathElement
from zExceptions import NotFound, Unauthorized
from OFS.interfaces import ITraversable
from Products.PageTemplates.DeferExpr import LazyExpr
from Products.PageTemplates.GlobalTranslationService import getGlobalTranslationService
from Products.PageTemplates.ZRPythonExpr import _SecureModuleImporter
SecureModuleImporter = _SecureModuleImporter()
# BBB 2005/05/01 -- remove after 12 months # BBB 2005/05/01 -- remove after 12 months
import zope.deferredimport import zope.deferredimport
...@@ -34,275 +42,77 @@ zope.deferredimport.deprecatedFrom( ...@@ -34,275 +42,77 @@ zope.deferredimport.deprecatedFrom(
"StringExpr", "NotExpr" "StringExpr", "NotExpr"
) )
_engine = None def boboTraverseAwareSimpleTraverse(object, path_items, econtext):
def getEngine(): """ a slightly modified version of zope.tales.expressions.simpleTraverse()
global _engine that interacts correctly with objects implementing bobo_traverse().
if _engine is None:
from PathIterator import Iterator
_engine = Engine(Iterator)
installHandlers(_engine)
return _engine
def installHandlers(engine):
reg = engine.registerType
pe = PathExpr
for pt in ('standard', 'path', 'exists', 'nocall'):
reg(pt, pe)
reg('string', StringExpr)
reg('python', PythonExpr)
reg('not', NotExpr)
reg('defer', DeferExpr)
reg('lazy', LazyExpr)
import AccessControl
import AccessControl.cAccessControl
acquisition_security_filter = AccessControl.cAccessControl.aq_validate
from AccessControl import getSecurityManager
from AccessControl.ZopeGuards import guarded_getattr
from AccessControl import Unauthorized
from ZRPythonExpr import PythonExpr
from ZRPythonExpr import _SecureModuleImporter
from ZRPythonExpr import call_with_ns
SecureModuleImporter = _SecureModuleImporter()
Undefs = (Undefined, AttributeError, KeyError,
TypeError, IndexError, Unauthorized)
def render(ob, ns):
"""
Calls the object, possibly a document template, or just returns it if
not callable. (From DT_Util.py)
""" """
if hasattr(ob, '__render_with_namespace__'): request = getattr(econtext, 'request', None)
ob = call_with_ns(ob.__render_with_namespace__, ns) path_items = list(path_items)
else: path_items.reverse()
base = aq_base(ob)
if callable(base):
try:
if getattr(base, 'isDocTemp', 0):
ob = call_with_ns(ob, ns, 2)
else:
ob = ob()
except AttributeError, n:
if str(n) != '__call__':
raise
return ob
class SubPathExpr:
def __init__(self, path):
self._path = path = path.strip().split('/')
self._base = base = path.pop(0)
if base and not _valid_name(base):
raise CompilerError, 'Invalid variable name "%s"' % base
# Parse path
self._dp = dp = []
for i in range(len(path)):
e = path[i]
if e[:1] == '?' and _valid_name(e[1:]):
dp.append((i, e[1:]))
dp.reverse()
def _eval(self, econtext,
list=list, isinstance=isinstance, StringType=type('')):
vars = econtext.vars
path = self._path
if self._dp:
path = list(path) # Copy!
for i, varname in self._dp:
val = vars[varname]
if isinstance(val, StringType):
path[i] = val
else:
# If the value isn't a string, assume it's a sequence
# of path names.
path[i:i+1] = list(val)
__traceback_info__ = base = self._base
if base == 'CONTEXTS' or not base:
ob = econtext.contexts
else:
ob = vars[base]
if isinstance(ob, DeferWrapper):
ob = ob()
if path:
ob = restrictedTraverse(ob, path, getSecurityManager())
return ob
class PathExpr:
def __init__(self, name, expr, engine):
self._s = expr
self._name = name
self._hybrid = 0
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())))
self._hybrid = 1
break
add(SubPathExpr(path)._eval)
def _exists(self, econtext):
for expr in self._subexprs:
try:
expr(econtext)
except Undefs:
pass
else:
return 1
return 0
def _eval(self, econtext, while path_items:
isinstance=isinstance, name = path_items.pop()
BasicTypes=(str, unicode, dict, list, tuple, bool), if ITraversable.providedBy(object):
render=render):
for expr in self._subexprs[:-1]:
# Try all but the last subexpression, skipping undefined ones.
try: try:
ob = expr(econtext) object = object.restrictedTraverse(name)
except Undefs: except (NotFound, Unauthorized), e:
pass # OFS.Traversable.restrictedTraverse spits out
# NotFound or Unauthorized (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: else:
break object = traversePathElement(object, name, path_items,
else: request=request)
# On the last subexpression allow exceptions through, and return object
# don't autocall if the expression was not a subpath.
ob = self._subexprs[-1](econtext)
if self._hybrid:
return ob
if self._name == 'nocall' or isinstance(ob, BasicTypes):
return ob
# Return the rendered object
return render(ob, econtext.vars)
def __call__(self, econtext):
if self._name == 'exists':
return self._exists(econtext)
return self._eval(econtext)
def __str__(self):
return '%s expression %s' % (self._name, `self._s`)
def __repr__(self):
return '%s:%s' % (self._name, `self._s`)
from zope.interface import Interface, implements
from zope.component import queryMultiAdapter
from zope.traversing.interfaces import TraversalError
from zope.traversing.namespace import nsParse, namespaceLookup
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.publisher.browser import setDefaultSkin
class FakeRequest(dict):
implements(IBrowserRequest)
def getURL(self):
return "http://codespeak.net/z3/five"
def restrictedTraverse(object, path, securityManager,
get=getattr, has=hasattr, N=None, M=[],
TupleType=type(()) ):
REQUEST = FakeRequest()
REQUEST['path'] = path
REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
setDefaultSkin(REQUEST)
path.reverse()
validate = securityManager.validate
__traceback_info__ = REQUEST
while path:
name = path.pop()
if isinstance(name, TupleType):
object = object(*name)
continue
if not name or name[0] == '_':
# Skip directly to item access
o = object[name]
# Check access to the item.
if not validate(object, object, None, o):
raise Unauthorized, name
object = o
continue
if name=='..': class ZopePathExpr(PathExpr):
o = get(object, 'aq_parent', M) """Zope2-aware path expression implementation"""
if o is not M:
if not validate(object, object, name, o):
raise Unauthorized, name
object=o
continue
t=get(object, '__bobo_traverse__', N) def __init__(self, name, expr, engine):
if name and name[:1] in '@+': super(ZopePathExpr, self).__init__(name, expr, engine,
# Process URI segment parameters. boboTraverseAwareSimpleTraverse)
ns, nm = nsParse(name)
if ns: class ZopeContext(Context):
try:
o = namespaceLookup(ns, nm, object, def translate(self, msgid, domain, mapping=None,
REQUEST).__of__(object) context=None, target_language=None, default=None):
if not validate(object, object, name, o): if context is None:
raise Unauthorized, name context = self.contexts.get('context')
except TraversalError: return getGlobalTranslationService().translate(
raise AttributeError(name) domain, msgid, mapping=mapping,
elif t is not N: context=context,
o=t(REQUEST, name) default=default,
target_language=target_language)
container = None
if aq_base(o) is not o: class ZopeEngine(ExpressionEngine):
# The object is wrapped, so the acquisition
# context determines the container. def getContext(self, contexts=None, **kwcontexts):
container = aq_parent(aq_inner(o)) if contexts is not None:
elif has(o, 'im_self'): if kwcontexts:
container = o.im_self kwcontexts.update(contexts)
elif (has(aq_base(object), name) and get(object, name) == o):
container = object
if not validate(object, container, name, o):
raise Unauthorized, name
else:
# Try an attribute.
o = guarded_getattr(object, str(name), M) # failed on u'aq_parent'
if o is M:
# Try an item.
try:
# XXX maybe in Python 2.2 we can just check whether
# the object has the attribute "__getitem__"
# instead of blindly catching exceptions.
try:
o = object[name]
except (AttributeError, KeyError):
# Try to look for a view
o = queryMultiAdapter((object, REQUEST),
Interface, name)
if o is None:
# Didn't find one, reraise the error:
raise
o = o.__of__(object)
except AttributeError, exc:
if str(exc).find('__getitem__') >= 0:
# The object does not support the item interface.
# Try to re-raise the original attribute error.
# XXX I think this only happens with
# ExtensionClass instances.
guarded_getattr(object, name)
raise
except TypeError, exc:
if str(exc).find('unsubscriptable') >= 0:
# The object does not support the item interface.
# Try to re-raise the original attribute error.
# XXX This is sooooo ugly.
guarded_getattr(object, name)
raise
else: else:
# Check access to the item. kwcontexts = contexts
if not validate(object, object, None, o): return ZopeContext(self, kwcontexts)
raise Unauthorized, name
object = o def Engine():
e = ZopeEngine()
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.registerType('lazy', LazyExpr)
e.registerBaseName('modules', SecureModuleImporter)
return e
Engine = Engine()
return object def getEngine():
return Engine
...@@ -23,7 +23,7 @@ from OFS.SimpleItem import SimpleItem ...@@ -23,7 +23,7 @@ from OFS.SimpleItem import SimpleItem
from OFS.Traversable import Traversable from OFS.Traversable import Traversable
from Shared.DC.Scripts.Script import Script from Shared.DC.Scripts.Script import Script
from Shared.DC.Scripts.Signature import FuncCode from Shared.DC.Scripts.Signature import FuncCode
from Products.PageTemplates.Engine import Engine from Products.PageTemplates.Expressions import getEngine
from Products.PageTemplates.Expressions import SecureModuleImporter from Products.PageTemplates.Expressions import SecureModuleImporter
from Products.PageTemplates.ZopePageTemplate import guess_type from Products.PageTemplates.ZopePageTemplate import guess_type
...@@ -82,7 +82,7 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable): ...@@ -82,7 +82,7 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
def pt_getEngine(self): def pt_getEngine(self):
return Engine return getEngine()
def pt_getContext(self): def pt_getContext(self):
root = self.getPhysicalRoot() root = self.getPhysicalRoot()
......
...@@ -38,7 +38,7 @@ from zope.contenttype import guess_content_type ...@@ -38,7 +38,7 @@ from zope.contenttype import guess_content_type
from zope.pagetemplate.pagetemplate import PageTemplate from zope.pagetemplate.pagetemplate import PageTemplate
from zope.pagetemplate.pagetemplatefile import sniff_type from zope.pagetemplate.pagetemplatefile import sniff_type
from Products.PageTemplates.Engine import Engine from Products.PageTemplates.Expressions import getEngine
# regular expression to extract the encoding from the XML preamble # regular expression to extract the encoding from the XML preamble
...@@ -187,7 +187,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -187,7 +187,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
def pt_getEngine(self): def pt_getEngine(self):
return Engine return getEngine()
security.declareProtected(change_page_templates, 'pt_upload') security.declareProtected(change_page_templates, 'pt_upload')
......
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