[Zope3-checkins] SVN: Zope3/trunk/src/zope/documenttemplate/ Shifted responsibility for compiling python exprs to templates

Jim Fulton jim at zope.com
Fri Jul 23 18:08:14 EDT 2004


Log message for revision 26737:
  Shifted responsibility for compiling python exprs to templates
  
  This will make it easier to introduce some needed security in the app
  server. 
  
  Also got rid os some TemplateDict class-dictionary hacking silliness.
  


Changed:
  U   Zope3/trunk/src/zope/documenttemplate/dt_if.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_in.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_let.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_raise.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_return.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_string.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_try.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_util.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_var.py
  U   Zope3/trunk/src/zope/documenttemplate/dt_with.py
  U   Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py


-=-
Modified: Zope3/trunk/src/zope/documenttemplate/dt_if.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_if.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_if.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -77,8 +77,7 @@
 
 $Id$
 """
-from zope.documenttemplate.dt_util import \
-     ParseError, parse_params, name_param
+from zope.documenttemplate.dt_util import ParseError, parse_params, name_param
 
 class If:
     blockContinuations = 'else', 'elif'
@@ -86,10 +85,10 @@
     elses = None
     expr = ''
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
         args = parse_params(args, name='', expr='')
-        name,expr = name_param(args,'if',1)
+        name,expr = name_param(context, args,'if',1)
         self.__name__ = name
         if expr is None:
             cond = name
@@ -102,7 +101,7 @@
             del blocks[-1]
             args = parse_params(args, name='')
             if args:
-                ename,expr=name_param(args,'else',1)
+                ename,expr=name_param(context, args,'else',1)
                 if ename != name:
                     raise ParseError, ('name in else does not match if', 'in')
             elses=section.blocks
@@ -113,7 +112,7 @@
                 raise ParseError, (
                     'more than one else tag for a single if tag', 'in')
             args = parse_params(args, name='', expr='')
-            name,expr = name_param(args, 'elif', 1)
+            name,expr = name_param(context, args, 'elif', 1)
             if expr is None:
                 cond = name
             else:
@@ -131,10 +130,10 @@
     name = 'unless'
     blockContinuations = ()
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
         args=parse_params(args, name='', expr='')
-        name,expr=name_param(args, 'unless', 1)
+        name,expr=name_param(context, args, 'unless', 1)
         if expr is None:
             cond = name
         else:

Modified: Zope3/trunk/src/zope/documenttemplate/dt_in.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_in.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_in.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -329,8 +329,8 @@
     blockContinuations = ('else',)
     name = 'in'
 
-    def __call__(self, blocks):
-        i = InClass(blocks)
+    def __call__(self, context, blocks):
+        i = InClass(context, blocks)
         if i.batch:
             return i.renderwb
         else:
@@ -345,7 +345,7 @@
     reverse = None
     sort_expr = reverse_expr = None
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
         args=parse_params(args, name='', start='1',end='-1',size='10',
                           orphan='3',overlap='1',mapping=1,
@@ -360,10 +360,10 @@
             if sort=='sequence-item': self.sort=''
 
         if has_key('sort_expr'):
-            self.sort_expr = Eval(args['sort_expr'])
+            self.sort_expr = Eval(context, args['sort_expr'])
 
         if has_key('reverse_expr'):
-            self.reverse_expr = Eval(args['reverse_expr'])
+            self.reverse_expr = Eval(context, args['reverse_expr'])
 
         if has_key('reverse'):
             self.reverse = args['reverse']
@@ -393,7 +393,7 @@
                         ''.join(map(lambda c: "[%s]" % c, v))+
                         '=[0-9]+&+')
 
-        name, expr = name_param(args, 'in', 1)
+        name, expr = name_param(context, args, 'in', 1)
         if expr is not None:
             expr = expr.eval
         self.__name__, self.expr = name, expr
@@ -404,7 +404,7 @@
             tname, args, section = blocks[1]
             args=parse_params(args, name='')
             if args:
-                ename=name_param(args)
+                ename = name_param(context, args)
                 if ename != name:
                     raise ParseError, (
                         'name in else does not match in', 'in')

Modified: Zope3/trunk/src/zope/documenttemplate/dt_let.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_let.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_let.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -50,7 +50,7 @@
     blockContinuations = ()
     name = 'let'
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
         self.__name__ = args
         self.section = section.blocks
@@ -62,7 +62,7 @@
                 # expr shorthand
                 expr = expr[1:-1]
                 try:
-                    args[i] = name, Eval(expr).eval
+                    args[i] = name, Eval(context, expr).eval
                 except SyntaxError, v:
                     m,(huh,l,c,src) = v
                     raise ParseError, (

Modified: Zope3/trunk/src/zope/documenttemplate/dt_raise.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_raise.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_raise.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -25,19 +25,20 @@
 
 $Id$
 '''
-from zope.documenttemplate.dt_util import \
-     parse_params, name_param, render_blocks
+from zope.documenttemplate.dt_util \
+     import parse_params, name_param, render_blocks
 
 class Raise:
     blockContinuations = ()
     name = 'raise'
     expr = ''
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
         self.section=section.blocks
         args=parse_params(args, type='', expr='')
-        self.__name__, self.expr = name_param(args, 'raise', 1, attr='type')
+        self.__name__, self.expr = name_param(
+            context, args, 'raise', 1, attr='type')
 
     def render(self, md):
         expr = self.expr

Modified: Zope3/trunk/src/zope/documenttemplate/dt_return.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_return.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_return.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -21,9 +21,9 @@
     name = 'return'
     expr = None
 
-    def __init__(self, args):
+    def __init__(self, context, args):
         args = parse_params(args, name='', expr='')
-        name, expr = name_param(args,'var',1)
+        name, expr = name_param(context, args,'var',1)
         self.__name__, self.expr = name, expr
 
     def render(self, md):

Modified: Zope3/trunk/src/zope/documenttemplate/dt_string.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_string.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_string.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -177,9 +177,9 @@
             else:
                 try:
                     if command is Var:
-                        r = command(args, self.varExtra(mo))
+                        r = command(self, args, self.varExtra(mo))
                     else:
-                        r = command(args)
+                        r = command(self, args)
                     if hasattr(r,'simple_form'):
                         r = r.simple_form
                     result.append(r)
@@ -248,7 +248,7 @@
                     sstart = start
                 else:
                     try:
-                        r = scommand(blocks)
+                        r = scommand(self, blocks)
                         if hasattr(r,'simple_form'):
                             r = r.simple_form
                         result.append(r)
@@ -503,3 +503,7 @@
             if k[:3] in _special: continue
             d[k] = v
         return d
+
+    def compile_python_expresssion(self, src):
+        return compile(src, getattr(self, '__name__', '<string>'), 'eval')
+    

Modified: Zope3/trunk/src/zope/documenttemplate/dt_try.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_try.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_try.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -18,8 +18,9 @@
 
 import sys, traceback
 from StringIO import StringIO
-from zope.documenttemplate.dt_util import ParseError, parse_params, render_blocks
-from zope.documenttemplate.dt_util import namespace, InstanceDict
+from zope.documenttemplate.dt_util \
+     import ParseError, parse_params, render_blocks
+from zope.documenttemplate.dt_util import InstanceDict
 from zope.documenttemplate.dt_return import DTReturn
 
 from types import StringType
@@ -95,7 +96,7 @@
     finallyBlock = None
     elseBlock = None
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
 
         self.args = parse_params(args)
@@ -178,7 +179,7 @@
                 f = StringIO()
                 traceback.print_exc(100,f)
                 error_tb = f.getvalue()
-                ns = namespace(md, error_type=errname, error_value=v,
+                ns = md.namespace(error_type=errname, error_value=v,
                     error_tb=error_tb)[0]
                 md._push(InstanceDict(ns,md))
                 return render_blocks(handler, md)

Modified: Zope3/trunk/src/zope/documenttemplate/dt_util.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_util.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_util.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -16,10 +16,7 @@
 $Id$
 """
 import re
