Mercurial > p > roundup > code
annotate roundup/cgi/PageTemplates/TALES.py @ 2662:29779f041ee7
typo
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Thu, 19 Aug 2004 22:44:48 +0000 |
| parents | b43efe461b3e |
| children | 5f9e00836006 |
| 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 |
| 2662 | 16 # 2. implemented ustr as str |
| 1049 | 17 """TALES |
| 18 | |
| 19 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
|
20 """ |
|
1071
c08b3820edd1
Adhering to ZPL
Richard Jones <richard@users.sourceforge.net>
parents:
1049
diff
changeset
|
21 |
| 2662 | 22 __version__='$Revision: 1.8 $'[11:-2] |
| 1049 | 23 |
| 24 import re, sys | |
| 25 from roundup.cgi import ZTUtils | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
26 from weakref import ref |
| 1049 | 27 from MultiMapping import MultiMapping |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
28 from GlobalTranslationService import getGlobalTranslationService |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
29 |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
30 ustr = str |
| 1049 | 31 |
| 32 StringType = type('') | |
| 33 | |
| 34 NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*" | |
| 35 _parse_expr = re.compile(r"(%s):" % NAME_RE).match | |
| 36 _valid_name = re.compile('%s$' % NAME_RE).match | |
| 37 | |
| 38 class TALESError(Exception): | |
| 39 """Error during TALES expression evaluation""" | |
| 40 | |
| 41 class Undefined(TALESError): | |
| 42 '''Exception raised on traversal of an undefined path''' | |
| 43 | |
| 44 class RegistrationError(Exception): | |
| 45 '''TALES Type Registration Error''' | |
| 46 | |
| 47 class CompilerError(Exception): | |
| 48 '''TALES Compiler Error''' | |
| 49 | |
| 50 class Default: | |
| 51 '''Retain Default''' | |
| 52 Default = Default() | |
| 53 | |
| 54 class SafeMapping(MultiMapping): | |
| 55 '''Mapping with security declarations and limited method exposure. | |
| 56 | |
| 57 Since it subclasses MultiMapping, this class can be used to wrap | |
| 58 one or more mapping objects. Restricted Python code will not be | |
| 59 able to mutate the SafeMapping or the wrapped mappings, but will be | |
| 60 able to read any value. | |
| 61 ''' | |
| 62 __allow_access_to_unprotected_subobjects__ = 1 | |
| 63 push = pop = None | |
| 64 | |
| 65 _push = MultiMapping.push | |
| 66 _pop = MultiMapping.pop | |
| 67 | |
| 68 | |
| 69 class Iterator(ZTUtils.Iterator): | |
| 70 def __init__(self, name, seq, context): | |
| 71 ZTUtils.Iterator.__init__(self, seq) | |
| 72 self.name = name | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
73 self._context_ref = ref(context) |
| 1049 | 74 |
| 75 def next(self): | |
| 76 if ZTUtils.Iterator.next(self): | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
77 context = self._context_ref() |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
78 if context is not None: |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
79 context.setLocal(self.name, self.item) |
| 1049 | 80 return 1 |
| 81 return 0 | |
| 82 | |
| 83 | |
| 84 class ErrorInfo: | |
| 85 """Information about an exception passed to an on-error handler.""" | |
| 86 __allow_access_to_unprotected_subobjects__ = 1 | |
| 87 | |
| 88 def __init__(self, err, position=(None, None)): | |
| 89 if isinstance(err, Exception): | |
| 90 self.type = err.__class__ | |
| 91 self.value = err | |
| 92 else: | |
| 93 self.type = err | |
| 94 self.value = None | |
| 95 self.lineno = position[0] | |
| 96 self.offset = position[1] | |
| 97 | |
| 98 | |
| 99 class Engine: | |
| 100 '''Expression Engine | |
| 101 | |
| 102 An instance of this class keeps a mutable collection of expression | |
| 103 type handlers. It can compile expression strings by delegating to | |
| 104 these handlers. It can provide an expression Context, which is | |
| 105 capable of holding state and evaluating compiled expressions. | |
| 106 ''' | |
| 107 Iterator = Iterator | |
| 108 | |
| 109 def __init__(self, Iterator=None): | |
| 110 self.types = {} | |
| 111 if Iterator is not None: | |
| 112 self.Iterator = Iterator | |
| 113 | |
| 114 def registerType(self, name, handler): | |
| 115 if not _valid_name(name): | |
| 116 raise RegistrationError, 'Invalid Expression type "%s".' % name | |
| 117 types = self.types | |
| 118 if types.has_key(name): | |
| 119 raise RegistrationError, ( | |
| 120 'Multiple registrations for Expression type "%s".' % | |
| 121 name) | |
| 122 types[name] = handler | |
| 123 | |
| 124 def getTypes(self): | |
| 125 return self.types | |
| 126 | |
| 127 def compile(self, expression): | |
| 128 m = _parse_expr(expression) | |
| 129 if m: | |
| 130 type = m.group(1) | |
| 131 expr = expression[m.end():] | |
| 132 else: | |
| 133 type = "standard" | |
| 134 expr = expression | |
| 135 try: | |
| 136 handler = self.types[type] | |
| 137 except KeyError: | |
| 138 raise CompilerError, ( | |
| 139 'Unrecognized expression type "%s".' % type) | |
| 140 return handler(type, expr, self) | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
141 |
| 1049 | 142 def getContext(self, contexts=None, **kwcontexts): |
| 143 if contexts is not None: | |
| 144 if kwcontexts: | |
| 145 kwcontexts.update(contexts) | |
| 146 else: | |
| 147 kwcontexts = contexts | |
| 148 return Context(self, kwcontexts) | |
| 149 | |
| 150 def getCompilerError(self): | |
| 151 return CompilerError | |
| 152 | |
| 153 class Context: | |
| 154 '''Expression Context | |
| 155 | |
| 156 An instance of this class holds context information that it can | |
| 157 use to evaluate compiled expressions. | |
| 158 ''' | |
| 159 | |
| 160 _context_class = SafeMapping | |
| 161 position = (None, None) | |
| 162 source_file = None | |
| 163 | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
164 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
|
165 self._compiler = compiler |
| 1049 | 166 self.contexts = contexts |
| 167 contexts['nothing'] = None | |
| 168 contexts['default'] = Default | |
| 169 | |
| 170 self.repeat_vars = rv = {} | |
| 171 # Wrap this, as it is visible to restricted code | |
| 172 contexts['repeat'] = rep = self._context_class(rv) | |
| 173 contexts['loop'] = rep # alias | |
| 174 | |
| 175 self.global_vars = gv = contexts.copy() | |
| 176 self.local_vars = lv = {} | |
| 177 self.vars = self._context_class(gv, lv) | |
| 178 | |
| 179 # Keep track of what needs to be popped as each scope ends. | |
| 180 self._scope_stack = [] | |
| 181 | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
182 def getCompiler(self): |
|
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
183 return self._compiler |
|
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
184 |
| 1049 | 185 def beginScope(self): |
| 186 self._scope_stack.append([self.local_vars.copy()]) | |
| 187 | |
| 188 def endScope(self): | |
| 189 scope = self._scope_stack.pop() | |
| 190 self.local_vars = lv = scope[0] | |
| 191 v = self.vars | |
| 192 v._pop() | |
| 193 v._push(lv) | |
| 194 # Pop repeat variables, if any | |
| 195 i = len(scope) - 1 | |
| 196 while i: | |
| 197 name, value = scope[i] | |
| 198 if value is None: | |
| 199 del self.repeat_vars[name] | |
| 200 else: | |
| 201 self.repeat_vars[name] = value | |
| 202 i = i - 1 | |
| 203 | |
| 204 def setLocal(self, name, value): | |
| 205 self.local_vars[name] = value | |
| 206 | |
| 207 def setGlobal(self, name, value): | |
| 208 self.global_vars[name] = value | |
| 209 | |
| 210 def setRepeat(self, name, expr): | |
| 211 expr = self.evaluate(expr) | |
| 212 if not expr: | |
|
1257
93b80ad11ca8
merged Zope Collector #372 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1219
diff
changeset
|
213 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
|
214 it = self._compiler.Iterator(name, expr, self) |
| 1049 | 215 old_value = self.repeat_vars.get(name) |
| 216 self._scope_stack[-1].append((name, old_value)) | |
| 217 self.repeat_vars[name] = it | |
| 218 return it | |
| 219 | |
| 220 def evaluate(self, expression, | |
| 221 isinstance=isinstance, StringType=StringType): | |
| 222 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
|
223 expression = self._compiler.compile(expression) |
| 1049 | 224 __traceback_supplement__ = ( |
| 225 TALESTracebackSupplement, self, expression) | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
226 return expression(self) |
| 1049 | 227 |
| 228 evaluateValue = evaluate | |
|
1219
9620f6782cb7
merge Zope Collector #580 fix from ZPT CVS trunk
Richard Jones <richard@users.sourceforge.net>
parents:
1071
diff
changeset
|
229 evaluateBoolean = evaluate |
| 1049 | 230 |
|
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
|
231 def evaluateText(self, expr): |
| 1049 | 232 text = self.evaluate(expr) |
| 233 if text is Default or text is None: | |
| 234 return text | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
235 if isinstance(text, unicode): |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
236 return text |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
237 else: |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
238 return ustr(text) |
| 1049 | 239 |
| 240 def evaluateStructure(self, expr): | |
| 241 return self.evaluate(expr) | |
| 242 evaluateStructure = evaluate | |
| 243 | |
| 244 def evaluateMacro(self, expr): | |
| 245 # XXX Should return None or a macro definition | |
| 246 return self.evaluate(expr) | |
| 247 evaluateMacro = evaluate | |
| 248 | |
| 249 def createErrorInfo(self, err, position): | |
| 250 return ErrorInfo(err, position) | |
| 251 | |
| 252 def getDefault(self): | |
| 253 return Default | |
| 254 | |
| 255 def setSourceFile(self, source_file): | |
| 256 self.source_file = source_file | |
| 257 | |
| 258 def setPosition(self, position): | |
| 259 self.position = position | |
| 260 | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
261 def translate(self, domain, msgid, mapping=None, |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
262 context=None, target_language=None, default=None): |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
263 if context is None: |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
264 context = self.contexts.get('here') |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
265 return getGlobalTranslationService().translate( |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
266 domain, msgid, mapping=mapping, |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
267 context=context, |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
268 default=default, |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
269 target_language=target_language) |
| 1049 | 270 |
| 271 class TALESTracebackSupplement: | |
| 272 """Implementation of ITracebackSupplement""" | |
| 273 def __init__(self, context, expression): | |
| 274 self.context = context | |
| 275 self.source_url = context.source_file | |
| 276 self.line = context.position[0] | |
| 277 self.column = context.position[1] | |
| 278 self.expression = repr(expression) | |
| 279 | |
| 280 def getInfo(self, as_html=0): | |
| 281 import pprint | |
| 282 data = self.context.contexts.copy() | |
| 283 s = pprint.pformat(data) | |
| 284 if not as_html: | |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
285 return ' - Names:\n %s' % s.replace('\n', '\n ') |
| 1049 | 286 else: |
| 287 from cgi import escape | |
| 288 return '<b>Names:</b><pre>%s</pre>' % (escape(s)) | |
| 289 | |
| 290 | |
| 291 class SimpleExpr: | |
| 292 '''Simple example of an expression type handler''' | |
| 293 def __init__(self, name, expr, engine): | |
| 294 self._name = name | |
| 295 self._expr = expr | |
| 296 def __call__(self, econtext): | |
| 297 return self._name, self._expr | |
| 298 def __repr__(self): | |
| 299 return '<SimpleExpr %s %s>' % (self._name, `self._expr`) |
