[Zope-Checkins] CVS: Zope3/lib/python/Zope/PageTemplate - PythonExpr.py:1.1.2.6

Shane Hathaway shane@cvs.zope.org
Wed, 13 Mar 2002 23:01:28 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/PageTemplate
In directory cvs.zope.org:/tmp/cvs-serv11927

Modified Files:
      Tag: Zope-3x-branch
	PythonExpr.py 
Log Message:
- Simplified a lot.  There's no reason we can't just use Python's compile()
  builtin.

- Renamed the attribute "expr" to "text", which more clearly expresses what
  you'd expect to put in it.


=== Zope3/lib/python/Zope/PageTemplate/PythonExpr.py 1.1.2.5 => 1.1.2.6 ===
 __version__ = '$Revision$'[11:-2]
 
-from TALES import CompilerError
-from sys import exc_info
-
-class NullSecurityManager:
-    '''Null security manager'''
-    def __init__(self):
-        self._stack = []
-    def validate(self, name, value):
-        pass
-    def validateValue(self, value):
-        pass
-    def pushExecutable(self, context):
-        self._stack.append(context)
-    def popExecutable(self):
-        self._stack.pop()
-
-def getSecurityManager(null_manager=NullSecurityManager()):
-    return null_manager
+_marker = object()
 
 
 class PythonExpr:
     def __init__(self, name, expr, engine):
-        self.expr = expr = expr.strip().replace('\n', ' ')
-        try:
-            d = {}
-            exec 'def f():\n return %s\n' % expr.strip() in d
-            self._f = d['f']
-        except:
-            raise CompilerError, ('Python expression error:\n'
-                                  '%s: %s') % exc_info()[:2]
+        text = expr.replace('\n', ' ').strip()
+        self.text = text
+        # The next line can legally raise SyntaxError.
+        self._code = compile(text, '<string>', 'eval')
         self._get_used_names()
 
     def _get_used_names(self):
-        self._f_varnames = vnames = []
-        for vname in self._f.func_code.co_names:
+        vnames = []
+        for vname in self._code.co_names:
             if vname[0] not in '$_':
                 vnames.append(vname)
+        self._varnames = vnames
 
     def _bind_used_names(self, econtext):
         # Bind template variables
         names = {}
         vars = econtext.vars
         getType = econtext._engine.getTypes().get
-        for vname in self._f_varnames:
-            has, val = vars.has_get(vname)
-            if not has:
-                has = val = getType(vname)
-                if has:
-                    val = ExprTypeProxy(vname, val, econtext)
-            if has:
+        marker = _marker
+        for vname in self._varnames:
+            val = vars.get(vname, marker)
+            if val is not marker:
                 names[vname] = val
+            else:
+                # Fall back to using expression types as variable values.
+                val = getType(vname)
+                if val is not None:
+                    val = ExprTypeProxy(vname, val, econtext)
+                    names[vname] = val
         return names
 
     def __call__(self, econtext):
-        __traceback_info__ = self.expr
-        f = self._f
-        f.func_globals.update(self._bind_used_names(econtext))        
-        return f()
+        __traceback_info__ = self.text
+        vars = self._bind_used_names(econtext)
+        return eval(self._code, vars)
 
     def __str__(self):
-        return 'Python expression "%s"' % self.expr
+        return 'Python expression "%s"' % self.text
+
     def __repr__(self):
-        return '<PythonExpr %s>' % self.expr
+        return '<PythonExpr %s>' % self.text
+
 
 class ExprTypeProxy:
     '''Class that proxies access to an expression type handler'''
@@ -81,7 +65,7 @@
         self._name = name
         self._handler = handler
         self._econtext = econtext
+
     def __call__(self, text):
         return self._handler(self._name, text,
                              self._econtext._engine)(self._econtext)
-