DT_Util.py
上传用户:gyjinxi
上传日期:2007-01-04
资源大小:159k
文件大小:17k
源码类别:

WEB邮件程序

开发平台:

Python

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64. '''$Id: DT_Util.py,v 1.61 1999/10/22 18:08:45 jim Exp $''' 
  65. __version__='$Revision: 1.61 $'[11:-2]
  66. import regex, string, math, os
  67. from string import strip, join, atoi, lower, split, find
  68. import VSEval
  69. str=__builtins__['str'] # Waaaaa, waaaaaaaa needed for pickling waaaaa
  70. ParseError='Document Template Parse Error'
  71. ValidationError='Unauthorized'
  72. def html_quote(v, name='(Unknown name)', md={},
  73.                character_entities=(
  74.                        (('&'), '&'),
  75.                        (("<"), '&lt;' ),
  76.                        ((">"), '&gt;' ),
  77.                        (('"'), '&quot;'))): #"
  78.         text=str(v)
  79.         for re,name in character_entities:
  80.             if find(text, re) >= 0: text=join(split(text,re),name)
  81.         return text
  82. def int_param(params,md,name,default=0, st=type('')):
  83.     try: v=params[name]
  84.     except: v=default
  85.     if v:
  86.         try: v=atoi(v)
  87.         except:
  88.             v=md[v]
  89.             if type(v) is st: v=atoi(v)
  90.     return v or 0
  91. _marker=[]
  92. def careful_getattr(md, inst, name, default=_marker):
  93.     
  94.     if name[:1]!='_':
  95.         # Try to get the attribute normally so that we don't
  96.         # accidentally acquire when we shouldn't.
  97.         try: v=getattr(inst, name)
  98.         except:
  99.             if default is not _marker:
  100.                 return default
  101.             raise
  102.         validate=md.validate
  103.         if validate is None: return v
  104.         if hasattr(inst,'aq_acquire'):
  105.             return inst.aq_acquire(name, validate, md)
  106.         if validate(inst,inst,name,v,md): return v
  107.     raise ValidationError, name
  108. def careful_hasattr(md, inst, name):
  109.     v=getattr(inst, name, _marker)
  110.     if v is not _marker:
  111.         try: 
  112.             if name[:1]!='_':
  113.                 validate=md.validate                
  114.                 if validate is None: return 1
  115.     
  116.                 if hasattr(inst,'aq_acquire'):
  117.                     inst.aq_acquire(name, validate, md)
  118.                     return 1
  119.     
  120.                 if validate(inst,inst,name,v,md): return 1
  121.         except: pass
  122.     return 0
  123. def careful_getitem(md, mapping, key):
  124.     v=mapping[key]
  125.     if type(v) is type(''): return v # Short-circuit common case
  126.     validate=md.validate
  127.     if validate is None or validate(mapping,mapping,key,v,md): return v
  128.     raise ValidationError, key
  129. def careful_getslice(md, seq, *indexes):
  130.     v=len(indexes)
  131.     if v==2:
  132.         v=seq[indexes[0]:indexes[1]]
  133.     elif v==1:
  134.         v=seq[indexes[0]:]
  135.     else: v=seq[:]
  136.     if type(seq) is type(''): return v # Short-circuit common case
  137.     validate=md.validate
  138.     if validate is not None:
  139.         for e in v:
  140.             if not validate(seq,seq,'',e,md):
  141.                 raise ValidationError, 'unauthorized access to slice member'
  142.     return v
  143. def careful_range(md, iFirst, *args):
  144.     # limited range function from Martijn Pieters
  145.     RANGELIMIT = 1000
  146.     if not len(args):
  147.         iStart, iEnd, iStep = 0, iFirst, 1
  148.     elif len(args) == 1:
  149.         iStart, iEnd, iStep = iFirst, args[0], 1
  150.     elif len(args) == 2:
  151.         iStart, iEnd, iStep = iFirst, args[0], args[1]
  152.     else:
  153.         raise AttributeError, 'range() requires 1-3 int arguments'
  154.     if iStep == 0: raise ValueError, 'zero step for range()'
  155.     iLen = int((iEnd - iStart) / iStep)
  156.     if iLen < 0: iLen = 0
  157.     if iLen >= RANGELIMIT: raise ValueError, 'range() too large'
  158.     return range(iStart, iEnd, iStep)
  159. import string, math, whrandom
  160. try:
  161.     import ExtensionClass
  162.     from cDocumentTemplate import InstanceDict, TemplateDict, render_blocks
  163.     from cDocumentTemplate import cDocument
  164. except: from pDocumentTemplate import InstanceDict, TemplateDict, render_blocks
  165. d=TemplateDict.__dict__
  166. for name in ('None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int',
  167.              'len', 'max', 'min', 'oct', 'ord', 'round', 'str'):
  168.     d[name]=__builtins__[name]
  169. d['string']=string
  170. d['math']=math
  171. d['whrandom']=whrandom
  172. def careful_pow(self, x, y, z):
  173.     if not z: raise ValueError, 'pow(x, y, z) with z==0'
  174.     return pow(x,y,z)
  175. d['pow']=careful_pow
  176. try:
  177.     import random
  178.     d['random']=random
  179. except: pass
  180. try:
  181.     import DateTime
  182.     d['DateTime']=DateTime.DateTime
  183. except: pass
  184. def test(self, *args):
  185.     l=len(args)
  186.     for i in range(1, l, 2):
  187.         if args[i-1]: return args[i]
  188.     if l%2: return args[-1]
  189. d['test']=test
  190. def obsolete_attr(self, inst, name, md):
  191.     return careful_getattr(md, inst, name)
  192. d['attr']=obsolete_attr
  193. d['getattr']=careful_getattr
  194. d['hasattr']=careful_hasattr
  195. d['range']=careful_range
  196. class namespace_: pass
  197. def namespace(self, **kw):
  198.     """Create a tuple consisting of a single instance whos attributes are
  199.     provided as keyword arguments."""
  200.     r=namespace_()
  201.     d=r.__dict__
  202.     for k, v in kw.items(): d[k]=v
  203.     return r,
  204. d['namespace']=namespace
  205. def render(self, v, simple={
  206.     type(''): 1, type(0): 1, type(0.0): 1,
  207.     type([]): 1, type(()): 1,
  208.     }.has_key):
  209.     "Render an object in the way done be the 'name' attribute"
  210.     if not simple(type(v)):
  211.         if hasattr(v,'isDocTemp') and v.isDocTemp:
  212.             v=v(None, self)
  213.         else:
  214.             try: v=v()
  215.             except (AttributeError,TypeError): pass
  216.     return v
  217. d['render']=render
  218. def reorder(self, s, with=None, without=()):
  219.     if with is None: with=s
  220.     d={}
  221.     tt=type(())
  222.     for i in s:
  223.         if type(i) is tt and len(i)==2: k, v = i
  224.         else:                           k= v = i
  225.         d[k]=v
  226.     r=[]
  227.     a=r.append
  228.     h=d.has_key
  229.     for i in without:
  230.         if type(i) is tt and len(i)==2: k, v = i
  231.         else:                           k= v = i
  232.         if h(k): del d[k]
  233.         
  234.     for i in with:
  235.         if type(i) is tt and len(i)==2: k, v = i
  236.         else:                           k= v = i
  237.         if h(k):
  238.             a((k,d[k]))
  239.             del d[k]
  240.     return r
  241. d['reorder']=reorder
  242. expr_globals={
  243.     '__builtins__':{},
  244.     '__guarded_mul__':      VSEval.careful_mul,
  245.     '__guarded_getattr__':  careful_getattr,
  246.     '__guarded_getitem__':  careful_getitem,
  247.     '__guarded_getslice__': careful_getslice,
  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.         return eval(code,globals,d)
  263. def name_param(params,tag='',expr=0, attr='name', default_unnamed=1):
  264.     used=params.has_key
  265.     __traceback_info__=params, tag, expr, attr
  266.     #if expr and used('expr') and used('') and not used(params['']):
  267.     #   # Fix up something like: <!--#in expr="whatever" mapping-->
  268.     #   params[params['']]=default_unnamed
  269.     #   del params['']
  270.         
  271.     if used(''):
  272.         v=params['']
  273.         if v[:1]=='"' and v[-1:]=='"' and len(v) > 1: # expr shorthand
  274.             if used(attr):
  275.                 raise ParseError, ('%s and expr given' % attr, tag)
  276.             if expr:
  277.                 if used('expr'):
  278.                     raise ParseError, ('two exprs given', tag)
  279.                 v=v[1:-1]
  280.                 try: expr=Eval(v, expr_globals)
  281.                 except SyntaxError, v:
  282.                     raise ParseError, (
  283.                         '<strong>Expression (Python) Syntax error</strong>:'
  284.                         'n<pre>n%sn</pre>n' % v[0],
  285.                         tag)
  286.                 return v, expr
  287.             else: raise ParseError, (
  288.                 'The "..." shorthand for expr was used in a tag '
  289.                 'that doesn't support expr attributes.',
  290.                 tag)
  291.         else: # name shorthand            
  292.             if used(attr):
  293.                 raise ParseError, ('Two %s values were given' % attr, tag)
  294.             if expr:
  295.                 if used('expr'):
  296.                     # raise 'Waaaaaa', 'waaa'
  297.                     raise ParseError, ('%s and expr given' % attr, tag)
  298.                 return params[''],None
  299.             return params['']
  300.     elif used(attr):
  301.         if expr:
  302.             if used('expr'):
  303.                 raise ParseError, ('%s and expr given' % attr, tag)
  304.             return params[attr],None
  305.         return params[attr]
  306.     elif expr and used('expr'):
  307.         name=params['expr']
  308.         expr=Eval(name, expr_globals)
  309.         return name, expr
  310.         
  311.     raise ParseError, ('No %s given' % attr, tag)
  312. Expr_doc="""
  313. Python expression support
  314.   Several document template tags, including 'var', 'in', 'if', 'else',
  315.   and 'elif' provide support for using Python expressions via an
  316.   'expr' tag attribute.
  317.   Expressions may be used where a simple variable value is
  318.   inadequate.  For example, an expression might be used to test
  319.   whether a variable is greater than some amount::
  320.      <!--#if expr="age > 18"-->
  321.   or to transform some basic data::
  322.      <!--#var expr="phone[:3]"-->
  323.   Objects available in the document templates namespace may be used.
  324.   Subobjects of these objects may be used as well, although subobject
  325.   access is restricted by the optional validation method.
  326.   In addition, a special additional name, '_', is available.  The '_'
  327.   variable provides access to the document template namespace as a
  328.   mapping object.  This variable can be useful for accessing objects
  329.   in a document template namespace that have names that are not legal
  330.   Python variable names::
  331.   
  332.      <!--#var expr="_['sequence-number']*5"-->
  333.   
  334.   This variable also has attributes that provide access to standard
  335.   utility objects.  These attributes include:
  336.   
  337.   - The objects: 'None', 'abs', 'chr', 'divmod', 'float', 'hash',
  338.        'hex', 'int', 'len', 'max', 'min', 'oct', 'ord', 'pow',
  339.        'round', and 'str' from the standard Python builtin module.
  340.   - Special security-aware versions of 'getattr' and 'hasattr',
  341.   
  342.   - The Python 'string', 'math', and 'whrandom' modules, and
  343.   
  344.   - A special function, 'test', that supports if-then expressions.
  345.     The 'test' function accepts any number of arguments.  If the
  346.     first argument is true, then the second argument is returned,
  347.     otherwise if the third argument is true, then the fourth
  348.     argument is returned, and so on.  If there is an odd number of
  349.     arguments, then the last argument is returned in the case that
  350.     none of the tested arguments is true, otherwise None is
  351.     returned. 
  352.   
  353.   For example, to convert a value to lower case::
  354.   
  355.     <!--#var expr="_.string.lower(title)"-->
  356. """
  357. ListType=type([])
  358. def parse_params(text,
  359.                  result=None,
  360.                  tag='',
  361.                  unparmre=regex.compile(
  362.                      '([- ]*([^- ="]+))'),
  363.                  qunparmre=regex.compile(
  364.                      '([- ]*("[^"]*"))'),
  365.                  parmre=regex.compile(
  366.                      '([- ]*([^- ="]+)=([^- ="]+))'),
  367.                  qparmre=regex.compile(
  368.                      '([- ]*([^- ="]+)="([^"]*)")'),
  369.                  **parms):
  370.     """Parse tag parameters
  371.     The format of tag parameters consists of 1 or more parameter
  372.     specifications separated by whitespace.  Each specification
  373.     consists of an unnamed and unquoted value, a valueless name, or a
  374.     name-value pair.  A name-value pair consists of a name and a
  375.     quoted or unquoted value separated by an '='.
  376.     The input parameter, text, gives the text to be parsed.  The
  377.     keyword parameters give valid parameter names and default values.
  378.     If a specification is not a name-value pair and it is not the
  379.     first specification and it is a
  380.     valid parameter name, then it is treated as a name-value pair with
  381.     a value as given in the keyword argument.  Otherwise, if it is not
  382.     a name-value pair, it is treated as an unnamed value.
  383.     The data are parsed into a dictionary mapping names to values.
  384.     Unnamed values are mapped from the name '""'.  Only one value may
  385.     be given for a name and there may be only one unnamed value. """
  386.     result=result or {}
  387.     if parmre.match(text) >= 0:
  388.         name=lower(parmre.group(2))
  389.         value=parmre.group(3)
  390.         l=len(parmre.group(1))
  391.     elif qparmre.match(text) >= 0:
  392.         name=lower(qparmre.group(2))
  393.         value=qparmre.group(3)
  394.         l=len(qparmre.group(1))
  395.     elif unparmre.match(text) >= 0:
  396.         name=unparmre.group(2)
  397.         l=len(unparmre.group(1))
  398.         if result:
  399.             if parms.has_key(name):
  400.                 if parms[name] is None: raise ParseError, (
  401.                     'Attribute %s requires a value' % name, tag)
  402.                     
  403.                 result[name]=parms[name]
  404.             else: raise ParseError, (
  405.                 'Invalid attribute name, "%s"' % name, tag)
  406.         else:
  407.             result['']=name
  408.         return apply(parse_params,(text[l:],result),parms)
  409.     elif qunparmre.match(text) >= 0:
  410.         name=qunparmre.group(2)
  411.         l=len(qunparmre.group(1))
  412.         if result: raise ParseError, (
  413.             'Invalid attribute name, "%s"' % name, tag)
  414.         else: result['']=name
  415.         return apply(parse_params,(text[l:],result),parms)
  416.     else:
  417.         if not text or not strip(text): return result
  418.         raise ParseError, ('invalid parameter: "%s"' % text, tag)
  419.     
  420.     if not parms.has_key(name):
  421.         raise ParseError, (
  422.             'Invalid attribute name, "%s"' % name, tag)
  423.     if result.has_key(name):
  424.         p=parms[name]
  425.         if type(p) is not ListType or p:
  426.             raise ParseError, (
  427.                 'Duplicate values for attribute "%s"' % name, tag)
  428.             
  429.     result[name]=value
  430.     text=strip(text[l:])
  431.     if text: return apply(parse_params,(text,result),parms)
  432.     else: return result