Mercurial > p > roundup > code
annotate roundup/cgi/PageTemplates/TALES.py @ 3896:fca0365521fc
ignore client shutdown exceptions when sending responses
patch from Ulrik Miaelsson
If the user clicks the stop button, or click another link before
the previous has finished loading, or something similar an IOError
exception will be raised which results in the admin being sent an
email.
This can understandably be pretty annoying if your users are
doing that on a regular basis. So we'll trap that exception
and ignore it.
| author | Justus Pendleton <jpend@users.sourceforge.net> |
|---|---|
| date | Tue, 11 Sep 2007 21:30:14 +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`) |