-import math
-import random
 
-from __builtin__ import str  # needed for pickling (legacy)
 from types import ListType, StringType, TupleType
 
 from zope.documenttemplate.pdocumenttemplate import \
@@ -59,209 +56,12 @@
                 v = v.atoi()
     return v or 0
 
-_marker=[]
-
-def careful_getattr(md, inst, name, default=_marker):
-
-    if name[:1] != '_':
-
-        try:
-            v = getattr(inst, name)
-        except:
-            if default is not _marker:
-                return default
-            raise
-
-        validate = md.validate
-
-        if validate is None:
-            return v
-
-        if validate(inst, inst, name, v, md):
-            return v
-
-    raise ValidationError, name
-
-
-def careful_hasattr(md, inst, name):
-    v=getattr(inst, name, _marker)
-    if v is not _marker:
-        try:
-            if name[:1] != '_':
-                validate = md.validate
-                if validate is None:
-                    return 1
-
-                if validate(inst, inst, name, v, md):
-                    return 1
-        except:
-            pass
-    return 0
-
-
-def careful_getitem(md, mapping, key):
-    v = mapping[key]
-    if isinstance(v, StringType):
-        return v # Short-circuit common case
-
-    validate = md.validate
-    if validate is None or validate(mapping, mapping, None, v, md):
-        return v
-    raise ValidationError, key
-
-
-def careful_getslice(md, seq, *indexes):
-    v = len(indexes)
-    if v == 2:
-        v = seq[indexes[0]:indexes[1]]
-    elif v == 1:
-        v = seq[indexes[0]:]
-    else:
-        v = seq[:]
-
-    if isinstance(seq, StringType):
-        return v # Short-circuit common case
-
-    validate = md.validate
-    if validate is not None:
-        for e in v:
-            if not validate(seq,seq,None,e,md):
-                raise ValidationError, u'unauthorized access to slice member'
-
-    return v
-
-
-def careful_range(md, iFirst, *args):
-    # limited range function from Martijn Pieters
-    RANGELIMIT = 1000
-    if not len(args):
-        iStart, iEnd, iStep = 0, iFirst, 1
-    elif len(args) == 1:
-        iStart, iEnd, iStep = iFirst, args[0], 1
-    elif len(args) == 2:
-        iStart, iEnd, iStep = iFirst, args[0], args[1]
-    else:
-        raise AttributeError, u'range() requires 1-3 int arguments'
-    if iStep == 0:
-        raise ValueError, u'zero step for range()'
-    iLen = int((iEnd - iStart) / iStep)
-    if iLen < 0:
-        iLen = 0
-    if iLen >= RANGELIMIT:
-        raise ValueError, u'range() too large'
-    return range(iStart, iEnd, iStep)
-
-
-d = TemplateDict.__dict__
-for name in ('None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int',
-             'len', 'max', 'min', 'oct', 'ord', 'round', 'str'):
-    d[name] = __builtins__[name]
-
-d['math'] = math
-d['random'] = random
-
-def careful_pow(self, x, y, z):
-    if not z:
-        raise ValueError, 'pow(x, y, z) with z==0'
-    return pow(x,y,z)
-
-d['pow'] = careful_pow
-
-try:
-    import DateTime
-    d['DateTime']=DateTime.DateTime
-except:
-    pass
-
-
-def test(self, *args):
-    l = len(args)
-    for i in range(1, l, 2):
-        if args[i-1]:
-            return args[i]
-
-    if l%2:
-        return args[-1]
-
-d['test'] = test
-
-def obsolete_attr(self, inst, name, md):
-    return careful_getattr(md, inst, name)
-
-d['attr'] = obsolete_attr
-d['getattr'] = careful_getattr
-d['hasattr'] = careful_hasattr
-d['range'] = careful_range
-
-def namespace(self, **kw):
-    """Create a tuple consisting of a single instance whose attributes are
-    provided as keyword arguments."""
-    if getattr(self, '__class__', None) != TemplateDict:
-        raise TypeError,'''A call was made to DT_Util.namespace() with an
-        incorrect "self" argument.  It could be caused by a product which
-        is not yet compatible with this version of Zope.  The traceback
-        information may contain more details.)'''
-    return apply(self, (), kw)
-
-d['namespace'] = namespace
-
-def render(self, v):
-    "Render an object in the way done by the 'name' attribute"
-    if hasattr(v, '__render_with_namespace__'):
-        v = v.__render_with_namespace__(self)
-    else:
-        vbase = getattr(v, 'aq_base', v)
-        if callable(vbase):
-            v = v()
-    return v
-
-d['render'] = render
-
-def reorder(self, s, with=None, without=()):
-    if with is None:
-        with = s
-    d = {}
-    for i in s:
-        if isinstance(i, TupleType) and len(i) == 2:
-            k, v = i
-        else:
-            k = v = i
-        d[k] = v
-    r = []
-    a = r.append
-    h = d.has_key
-
-    for i in without:
-        if isinstance(i, TupleType) and len(i) == 2:
-            k, v = i
-        else:
-            k= v = i
-        if h(k):
-            del d[k]
-
-    for i in with:
-        if isinstance(i, TupleType) and len(i) == 2:
-            k, v = i
-        else:
-            k= v = i
-        if h(k):
-            a((k,d[k]))
-            del d[k]
-
-    return r
-
-d['reorder'] = reorder
-
-
 class Eval:
 
