Mercurial > p > roundup > code
annotate roundup/cgi/PageTemplates/TALES.py @ 8562:9c3ec0a5c7fc
chore: remove __future print_funcion from code.
Not needed as of Python 3.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Wed, 08 Apr 2026 21:39:40 -0400 |
| parents | bd4097fa0671 |
| children |
| rev | line source |
|---|---|
| 1049 | 1 ############################################################################## |
| 2 # | |
| 3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
4 # |
| 1049 | 5 # This software is subject to the provisions of the Zope Public License, |
| 6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. | |
| 7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | |
| 8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | |
| 10 # FOR A PARTICULAR PURPOSE | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
11 # |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
12 ############################################################################## |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
13 # Modified for Roundup: |
| 1049 | 14 # |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
15 # 1. changed imports to import from roundup.cgi |
|
2663
5f9e00836006
update comment
Richard Jones <richard@users.sourceforge.net>
parents:
2662
diff
changeset
|
16 # 2. implemented ustr as str (removes import from DocumentTemplate) |
|
5f9e00836006
update comment
Richard Jones <richard@users.sourceforge.net>
parents:
2662
diff
changeset
|
17 # 3. removed import and use of Unauthorized from zExceptions |
| 1049 | 18 """TALES |
| 19 | |
| 20 An implementation of a generic TALES engine | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
21 """ |
|
1071
c08b3820edd1
Adhering to ZPL
Richard Jones <richard@users.sourceforge.net>
parents:
1049
diff
changeset
|
22 |
| 1049 | 23 import re, sys |
| 24 from roundup.cgi import ZTUtils | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
25 from weakref import ref |
|
5388
d26921b851c3
Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents:
5381
diff
changeset
|
26 from .MultiMapping import MultiMapping |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
27 |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
28 ustr = str |
| 1049 | 29 |
| 30 StringType = type('') | |
| 31 | |
| 32 NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*" | |
| 33 _parse_expr = re.compile(r"(%s):" % NAME_RE).match | |
| 34 _valid_name = re.compile('%s$' % NAME_RE).match | |
| 35 | |
|
5265
63868084b8bb
Python 2 and 3 support. Convert Exception to BaseException. TAL and
John Rouillard <rouilj@ieee.org>
parents:
4570
diff
changeset
|
36 class TALESError(BaseException): |
| 1049 | 37 """Error during TALES expression evaluation""" |
| 38 | |
| 39 class Undefined(TALESError): | |
| 40 '''Exception raised on traversal of an undefined path''' | |
| 41 | |
|
5265
63868084b8bb
Python 2 and 3 support. Convert Exception to BaseException. TAL and
John Rouillard <rouilj@ieee.org>
parents:
4570
diff
changeset
|
42 class RegistrationError(BaseException): |
| 1049 | 43 '''TALES Type Registration Error''' |
| 44 | |
|
5265
63868084b8bb
Python 2 and 3 support. Convert Exception to BaseException. TAL and
John Rouillard <rouilj@ieee.org>
parents:
4570
diff
changeset
|
45 class CompilerError(BaseException): |
| 1049 | 46 '''TALES Compiler Error''' |
| 47 | |
| 48 class Default: | |
| 49 '''Retain Default''' | |
| 50 Default = Default() | |
| 51 | |
| 52 class SafeMapping(MultiMapping): | |
| 53 '''Mapping with security declarations and limited method exposure. | |
| 54 | |
| 55 Since it subclasses MultiMapping, this class can be used to wrap | |
| 56 one or more mapping objects. Restricted Python code will not be | |
| 57 able to mutate the SafeMapping or the wrapped mappings, but will be | |
| 58 able to read any value. | |
| 59 ''' | |
| 60 __allow_access_to_unprotected_subobjects__ = 1 | |
| 61 push = pop = None | |
| 62 | |
| 63 _push = MultiMapping.push | |
| 64 _pop = MultiMapping.pop | |
| 65 | |
| 66 | |
| 67 class Iterator(ZTUtils.Iterator): | |
| 68 def __init__(self, name, seq, context): | |
| 69 ZTUtils.Iterator.__init__(self, seq) | |
| 70 self.name = name | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
71 self._context_ref = ref(context) |
| 1049 | 72 |
| 73 def next(self): | |
| 74 if ZTUtils.Iterator.next(self): | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
75 context = self._context_ref() |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
76 if context is not None: |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
77 context.setLocal(self.name, self.item) |
| 1049 | 78 return 1 |
| 79 return 0 | |
| 80 | |
| 81 | |
| 82 class ErrorInfo: | |
| 83 """Information about an exception passed to an on-error handler.""" | |
| 84 __allow_access_to_unprotected_subobjects__ = 1 | |
| 85 | |
| 86 def __init__(self, err, position=(None, None)): | |
|
5265
63868084b8bb
Python 2 and 3 support. Convert Exception to BaseException. TAL and
John Rouillard <rouilj@ieee.org>
parents:
4570
diff
changeset
|
87 if isinstance(err, BaseException): |
| 1049 | 88 self.type = err.__class__ |
| 89 self.value = err | |
| 90 else: | |
| 91 self.type = err | |
| 92 self.value = None | |
| 93 self.lineno = position[0] | |
| 94 self.offset = position[1] | |
| 95 | |
| 96 | |
| 97 class Engine: | |
| 98 '''Expression Engine | |
| 99 | |
| 100 An instance of this class keeps a mutable collection of expression | |
| 101 type handlers. It can compile expression strings by delegating to | |
| 102 these handlers. It can provide an expression Context, which is | |
| 103 capable of holding state and evaluating compiled expressions. | |
| 104 ''' | |
| 105 Iterator = Iterator | |
| 106 | |
| 107 def __init__(self, Iterator=None): | |
| 108 self.types = {} | |
| 109 if Iterator is not None: | |
| 110 self.Iterator = Iterator | |
| 111 | |
| 112 def registerType(self, name, handler): | |
| 113 if not _valid_name(name): | |
|
5378
35ea9b1efc14
Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents:
5377
diff
changeset
|
114 raise RegistrationError('Invalid Expression type "%s".' % name) |
| 1049 | 115 types = self.types |
|
5381
0942fe89e82e
Python 3 preparation: change "x.has_key(y)" to "y in x".
Joseph Myers <jsm@polyomino.org.uk>
parents:
5378
diff
changeset
|
116 if name in types: |
|
5378
35ea9b1efc14
Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents:
5377
diff
changeset
|
117 raise RegistrationError( |
| 1049 | 118 'Multiple registrations for Expression type "%s".' % |
| 119 name) | |
| 120 types[name] = handler | |
| 121 | |
| 122 def getTypes(self): | |
| 123 return self.types | |
| 124 | |
| 125 def compile(self, expression): | |
| 126 m = _parse_expr(expression) | |
| 127 if m: | |
| 128 type = m.group(1) | |
| 129 expr = expression[m.end():] | |
| 130 else: | |
| 131 type = "standard" | |
| 132 expr = expression | |
| 133 try: | |
| 134 handler = self.types[type] | |
| 135 except KeyError: | |
|
5378
35ea9b1efc14
Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents:
5377
diff
changeset
|
136 raise CompilerError( |
| 1049 | 137 'Unrecognized expression type "%s".' % type) |
| 138 return handler(type, expr, self) | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
139 |
| 1049 | 140 def getContext(self, contexts=None, **kwcontexts): |
| 141 if contexts is not None: | |
| 142 if kwcontexts: | |
| 143 kwcontexts.update(contexts) | |
| 144 else: | |
| 145 kwcontexts = contexts | |
| 146 return Context(self, kwcontexts) | |
| 147 | |
| 148 def getCompilerError(self): | |
| 149 return CompilerError | |
| 150 | |
| 151 class Context: | |
| 152 '''Expression Context | |
| 153 | |
| 154 An instance of this class holds context information that it can | |
| 155 use to evaluate compiled expressions. | |
| 156 ''' | |
| 157 | |
| 158 _context_class = SafeMapping | |
| 159 position = (None, None) | |
| 160 source_file = None | |
| 161 | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
162 def __init__(self, compiler, contexts): |
|
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
163 self._compiler = compiler |
| 1049 | 164 self.contexts = contexts |
| 165 contexts['nothing'] = None | |
| 166 contexts['default'] = Default | |
| 167 | |
| 168 self.repeat_vars = rv = {} | |
| 169 # Wrap this, as it is visible to restricted code | |
| 170 contexts['repeat'] = rep = self._context_class(rv) | |
| 171 contexts['loop'] = rep # alias | |
| 172 | |
| 173 self.global_vars = gv = contexts.copy() | |
| 174 self.local_vars = lv = {} | |
| 175 self.vars = self._context_class(gv, lv) | |
| 176 | |
| 177 # Keep track of what needs to be popped as each scope ends. | |
| 178 self._scope_stack = [] | |
| 179 | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
180 def getCompiler(self): |
|
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
181 return self._compiler |
|
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
182 |
| 1049 | 183 def beginScope(self): |
| 184 self._scope_stack.append([self.local_vars.copy()]) | |
| 185 | |
| 186 def endScope(self): | |
| 187 scope = self._scope_stack.pop() | |
| 188 self.local_vars = lv = scope[0] | |
| 189 v = self.vars | |
| 190 v._pop() | |
| 191 v._push(lv) | |
| 192 # Pop repeat variables, if any | |
| 193 i = len(scope) - 1 | |
| 194 while i: | |
| 195 name, value = scope[i] | |
| 196 if value is None: | |
| 197 del self.repeat_vars[name] | |
| 198 else: | |
| 199 self.repeat_vars[name] = value | |
| 200 i = i - 1 | |
| 201 | |
| 202 def setLocal(self, name, value): | |
| 203 self.local_vars[name] = value | |
| 204 | |
| 205 def setGlobal(self, name, value): | |
| 206 self.global_vars[name] = value | |
| 207 | |
| 208 def setRepeat(self, name, expr): | |
| 209 expr = self.evaluate(expr) | |
| 210 if not expr: | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
211 return self._compiler.Iterator(name, (), self) |
|
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
212 it = self._compiler.Iterator(name, expr, self) |
| 1049 | 213 old_value = self.repeat_vars.get(name) |
| 214 self._scope_stack[-1].append((name, old_value)) | |
| 215 self.repeat_vars[name] = it | |
| 216 return it | |
| 217 | |
| 218 def evaluate(self, expression, | |
| 219 isinstance=isinstance, StringType=StringType): | |
| 220 if isinstance(expression, StringType): | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
221 expression = self._compiler.compile(expression) |
| 1049 | 222 __traceback_supplement__ = ( |
| 223 TALESTracebackSupplement, self, expression) | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
224 return expression(self) |
| 1049 | 225 |
| 226 evaluateValue = evaluate | |
|
1219
9620f6782cb7
merge Zope Collector #580 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1071
diff
changeset
|
227 evaluateBoolean = evaluate |
| 1049 | 228 |
|
1409
8dc60d87ab42
Fixed a backlog of bug reports, and worked on python 2.3 compatibility:
Richard Jones <richard@users.sourceforge.net>
parents:
1257
diff
changeset
|
229 def evaluateText(self, expr): |
| 1049 | 230 text = self.evaluate(expr) |
| 231 if text is Default or text is None: | |
| 232 return text | |
|
5416
56c9bcdea47f
Python 3 preparation: unicode.
Joseph Myers <jsm@polyomino.org.uk>
parents:
5388
diff
changeset
|
233 if isinstance(text, type(u'')): |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
234 return text |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
235 else: |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
236 return ustr(text) |
| 1049 | 237 |
| 238 def evaluateStructure(self, expr): | |
| 239 return self.evaluate(expr) | |
| 240 evaluateStructure = evaluate | |
| 241 | |
| 242 def evaluateMacro(self, expr): | |
| 243 # XXX Should return None or a macro definition | |
| 244 return self.evaluate(expr) | |
| 245 evaluateMacro = evaluate | |
| 246 | |
| 247 def createErrorInfo(self, err, position): | |
| 248 return ErrorInfo(err, position) | |
| 249 | |
| 250 def getDefault(self): | |
| 251 return Default | |
| 252 | |
| 253 def setSourceFile(self, source_file): | |
| 254 self.source_file = source_file | |
| 255 | |
| 256 def setPosition(self, position): | |
| 257 self.position = position | |
| 258 | |
| 259 class TALESTracebackSupplement: | |
| 260 """Implementation of ITracebackSupplement""" | |
| 261 def __init__(self, context, expression): | |
| 262 self.context = context | |
| 263 self.source_url = context.source_file | |
| 264 self.line = context.position[0] | |
| 265 self.column = context.position[1] | |
| 266 self.expression = repr(expression) | |
| 267 | |
| 268 def getInfo(self, as_html=0): | |
| 269 import pprint | |
| 270 data = self.context.contexts.copy() | |
| 271 s = pprint.pformat(data) | |
| 272 if not as_html: | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
273 return ' - Names:\n %s' % s.replace('\n', '\n ') |
| 1049 | 274 else: |
|
5837
883c9e90b403
Fix problem with cgi.escape being depricated a different way. This way
John Rouillard <rouilj@ieee.org>
parents:
5416
diff
changeset
|
275 from roundup.anypy.html import html_escape |
|
883c9e90b403
Fix problem with cgi.escape being depricated a different way. This way
John Rouillard <rouilj@ieee.org>
parents:
5416
diff
changeset
|
276 return '<b>Names:</b><pre>%s</pre>' % (html_escape(s)) |
| 1049 | 277 |
| 278 | |
| 279 class SimpleExpr: | |
| 280 '''Simple example of an expression type handler''' | |
| 281 def __init__(self, name, expr, engine): | |
| 282 self._name = name | |
| 283 self._expr = expr | |
| 284 def __call__(self, econtext): | |
| 285 return self._name, self._expr | |
| 286 def __repr__(self): | |
|
5377
12fe83f90f0d
Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents:
5265
diff
changeset
|
287 return '<SimpleExpr %s %s>' % (self._name, repr(self._expr)) |
