Package qm :: Package external :: Package DocumentTemplate :: Module DT_Util
[hide private]
[frames] | no frames]

Source Code for Module qm.external.DocumentTemplate.DT_Util

  1  ############################################################################## 
  2  # 
  3  # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved. 
  4  # 
  5  # This software is subject to the provisions of the Zope Public License, 
  6  # Version 2.1 (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 
 11  # 
 12  ############################################################################## 
 13  """DTML Utilities 
 14   
 15  $Id: DT_Util.py 1069 2008-11-13 21:55:43Z stefan $""" 
 16   
 17  import re 
 18  import VSEval 
 19   
 20  str=__builtins__['str'] # Waaaaa, waaaaaaaa needed for pickling waaaaa 
 21   
 22  ParseError='Document Template Parse Error' 
 23  ValidationError='Unauthorized' 
 24   
 25   
26 -def html_quote(v, name='(Unknown name)', md={}, 27 character_entities=( 28 (('&'), '&amp;'), 29 (('<'), '&lt;' ), 30 (('>'), '&gt;' ), 31 (('"'), '&quot;'))): #"
32 text=str(v) 33 for re,name in character_entities: 34 if text.find(re) >= 0: text=text.split(re).join(name) 35 return text 36
37 -def int_param(params,md,name,default=0, st=type('')):
38 v = params.get(name, default) 39 if v: 40 try: 41 v = int(v) 42 except: 43 v = md[v] 44 if isinstance(v, str): 45 v = int(v) 46 return v or 0
47 48 _marker=[] 49
50 -def careful_getattr(md, inst, name, default=_marker):
51 52 if name[:1]!='_': 53 54 # Try to get the attribute normally so that we don't 55 # accidentally acquire when we shouldn't. 56 try: v=getattr(inst, name) 57 except: 58 if default is not _marker: 59 return default 60 raise 61 62 validate=md.validate 63 64 if validate is None: return v 65 66 if hasattr(inst,'aq_acquire'): 67 return inst.aq_acquire(name, validate, md) 68 69 if validate(inst,inst,name,v,md): return v 70 71 raise ValidationError, name
72
73 -def careful_hasattr(md, inst, name):
74 v=getattr(inst, name, _marker) 75 if v is not _marker: 76 try: 77 if name[:1]!='_': 78 validate=md.validate 79 if validate is None: return 1 80 81 if hasattr(inst,'aq_acquire'): 82 inst.aq_acquire(name, validate, md) 83 return 1 84 85 if validate(inst,inst,name,v,md): return 1 86 except: pass 87 return 0
88
89 -def careful_getitem(md, mapping, key):
90 v=mapping[key] 91 92 if type(v) is type(''): return v # Short-circuit common case 93 94 validate=md.validate 95 if validate is None or validate(mapping,mapping,None,v,md): return v 96 raise ValidationError, key
97
98 -def careful_getslice(md, seq, *indexes):
99 v=len(indexes) 100 if v==2: 101 v=seq[indexes[0]:indexes[1]] 102 elif v==1: 103 v=seq[indexes[0]:] 104 else: v=seq[:] 105 106 if type(seq) is type(''): return v # Short-circuit common case 107 108 validate=md.validate 109 if validate is not None: 110 for e in v: 111 if not validate(seq,seq,None,e,md): 112 raise ValidationError, 'unauthorized access to slice member' 113 114 return v
115
116 -def careful_range(md, iFirst, *args):
117 # limited range function from Martijn Pieters 118 RANGELIMIT = 1000 119 if not len(args): 120 iStart, iEnd, iStep = 0, iFirst, 1 121 elif len(args) == 1: 122 iStart, iEnd, iStep = iFirst, args[0], 1 123 elif len(args) == 2: 124 iStart, iEnd, iStep = iFirst, args[0], args[1] 125 else: 126 raise AttributeError, 'range() requires 1-3 int arguments' 127 if iStep == 0: raise ValueError, 'zero step for range()' 128 iLen = int((iEnd - iStart) / iStep) 129 if iLen < 0: iLen = 0 130 if iLen >= RANGELIMIT: raise ValueError, 'range() too large' 131 return range(iStart, iEnd, iStep)
132 133 import string, math, random 134 135 try: 136 import ExtensionClass 137 from cDocumentTemplate import InstanceDict, TemplateDict, render_blocks 138 except: from pDocumentTemplate import InstanceDict, TemplateDict, render_blocks 139 140 141 d=TemplateDict.__dict__ 142 for name in ('None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int', 143 'len', 'max', 'min', 'oct', 'ord', 'round', 'str'): 144 d[name]=__builtins__[name] 145 d['string']=string 146 d['math']=math 147 d['random']=random 148
149 -def careful_pow(self, x, y, z):
150 if not z: raise ValueError, 'pow(x, y, z) with z==0' 151 return pow(x,y,z)
152 153 d['pow']=careful_pow 154 155 try: 156 import random 157 d['random']=random 158 except: pass 159 160 try: 161 import DateTime 162 d['DateTime']=DateTime.DateTime 163 except: pass 164
165 -def test(self, *args):
166 l=len(args) 167 for i in range(1, l, 2): 168 if args[i-1]: return args[i] 169 170 if l%2: return args[-1]
171 172 d['test']=test 173
174 -def obsolete_attr(self, inst, name, md):
175 return careful_getattr(md, inst, name)
176 177 d['attr']=obsolete_attr 178 d['getattr']=careful_getattr 179 d['hasattr']=careful_hasattr 180 d['range']=careful_range 181 182 #class namespace_: 183 # __allow_access_to_unprotected_subobjects__=1 184
185 -def namespace(self, **kw):
186 """Create a tuple consisting of a single instance whose attributes are 187 provided as keyword arguments.""" 188 if getattr(self, '__class__', None) != TemplateDict: 189 raise TypeError,'''A call was made to DT_Util.namespace() with an 190 incorrect "self" argument. It could be caused by a product which 191 is not yet compatible with this version of Zope. The traceback 192 information may contain more details.)''' 193 return apply(self, (), kw)
194 195 d['namespace']=namespace 196
197 -def render(self, v):
198 "Render an object in the way done by the 'name' attribute" 199 if hasattr(v, '__render_with_namespace__'): 200 v = v.__render_with_namespace__(self) 201 else: 202 vbase = getattr(v, 'aq_base', v) 203 if callable(vbase): 204 if getattr(vbase, 'isDocTemp', 0): 205 v = v(None, self) 206 else: 207 v = v() 208 return v
209 210 d['render']=render 211 212 expr_globals={ 213 '__builtins__':{}, 214 '__guarded_mul__': VSEval.careful_mul, 215 '__guarded_getattr__': careful_getattr, 216 '__guarded_getitem__': careful_getitem, 217 '__guarded_getslice__': careful_getslice, 218 } 219
220 -class Eval(VSEval.Eval):
221
222 - def eval(self, mapping):
223 d={'_vars': mapping, '_': mapping} 224 code=self.code 225 globals=self.globals 226 for name in self.used: 227 __traceback_info__ = name 228 try: d[name]=mapping.getitem(name,0) 229 except KeyError: 230 if name=='_getattr': 231 d['__builtins__']=globals 232 exec compiled_getattr in d 233 234 return eval(code,globals,d)
235 236
237 -def name_param(params,tag='',expr=0, attr='name', default_unnamed=1):
238 used=params.has_key 239 __traceback_info__=params, tag, expr, attr 240 241 #if expr and used('expr') and used('') and not used(params['']): 242 # # Fix up something like: <!--#in expr="whatever" mapping--> 243 # params[params['']]=default_unnamed 244 # del params[''] 245 246 if used(''): 247 v=params[''] 248 249 if v[:1]=='"' and v[-1:]=='"' and len(v) > 1: # expr shorthand 250 if used(attr): 251 raise ParseError, ('%s and expr given' % attr, tag) 252 if expr: 253 if used('expr'): 254 raise ParseError, ('two exprs given', tag) 255 v=v[1:-1] 256 try: expr=Eval(v, expr_globals) 257 except SyntaxError, v: 258 raise ParseError, ( 259 '<strong>Expression (Python) Syntax error</strong>:' 260 '\n<pre>\n%s\n</pre>\n' % v[0], 261 tag) 262 return v, expr 263 else: raise ParseError, ( 264 'The "..." shorthand for expr was used in a tag ' 265 'that doesn\'t support expr attributes.', 266 tag) 267 268 else: # name shorthand 269 if used(attr): 270 raise ParseError, ('Two %s values were given' % attr, tag) 271 if expr: 272 if used('expr'): 273 # raise 'Waaaaaa', 'waaa' 274 raise ParseError, ('%s and expr given' % attr, tag) 275 return params[''],None 276 return params[''] 277 278 elif used(attr): 279 if expr: 280 if used('expr'): 281 raise ParseError, ('%s and expr given' % attr, tag) 282 return params[attr],None 283 return params[attr] 284 elif expr and used('expr'): 285 name=params['expr'] 286 expr=Eval(name, expr_globals) 287 return name, expr 288 289 raise ParseError, ('No %s given' % attr, tag)
290 291 Expr_doc=""" 292 293 294 Python expression support 295 296 Several document template tags, including 'var', 'in', 'if', 'else', 297 and 'elif' provide support for using Python expressions via an 298 'expr' tag attribute. 299 300 Expressions may be used where a simple variable value is 301 inadequate. For example, an expression might be used to test 302 whether a variable is greater than some amount:: 303 304 <!--#if expr="age > 18"--> 305 306 or to transform some basic data:: 307 308 <!--#var expr="phone[:3]"--> 309 310 Objects available in the document templates namespace may be used. 311 Subobjects of these objects may be used as well, although subobject 312 access is restricted by the optional validation method. 313 314 In addition, a special additional name, '_', is available. The '_' 315 variable provides access to the document template namespace as a 316 mapping object. This variable can be useful for accessing objects 317 in a document template namespace that have names that are not legal 318 Python variable names:: 319 320 <!--#var expr="_['sequence-number']*5"--> 321 322 This variable also has attributes that provide access to standard 323 utility objects. These attributes include: 324 325 - The objects: 'None', 'abs', 'chr', 'divmod', 'float', 'hash', 326 'hex', 'int', 'len', 'max', 'min', 'oct', 'ord', 'pow', 327 'round', and 'str' from the standard Python builtin module. 328 329 - Special security-aware versions of 'getattr' and 'hasattr', 330 331 - The Python 'string', 'math', and 'random' modules, and 332 333 - A special function, 'test', that supports if-then expressions. 334 The 'test' function accepts any number of arguments. If the 335 first argument is true, then the second argument is returned, 336 otherwise if the third argument is true, then the fourth 337 argument is returned, and so on. If there is an odd number of 338 arguments, then the last argument is returned in the case that 339 none of the tested arguments is true, otherwise None is 340 returned. 341 342 For example, to convert a value to lower case:: 343 344 <!--#var expr="_.string.lower(title)"--> 345 346 """ 347 348 ListType=type([])
349 -def parse_params(text, 350 result=None, 351 tag='', 352 unparmre=re.compile('([\000- ]*([^\000- ="]+))'), 353 qunparmre=re.compile('([\000- ]*("[^"]*"))'), 354 parmre=re.compile('([\000- ]*([^\000- ="]+)=([^\000- ="]+))'), 355 qparmre=re.compile('([\000- ]*([^\000- ="]+)="([^"]*)")'), 356 **parms):
357 358 """Parse tag parameters 359 360 The format of tag parameters consists of 1 or more parameter 361 specifications separated by whitespace. Each specification 362 consists of an unnamed and unquoted value, a valueless name, or a 363 name-value pair. A name-value pair consists of a name and a 364 quoted or unquoted value separated by an '='. 365 366 The input parameter, text, gives the text to be parsed. The 367 keyword parameters give valid parameter names and default values. 368 369 If a specification is not a name-value pair and it is not the 370 first specification and it is a 371 valid parameter name, then it is treated as a name-value pair with 372 a value as given in the keyword argument. Otherwise, if it is not 373 a name-value pair, it is treated as an unnamed value. 374 375 The data are parsed into a dictionary mapping names to values. 376 Unnamed values are mapped from the name '""'. Only one value may 377 be given for a name and there may be only one unnamed value. """ 378 379 result=result or {} 380 381 # HACK - we precalculate all matches. Maybe we don't need them 382 # all. This should be fixed for performance issues 383 384 mo_p = parmre.match(text) 385 mo_q = qparmre.match(text) 386 mo_unp = unparmre.match(text) 387 mo_unq = qunparmre.match(text) 388 389 if mo_p: 390 name=mo_p.group(2).lower() 391 value=mo_p.group(3) 392 l=len(mo_p.group(1)) 393 elif mo_q: 394 name=mo_q.group(2).lower() 395 value=mo_q.group(3) 396 l=len(mo_q.group(1)) 397 elif mo_unp: 398 name=mo_unp.group(2) 399 l=len(mo_unp.group(1)) 400 if result: 401 if parms.has_key(name): 402 if parms[name] is None: raise ParseError, ( 403 'Attribute %s requires a value' % name, tag) 404 405 result[name]=parms[name] 406 else: raise ParseError, ( 407 'Invalid attribute name, "%s"' % name, tag) 408 else: 409 result['']=name 410 return parse_params(text[l:],result,**parms) 411 elif mo_unq: 412 name=mo_unq.group(2) 413 l=len(mo_unq.group(1)) 414 if result: raise ParseError, ( 415 'Invalid attribute name, "%s"' % name, tag) 416 else: result['']=name 417 return parse_params(text[l:],result,**parms) 418 else: 419 if not text or not text.strip(): return result 420 raise ParseError, ('invalid parameter: "%s"' % text, tag) 421 422 if not parms.has_key(name): 423 raise ParseError, ( 424 'Invalid attribute name, "%s"' % name, tag) 425 426 if result.has_key(name): 427 p=parms[name] 428 if type(p) is not ListType or p: 429 raise ParseError, ( 430 'Duplicate values for attribute "%s"' % name, tag) 431 432 result[name]=value 433 434 text=text[l:].strip() 435 if text: return parse_params(text,result,**parms) 436 else: return result
437