[Zope-Checkins] CVS: Releases/Zope/lib/python/Products/PageTemplates - PathPrefixes.py:1.1.2.1 Expressions.py:1.43.46.1
Evan Simpson
evan@4-am.com
Tue, 29 Jul 2003 15:55:50 -0400
Update of /cvs-repository/Releases/Zope/lib/python/Products/PageTemplates
In directory cvs.zope.org:/tmp/cvs-serv16592
Modified Files:
Tag: evan-pathprefix-branch
Expressions.py
Added Files:
Tag: evan-pathprefix-branch
PathPrefixes.py
Log Message:
Initial implementation of TALES Path prefixes.
=== Added File Releases/Zope/lib/python/Products/PageTemplates/PathPrefixes.py ===
from TALES import _valid_name, CompilerError
_subpath_prefixes = {}
def initialize():
global guarded_getattr
from Expressions import guarded_getattr
def registerSubPathPrefix(prefix, compiler=None, handler=None,
do_validate=0):
'''Register a prefix for subpath expressions.
A prefixed subpath is a subpath of the form "{px}:{arg}",
where {px} is the name of a prefix, and {arg} is an arbitrary
(and possibly empty) argument for the prefix.
When a subpath is prefixed, during compilation the compiler
(if any) for the prefix is called with {px} and {arg} as
arguments, and the returned value replaces {arg} in further
processing. If no handler is provided, {arg} replaces the
subpath.
If a handler is provided, it is called during traversal
with {prefix}, {arg}, the current traversal object, the list
of remaining path elements, and the expression context. The value
returned by the handler replaces the current traversal object.
If do_validate is true, the security validator is checked.
'''
if not _valid_name(prefix):
raise ValueError, (
'Invalid subpath prefix "%s"' % prefix)
if compiler is None and handler is None:
raise ValueError, ("registerSubPathPrefix requires either "
"a compiler or a handler, or both.")
_subpath_prefixes[str(prefix)] = (compiler, handler, do_validate)
# 'var:x' is replaced with the value of variable 'x'
def var_compiler(prefix, arg):
arg = arg.strip()
if not _valid_name(arg):
raise CompilerError, ('"%s" is not a valid variable name'
% arg)
return arg
def var_handler(prefix, arg, object, path, econtext):
path.append(econtext.vars[arg])
return object
registerSubPathPrefix('var', var_compiler, var_handler)
# 'call:' calls the current object.
# 'call:x, y, x' passes variables 'x', 'y', and 'z' as arguments.
def call_compiler(prefix, arg):
args = [name.strip() for name in arg.split(',')]
for name in args:
if not _valid_name(name):
raise CompilerError, ('"%s" is not a valid variable name'
% name)
return args
def call_handler(prefix, arg, object, path, econtext):
args = [econtext.vars[name] for name in arg]
return object(*args)
registerSubPathPrefix('call', call_compiler, call_handler)
# 'key:foo' tries to fetch key 'foo' of the current object.
def key_handler(prefix, arg, object, path, econtext):
return object[arg]
registerSubPathPrefix('key', handler=key_handler, do_validate=1)
# 'item:6' tries to fetch integer key '6' of the current object.
def item_compiler(prefix, arg):
return int(arg)
registerSubPathPrefix('item', compiler=item_compiler,
handler=key_handler, do_validate=1)
# 'attr:foo' tries to fetch attribute 'foo' of the current object.
def attr_compiler(prefix, arg):
arg = arg.strip()
if not _valid_name(arg):
raise CompilerError, ('"%s" is not a valid attribute name'
% arg)
return arg
def attr_handler(prefix, arg, object, path, econtext):
return guarded_getattr(object, arg)
registerSubPathPrefix('attr', attr_compiler, attr_handler)
# 'fmt:dollars_and_cents' calls standard PythonScript library
# function 'dollars_and_cents' on the current object.
# 'fmt:%.2f' uses the Python formatting operator to format the
# current object as a floating point number with two decimal places.
try:
from Products.PythonScripts import standard
_fmt_names = ('whole_dollars', 'dollars_and_cents',
'structured_text', 'restructured_text',
'sql_quote', 'html_quote', 'url_quote',
'url_quote_plus', 'newline_to_br',
'thousands_commas', 'url_unquote',
'url_unquote_plus', 'urlencode')
except:
_fmt_names = ()
def fmt_handler(prefix, arg, object, path, econtext):
if arg in _fmt_names:
return getattr(standard, arg)(object)
return arg % object
registerSubPathPrefix('fmt', handler=fmt_handler)
=== Releases/Zope/lib/python/Products/PageTemplates/Expressions.py 1.43 => 1.43.46.1 ===
--- Releases/Zope/lib/python/Products/PageTemplates/Expressions.py:1.43 Thu Sep 26 17:33:17 2002
+++ Releases/Zope/lib/python/Products/PageTemplates/Expressions.py Tue Jul 29 15:55:43 2003
@@ -23,7 +23,7 @@
from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
Undefined, Default, _parse_expr
from Acquisition import aq_base, aq_inner, aq_parent
-
+import PathPrefixes
_engine = None
def getEngine():
@@ -32,6 +32,7 @@
from PathIterator import Iterator
_engine = Engine(Iterator)
installHandlers(_engine)
+ PathPrefixes.initialize()
return _engine
def installHandlers(engine):
@@ -111,6 +112,19 @@
raise
return ob
+class SubPathHandler:
+ def __init__(self, prefix, arg, handler, do_validate):
+ self.prefix = prefix
+ self.arg = arg
+ self.handler = handler
+ self.do_validate = do_validate
+ def __call__(self, object, path, econtext, validate):
+ arg = self.arg
+ o = self.handler(self.prefix, arg, object, path, econtext)
+ if self.do_validate and not validate(object, object, arg, o):
+ raise Unauthorized, arg
+ return o
+
class SubPathExpr:
def __init__(self, path):
self._path = path = path.strip().split('/')
@@ -119,10 +133,23 @@
raise CompilerError, 'Invalid variable name "%s"' % base
# Parse path
self._dp = dp = []
+ prefixes = PathPrefixes._subpath_prefixes
for i in range(len(path)):
e = path[i]
if e[:1] == '?' and _valid_name(e[1:]):
dp.append((i, e[1:]))
+ elif ':' in e:
+ prefix, arg = e.split(':', 1)
+ if not prefixes.has_key(prefix):
+ raise CompilerError, (
+ 'Unknown prefix "%s"' % prefix)
+ compiler, handler, do_v = prefixes.get(prefix)
+ if compiler is not None:
+ arg = compiler(prefix, arg)
+ if handler is None:
+ path[i] = arg
+ else:
+ path[i] = SubPathHandler(prefix, arg, handler, do_v)
dp.reverse()
def _eval(self, econtext,
@@ -147,7 +174,7 @@
if isinstance(ob, DeferWrapper):
ob = ob()
if path:
- ob = restrictedTraverse(ob, path, getSecurityManager())
+ ob = restrictedTraverse(ob, path, getSecurityManager(), econtext)
return ob
class PathExpr:
@@ -292,7 +319,7 @@
return 'defer:%s' % `self._s`
-def restrictedTraverse(object, path, securityManager,
+def restrictedTraverse(object, path, securityManager, econtext,
get=getattr, has=hasattr, N=None, M=[],
TupleType=type(()) ):
@@ -307,6 +334,12 @@
if isinstance(name, TupleType):
object = object(*name)
continue
+
+ if isinstance(name, SubPathHandler):
+ object = name(object, path, econtext, validate)
+ continue
+
+ name = str(name)
if not name or name[0] == '_':
# Skip directly to item access