Mercurial > p > roundup > code
annotate roundup/cgi/PageTemplates/TALES.py @ 2467:76ead526113d
client instances may be used as translation engines.
any backend translator may be passed as constructor
argument or via setTranslator() method. by default,
templating.translationService is used.
use this engine to translate client messages.
| author | Alexander Smishlajev <a1s@users.sourceforge.net> |
|---|---|
| date | Tue, 15 Jun 2004 09:19:49 +0000 |
| parents | b43efe461b3e |
| children | 29779f041ee7 |
| 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 |
|
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
16 # 2. implemented ustr as atr |
| 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 |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
22 __version__='$Revision: 1.7 $'[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`) |
