1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
1 ##############################################################################
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
2 #
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
4 #
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
5 # This software is subject to the provisions of the Zope Public License,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
10 # FOR A PARTICULAR PURPOSE
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
11 #
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
12 ##############################################################################
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
13
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
14 """Page Template Expression Engine
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
15
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
16 Page Template-specific implementation of TALES, with handlers
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
17 for Python expressions, string literals, and paths.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
18 """
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
19
|
1065
0f9aa62917bd
much nicer error messages when there's a templating error
Richard Jones <richard@users.sourceforge.net>
diff
changeset
|
20 __version__='$Revision: 1.2 $'[11:-2]
|
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
21
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
22 import re, sys
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
23 from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
24 Undefined, Default, _parse_expr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
25 from string import strip, split, join, replace, lstrip
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
26
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
27 _engine = None
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
28 def getEngine():
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
29 global _engine
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
30 if _engine is None:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
31 from PathIterator import Iterator
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
32 _engine = Engine(Iterator)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
33 installHandlers(_engine)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
34 return _engine
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
35
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
36 def installHandlers(engine):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
37 reg = engine.registerType
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
38 pe = PathExpr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
39 for pt in ('standard', 'path', 'exists', 'nocall'):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
40 reg(pt, pe)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
41 reg('string', StringExpr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
42 reg('python', PythonExpr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
43 reg('not', NotExpr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
44 reg('defer', DeferExpr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
45
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
46 from PythonExpr import getSecurityManager, PythonExpr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
47 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
48 from zExceptions import Unauthorized
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
49 except ImportError:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
50 Unauthorized = "Unauthorized"
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
51 def call_with_ns(f, ns, arg=1):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
52 if arg==2:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
53 return f(None, ns)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
54 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
55 return f(ns)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
56
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
57 class _SecureModuleImporter:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
58 """Simple version of the importer for use with trusted code."""
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
59 __allow_access_to_unprotected_subobjects__ = 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
60 def __getitem__(self, module):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
61 __import__(module)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
62 return sys.modules[module]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
63
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
64 Undefs = (Undefined, AttributeError, KeyError,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
65 TypeError, IndexError, Unauthorized)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
66
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
67 def render(ob, ns):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
68 """
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
69 Calls the object, possibly a document template, or just returns it if
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
70 not callable. (From DT_Util.py)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
71 """
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
72 if hasattr(ob, '__render_with_namespace__'):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
73 ob = call_with_ns(ob.__render_with_namespace__, ns)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
74 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
75 base = ob
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
76 if callable(base):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
77 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
78 if getattr(base, 'isDocTemp', 0):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
79 ob = call_with_ns(ob, ns, 2)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
80 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
81 ob = ob()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
82 except AttributeError, n:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
83 if str(n) != '__call__':
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
84 raise
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
85 return ob
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
86
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
87 class SubPathExpr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
88 def __init__(self, path):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
89 self._path = path = split(strip(path), '/')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
90 self._base = base = path.pop(0)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
91 if not _valid_name(base):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
92 raise CompilerError, 'Invalid variable name "%s"' % base
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
93 # Parse path
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
94 self._dp = dp = []
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
95 for i in range(len(path)):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
96 e = path[i]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
97 if e[:1] == '?' and _valid_name(e[1:]):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
98 dp.append((i, e[1:]))
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
99 dp.reverse()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
100
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
101 def _eval(self, econtext,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
102 list=list, isinstance=isinstance, StringType=type('')):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
103 vars = econtext.vars
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
104 path = self._path
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
105 if self._dp:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
106 path = list(path) # Copy!
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
107 for i, varname in self._dp:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
108 val = vars[varname]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
109 if isinstance(val, StringType):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
110 path[i] = val
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
111 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
112 # If the value isn't a string, assume it's a sequence
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
113 # of path names.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
114 path[i:i+1] = list(val)
|
1065
0f9aa62917bd
much nicer error messages when there's a templating error
Richard Jones <richard@users.sourceforge.net>
diff
changeset
|
115 base = self._base
|
0f9aa62917bd
much nicer error messages when there's a templating error
Richard Jones <richard@users.sourceforge.net>
diff
changeset
|
116 __traceback_info__ = 'sub path expression "%s"'%base
|
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
117 if base == 'CONTEXTS':
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
118 ob = econtext.contexts
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
119 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
120 ob = vars[base]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
121 if isinstance(ob, DeferWrapper):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
122 ob = ob()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
123 if path:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
124 ob = restrictedTraverse(ob, path, getSecurityManager())
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
125 return ob
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
126
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
127 class PathExpr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
128 def __init__(self, name, expr, engine):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
129 self._s = expr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
130 self._name = name
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
131 paths = split(expr, '|')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
132 self._subexprs = []
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
133 add = self._subexprs.append
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
134 for i in range(len(paths)):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
135 path = lstrip(paths[i])
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
136 if _parse_expr(path):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
137 # This part is the start of another expression type,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
138 # so glue it back together and compile it.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
139 add(engine.compile(lstrip(join(paths[i:], '|'))))
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
140 break
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
141 add(SubPathExpr(path)._eval)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
142
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
143 def _exists(self, econtext):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
144 for expr in self._subexprs:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
145 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
146 expr(econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
147 except Undefs:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
148 pass
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
149 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
150 return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
151 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
152
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
153 def _eval(self, econtext,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
154 isinstance=isinstance, StringType=type(''), render=render):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
155 for expr in self._subexprs[:-1]:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
156 # Try all but the last subexpression, skipping undefined ones.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
157 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
158 ob = expr(econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
159 except Undefs:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
160 pass
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
161 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
162 break
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
163 else:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
164 # On the last subexpression allow exceptions through.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
165 ob = self._subexprs[-1](econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
166
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
167 if self._name == 'nocall' or isinstance(ob, StringType):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
168 return ob
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
169 # Return the rendered object
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
170 return render(ob, econtext.vars)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
171
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
172 def __call__(self, econtext):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
173 if self._name == 'exists':
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
174 return self._exists(econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
175 return self._eval(econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
176
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
177 def __str__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
178 return '%s expression %s' % (self._name, `self._s`)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
179
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
180 def __repr__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
181 return '%s:%s' % (self._name, `self._s`)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
182
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
183
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
184 _interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/%(n)s)*)}' % {'n': NAME_RE})
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
185
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
186 class StringExpr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
187 def __init__(self, name, expr, engine):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
188 self._s = expr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
189 if '%' in expr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
190 expr = replace(expr, '%', '%%')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
191 self._vars = vars = []
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
192 if '$' in expr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
193 parts = []
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
194 for exp in split(expr, '$$'):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
195 if parts: parts.append('$')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
196 m = _interp.search(exp)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
197 while m is not None:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
198 parts.append(exp[:m.start()])
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
199 parts.append('%s')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
200 vars.append(PathExpr('path', m.group(1) or m.group(2),
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
201 engine))
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
202 exp = exp[m.end():]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
203 m = _interp.search(exp)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
204 if '$' in exp:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
205 raise CompilerError, (
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
206 '$ must be doubled or followed by a simple path')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
207 parts.append(exp)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
208 expr = join(parts, '')
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
209 self._expr = expr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
210
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
211 def __call__(self, econtext):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
212 vvals = []
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
213 for var in self._vars:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
214 v = var(econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
215 if isinstance(v, Exception):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
216 raise v
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
217 vvals.append(v)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
218 return self._expr % tuple(vvals)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
219
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
220 def __str__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
221 return 'string expression %s' % `self._s`
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
222
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
223 def __repr__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
224 return 'string:%s' % `self._s`
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
225
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
226 class NotExpr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
227 def __init__(self, name, expr, compiler):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
228 self._s = expr = lstrip(expr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
229 self._c = compiler.compile(expr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
230
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
231 def __call__(self, econtext):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
232 return not econtext.evaluateBoolean(self._c)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
233
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
234 def __repr__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
235 return 'not:%s' % `self._s`
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
236
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
237 class DeferWrapper:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
238 def __init__(self, expr, econtext):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
239 self._expr = expr
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
240 self._econtext = econtext
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
241
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
242 def __str__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
243 return str(self())
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
244
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
245 def __call__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
246 return self._expr(self._econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
247
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
248 class DeferExpr:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
249 def __init__(self, name, expr, compiler):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
250 self._s = expr = lstrip(expr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
251 self._c = compiler.compile(expr)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
252
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
253 def __call__(self, econtext):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
254 return DeferWrapper(self._c, econtext)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
255
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
256 def __repr__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
257 return 'defer:%s' % `self._s`
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
258
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
259
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
260 def restrictedTraverse(self, path, securityManager,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
261 get=getattr, has=hasattr, N=None, M=[],
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
262 TupleType=type(()) ):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
263
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
264 REQUEST = {'path': path}
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
265 REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
266 if not path[0]:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
267 # If the path starts with an empty string, go to the root first.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
268 self = self.getPhysicalRoot()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
269 path.pop(0)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
270
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
271 path.reverse()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
272 object = self
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
273 #print 'TRAVERSE', (object, path)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
274 while path:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
275 name = path.pop()
|
1065
0f9aa62917bd
much nicer error messages when there's a templating error
Richard Jones <richard@users.sourceforge.net>
diff
changeset
|
276 __traceback_info__ = 'looking for "%s"'%name
|
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
277
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
278 if isinstance(name, TupleType):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
279 object = apply(object, name)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
280 continue
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
281
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
282 if name[0] == '_':
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
283 # Never allowed in a URL.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
284 raise AttributeError, name
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
285
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
286 # Try an attribute.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
287 o = get(object, name, M)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
288 # print '...', (object, name, M, o)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
289 if o is M:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
290 # Try an item.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
291 # print '... try an item'
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
292 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
293 # XXX maybe in Python 2.2 we can just check whether
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
294 # the object has the attribute "__getitem__"
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
295 # instead of blindly catching exceptions.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
296 o = object[name]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
297 except AttributeError, exc:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
298 if str(exc).find('__getitem__') >= 0:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
299 # The object does not support the item interface.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
300 # Try to re-raise the original attribute error.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
301 # XXX I think this only happens with
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
302 # ExtensionClass instances.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
303 get(object, name)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
304 raise
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
305 except TypeError, exc:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
306 if str(exc).find('unsubscriptable') >= 0:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
307 # The object does not support the item interface.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
308 # Try to re-raise the original attribute error.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
309 # XXX This is sooooo ugly.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
310 get(object, name)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
311 raise
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
312 #print '... object is now', `o`
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
313 object = o
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
314
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
315 return object
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
316
|