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 1007 2007-02-10 01:07:28Z 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 -def reorder(self, s, with=None, without=()):
213 if with is None: with=s 214 d={} 215 tt=type(()) 216 for i in s: 217 if type(i) is tt and len(i)==2: k, v = i 218 else: k= v = i 219 d[k]=v 220 r=[] 221 a=r.append 222 h=d.has_key 223 224 for i in without: 225 if type(i) is tt and len(i)==2: k, v = i 226 else: k= v = i 227 if h(k): del d[k] 228 229 for i in with: 230 if type(i) is tt and len(i)==2: k, v = i 231 else: k= v = i 232 if h(k): 233 a((k,d[k])) 234 del d[k] 235 236 return r
237 238 d['reorder']=reorder 239 240 241 expr_globals={ 242 '__builtins__':{}, 243 '__guarded_mul__': VSEval.careful_mul, 244 '__guarded_getattr__': careful_getattr, 245 '__guarded_getitem__': careful_getitem, 246 '__guarded_getslice__': careful_getslice, 247 } 248
249 -class Eval(VSEval.Eval):
250
251 - def eval(self, mapping):
252 d={'_vars': mapping, '_': mapping} 253 code=self.code 254 globals=self.globals 255 for name in self.used: 256 __traceback_info__ = name 257 try: d[name]=mapping.getitem(name,0) 258 except KeyError: 259 if name=='_getattr': 260 d['__builtins__']=globals 261 exec compiled_getattr in d 262 263 return eval(code,globals,d)
264 265
266 -def name_param(params,tag='',expr=0, attr='name', default_unnamed=1):
267 used=params.has_key 268 __traceback_info__=params, tag, expr, attr 269 270 #if expr and used('expr') and used('') and not used(params['']): 271 # # Fix up something like: <!--#in expr="whatever" mapping--> 272 # params[params['']]=default_unnamed 273 # del params[''] 274 275 if used(''): 276 v=params[''] 277 278 if v[:1]=='"' and v[-1:]=='"' and len(v) > 1: # expr shorthand 279 if used(attr): 280 raise ParseError, ('%s and expr given' % attr, tag) 281 if expr: 282 if used('expr'): 283 raise ParseError, ('two exprs given', tag) 284 v=v[1:-1] 285 try: expr=Eval(v, expr_globals) 286 except SyntaxError, v: 287 raise ParseError, ( 288 '<strong>Expression (Python) Syntax error</strong>:' 289 '\n<pre>\n%s\n</pre>\n' % v[0], 290 tag) 291 return v, expr 292 else: raise ParseError, ( 293 'The "..." shorthand for expr was used in a tag ' 294 'that doesn\'t support expr attributes.', 295 tag) 296 297 else: # name shorthand 298 if used(attr): 299 raise ParseError, ('Two %s values were given' % attr, tag) 300 if expr: 301 if used('expr'): 302 # raise 'Waaaaaa', 'waaa' 303 raise ParseError, ('%s and expr given' % attr, tag) 304 return params[''],None 305 return params[''] 306 307 elif used(attr): 308 if expr: 309 if used('expr'): 310 raise ParseError, ('%s and expr given' % attr, tag) 311 return params[attr],None 312 return params[attr] 313 elif expr and used('expr'): 314 name=params['expr'] 315 expr=Eval(name, expr_globals) 316 return name, expr 317 318 raise ParseError, ('No %s given' % attr, tag)
319 320 Expr_doc=""" 321 322 323 Python expression support 324 325 Several document template tags, including 'var', 'in', 'if', 'else', 326 and 'elif' provide support for using Python expressions via an 327 'expr' tag attribute. 328 329 Expressions may be used where a simple variable value is 330 inadequate. For example, an expression might be used to test 331 whether a variable is greater than some amount:: 332 333 <!--#if expr="age > 18"--> 334 335 or to transform some basic data:: 336 337 <!--#var expr="phone[:3]"--> 338 339 Objects available in the document templates namespace may be used. 340 Subobjects of these objects may be used as well, although subobject 341 access is restricted by the optional validation method. 342 343 In addition, a special additional name, '_', is available. The '_' 344 variable provides access to the document template namespace as a 345 mapping object. This variable can be useful for accessing objects 346 in a document template namespace that have names that are not legal 347 Python variable names:: 348 349 <!--#var expr="_['sequence-number']*5"--> 350 351 This variable also has attributes that provide access to standard 352 utility objects. These attributes include: 353 354 - The objects: 'None', 'abs', 'chr', 'divmod', 'float', 'hash', 355 'hex', 'int', 'len', 'max', 'min', 'oct', 'ord', 'pow', 356 'round', and 'str' from the standard Python builtin module. 357 358 - Special security-aware versions of 'getattr' and 'hasattr', 359 360 - The Python 'string', 'math', and 'random' modules, and 361 362 - A special function, 'test', that supports if-then expressions. 363 The 'test' function accepts any number of arguments. If the 364 first argument is true, then the second argument is returned, 365 otherwise if the third argument is true, then the fourth 366 argument is returned, and so on. If there is an odd number of 367 arguments, then the last argument is returned in the case that 368 none of the tested arguments is true, otherwise None is 369 returned. 370 371 For example, to convert a value to lower case:: 372 373 <!--#var expr="_.string.lower(title)"--> 374 375 """ 376 377 ListType=type([])
378 -def parse_params(text, 379 result=None, 380 tag='', 381 unparmre=re.compile('([\000- ]*([^\000- ="]+))'), 382 qunparmre=re.compile('([\000- ]*("[^"]*"))'), 383 parmre=re.compile('([\000- ]*([^\000- ="]+)=([^\000- ="]+))'), 384 qparmre=re.compile('([\000- ]*([^\000- ="]+)="([^"]*)")'), 385 **parms):
386 387 """Parse tag parameters 388 389 The format of tag parameters consists of 1 or more parameter 390 specifications separated by whitespace. Each specification 391 consists of an unnamed and unquoted value, a valueless name, or a 392 name-value pair. A name-value pair consists of a name and a 393 quoted or unquoted value separated by an '='. 394 395 The input parameter, text, gives the text to be parsed. The 396 keyword parameters give valid parameter names and default values. 397 398 If a specification is not a name-value pair and it is not the 399 first specification and it is a 400 valid parameter name, then it is treated as a name-value pair with 401 a value as given in the keyword argument. Otherwise, if it is not 402 a name-value pair, it is treated as an unnamed value. 403 404 The data are parsed into a dictionary mapping names to values. 405 Unnamed values are mapped from the name '""'. Only one value may 406 be given for a name and there may be only one unnamed value. """ 407 408 result=result or {} 409 410 # HACK - we precalculate all matches. Maybe we don't need them 411 # all. This should be fixed for performance issues 412 413 mo_p = parmre.match(text) 414 mo_q = qparmre.match(text) 415 mo_unp = unparmre.match(text) 416 mo_unq = qunparmre.match(text) 417 418 if mo_p: 419 name=mo_p.group(2).lower() 420 value=mo_p.group(3) 421 l=len(mo_p.group(1)) 422 elif mo_q: 423 name=mo_q.group(2).lower() 424 value=mo_q.group(3) 425 l=len(mo_q.group(1)) 426 elif mo_unp: 427 name=mo_unp.group(2) 428 l=len(mo_unp.group(1)) 429 if result: 430 if parms.has_key(name): 431 if parms[name] is None: raise ParseError, ( 432 'Attribute %s requires a value' % name, tag) 433 434 result[name]=parms[name] 435 else: raise ParseError, ( 436 'Invalid attribute name, "%s"' % name, tag) 437 else: 438 result['']=name 439 return parse_params(text[l:],result,**parms) 440 elif mo_unq: 441 name=mo_unq.group(2) 442 l=len(mo_unq.group(1)) 443 if result: raise ParseError, ( 444 'Invalid attribute name, "%s"' % name, tag) 445 else: result['']=name 446 return parse_params(text[l:],result,**parms) 447 else: 448 if not text or not text.strip(): return result 449 raise ParseError, ('invalid parameter: "%s"' % text, tag) 450 451 if not parms.has_key(name): 452 raise ParseError, ( 453 'Invalid attribute name, "%s"' % name, tag) 454 455 if result.has_key(name): 456 p=parms[name] 457 if type(p) is not ListType or p: 458 raise ParseError, ( 459 'Duplicate values for attribute "%s"' % name, tag) 460 461 result[name]=value 462 463 text=text[l:].strip() 464 if text: return parse_params(text,result,**parms) 465 else: return result
466