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