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