-    def __init__(self, expr):
+    def __init__(self, context, expr):
 
-        expr = expr.strip()
-        expr = expr.replace('\n', ' ')
-        expr = expr.replace('\r', ' ')
-        self.expr = expr
-        self.code = compile(expr,'<string>','eval')
+        self.expr = '('+expr.strip()+')'
+        self.code = context.compile_python_expresssion(self.expr)
 
 
     def eval(self, mapping):
@@ -279,7 +79,7 @@
                     # does need the name, a NameError will occur.
                     pass
 
-        return eval(code, {}, d)
+        return eval(code, {'__builtins__': None}, d)
 
 
     def __call__(self, **kw):
@@ -287,7 +87,8 @@
 
 
 
-def name_param(params,tag='',expr=0, attr='name', default_unnamed=1):
+def name_param(context, params, tag='', expr=0, attr='name',
+               default_unnamed=1):
     used = params.has_key
     __traceback_info__ = params, tag, expr, attr
 
@@ -307,7 +108,7 @@
                     raise ParseError, (u'two exprs given', tag)
                 v = v[1:-1]
                 try:
-                    expr=Eval(v)
+                    expr=Eval(context, v)
                 except SyntaxError, v:
                     raise ParseError, (
                         u'<strong>Expression (Python) Syntax error</strong>:'
@@ -338,7 +139,7 @@
         return params[attr]
     elif expr and used('expr'):
         name = params['expr']
-        expr = Eval(name)
+        expr = Eval(context, name)
         return name, expr
 
     raise ParseError, (u'No %s given' % attr, tag)

Modified: Zope3/trunk/src/zope/documenttemplate/dt_var.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_var.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_var.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -147,7 +147,7 @@
 
 $Id$
 """
-from zope.documenttemplate.dt_util import parse_params, name_param, html_quote, str
+from zope.documenttemplate.dt_util import parse_params, name_param, html_quote
 import re, sys
 from urllib import quote, quote_plus
 
@@ -156,7 +156,7 @@
     name = 'var'
     expr = None
 
-    def __init__(self, args, fmt='s'):
+    def __init__(self, context, args, fmt='s'):
         if args[:4] == 'var ':
             args = args[4:]
         args = parse_params(args, name='', lower=1, upper=1, expr='',
@@ -173,7 +173,7 @@
                        used(m[0]) and args[m[0]],
                        modifiers)))
 
-        name, expr = name_param(args, 'var', 1)
+        name, expr = name_param(context, args, 'var', 1)
 
         self.__name__, self.expr = name, expr
         self.fmt = fmt
@@ -285,9 +285,9 @@
     name = 'call'
     expr = None
 
-    def __init__(self, args):
+    def __init__(self, context, args):
         args = parse_params(args, name='', expr='')
-        name, expr = name_param(args,'call',1)
+        name, expr = name_param(context, args,'call',1)
         if expr is None:
             expr = name
         else:
@@ -451,7 +451,7 @@
     name = 'comment'
     blockContinuations = ()
 
-    def __init__(self, args, fmt=''):
+    def __init__(self, context, args, fmt=''):
         pass
 
     def render(self, md):

Modified: Zope3/trunk/src/zope/documenttemplate/dt_with.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/dt_with.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/dt_with.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -48,10 +48,10 @@
     mapping = None
     only = 0
 
-    def __init__(self, blocks):
+    def __init__(self, context, blocks):
         tname, args, section = blocks[0]
         args = parse_params(args, name='', expr='', mapping=1, only=1)
-        name, expr = name_param(args, 'with', 1)
+        name, expr = name_param(context, args, 'with', 1)
         if expr is None:
             expr = name
         else:

Modified: Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py
===================================================================
--- Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py	2004-07-23 22:08:09 UTC (rev 26736)
+++ Zope3/trunk/src/zope/documenttemplate/pdocumenttemplate.py	2004-07-23 22:08:14 UTC (rev 26737)
@@ -171,7 +171,103 @@
             m=kw
         return (DictInstance(m),)
 
+    # extra handy utilities that people expect to find in template dicts:
 
+    import math
+    import random
+
+    def range(md, iFirst, *args):
+        # limited range function from Martijn Pieters
+        RANGELIMIT = 1000
+        if not len(args):
+            iStart, iEnd, iStep = 0, iFirst, 1
+        elif len(args) == 1:
+            iStart, iEnd, iStep = iFirst, args[0], 1
+        elif len(args) == 2:
+            iStart, iEnd, iStep = iFirst, args[0], args[1]
+        else:
+            raise AttributeError, u'range() requires 1-3 int arguments'
+        if iStep == 0:
+            raise ValueError, u'zero step for range()'
+        iLen = int((iEnd - iStart) / iStep)
+        if iLen < 0:
+            iLen = 0
+        if iLen >= RANGELIMIT:
+            raise ValueError, u'range() too large'
+        return range(iStart, iEnd, iStep)
+
+    def pow(self, x, y, z):
+        if not z:
+            raise ValueError, 'pow(x, y, z) with z==0'
+        return pow(x,y,z)
+
+    def test(self, *args):
+        l = len(args)
+        for i in range(1, l, 2):
+            if args[i-1]:
+                return args[i]
+
+        if l%2:
+            return args[-1]
+
+    getattr = getattr
+    attr = getattr
+    hasattr = hasattr
+    
+    def namespace(self, **kw):
+        return self(**kw)
+
+    def render(self, v):
+        "Render an object in the way done by the 'name' attribute"
+        if hasattr(v, '__render_with_namespace__'):
+            v = v.__render_with_namespace__(self)
+        else:
+            vbase = getattr(v, 'aq_base', v)
+            if callable(vbase):
+                v = v()
+        return v
+
+    def reorder(self, s, with=None, without=()):
+        if with is None:
+            with = s
+        d = {}
+        for i in s:
+            if isinstance(i, TupleType) and len(i) == 2:
+                k, v = i
+            else:
+                k = v = i
+            d[k] = v
+        r = []
+        a = r.append
+        h = d.has_key
+
+        for i in without:
+            if isinstance(i, TupleType) and len(i) == 2:
+                k, v = i
+            else:
+                k= v = i
+            if h(k):
+                del d[k]
+
+        for i in with:
+            if isinstance(i, TupleType) and len(i) == 2:
+                k, v = i
+            else:
+                k= v = i
+            if h(k):
+                a((k,d[k]))
+                del d[k]
+
+        return r
+
+
+# Add selected builtins to template dicts
+for name in ('None', 'abs', 'chr', 'divmod', 'float', 'hash', 'hex', 'int',
+             'len', 'max', 'min', 'oct', 'ord', 'round', 'str'):
+    setattr(TemplateDict, name, __builtins__[name])
+
+
+
 def render_blocks(blocks, md):
     rendered = []
     for section in blocks:



More information about the Zope3-Checkins mailing list