[ZPT] CVS: Products/PageTemplates - Expressions.py:1.21 PageTemplate.py:1.15 PageTemplateFile.py:1.4 TALES.py:1.22 ZopePageTemplate.py:1.19

Evan Simpson evan@zope.com
Thu, 11 Oct 2001 13:07:28 -0400


Update of /cvs-repository/Products/PageTemplates
In directory cvs.zope.org:/tmp/cvs-serv25400

Modified Files:
	Expressions.py PageTemplate.py PageTemplateFile.py TALES.py 
	ZopePageTemplate.py 
Log Message:
Improve error reporting.


=== Products/PageTemplates/Expressions.py 1.20 => 1.21 ===
     reg('python', PythonExpr)
     reg('not', NotExpr)
+    reg('defer', DeferExpr)
 
 if sys.modules.has_key('Zope'):
     import AccessControl
@@ -194,10 +195,14 @@
                     ob = econtext.contexts
                 else:
                     ob = vars[base]
+                if isinstance(ob, DeferWrapper):
+                    ob = ob()
                 if path:
                     ob = restrictedTraverse(ob, path, securityManager)
                 exists = 1
                 break
+            except Undefined, e:
+                ob = e
             except (AttributeError, KeyError, TypeError, IndexError,
                     'Unauthorized'), e:
                 ob = Undefined(self._s, sys.exc_info())
@@ -214,10 +219,10 @@
         return self._eval(econtext, getSecurityManager())
 
     def __str__(self):
-        return '%s expression "%s"' % (self._name, self._s)
+        return '%s expression %s' % (self._name, `self._s`)
 
     def __repr__(self):
-        return '<PathExpr %s:%s>' % (self._name, self._s)
+        return '%s:%s' % (self._name, `self._s`)
 
             
 _interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/%(n)s)*)}' % {'n': NAME_RE})
@@ -242,8 +247,7 @@
                     m = _interp.search(exp)
                 if '$' in exp:
                     raise CompilerError, (
-                        '$ must be doubled or followed by a variable name '
-                        'in string expression "%s"' % expr)
+                        '$ must be doubled or followed by a simple path')
                 parts.append(exp)
             expr = join(parts, '')
         self._expr = expr
@@ -261,7 +265,7 @@
         return 'string expression %s' % `self._s`
 
     def __repr__(self):
-        return '<StringExpr %s>' % `self._s`
+        return 'string:%s' % `self._s`
 
 class NotExpr:
     def __init__(self, name, expr, compiler):
@@ -272,7 +276,29 @@
         return not econtext.evaluateBoolean(self._c)
 
     def __repr__(self):
-        return '<NotExpr %s>' % `self._s`
+        return 'not:%s' % `self._s`
+
+class DeferWrapper:
+    def __init__(self, expr, econtext):
+        self._expr = expr
+        self._econtext = econtext
+
+    def __str__(self):
+        return str(self())
+
+    def __call__(self):
+        return self._expr(self._econtext)
+
+class DeferExpr:
+    def __init__(self, name, expr, compiler):
+        self._s = expr = lstrip(expr)
+        self._c = compiler.compile(expr)
+        
+    def __call__(self, econtext):
+        return DeferWrapper(self._c, econtext)
+
+    def __repr__(self):
+        return 'defer:%s' % `self._s`
 
 
 def restrictedTraverse(self, path, securityManager,


=== Products/PageTemplates/PageTemplate.py 1.14 => 1.15 ===
     expand = 1
     _v_errors = ()
+    _v_warnings = ()
     _text = ''
     _error_start = '<!-- Page Template Diagnostics'
 
@@ -162,7 +163,16 @@
         return self.pt_render(extra_context={'options': kwargs})
 
     def pt_errors(self):
-        return self._v_errors
+        err = self._v_errors
+        if err:
+            return err
+        try:
+            self.pt_render(source=1)
+        except:
+            return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2])
+        
+    def pt_warnings(self):
+        return self._v_warnings
 
     def write(self, text):
         assert type(text) is type('')
@@ -209,6 +219,7 @@
         except:
             self._v_errors = ["Compilation failed",
                               "%s: %s" % sys.exc_info()[:2]]
+        self._v_warnings = parser.getWarnings()
 
     def html(self):
         return self.content_type == 'text/html'


=== Products/PageTemplates/PageTemplateFile.py 1.3 => 1.4 ===
         # Execute the template in a new security context.
         security=getSecurityManager()
+        bound_names['user'] = security.getUser()
         security.addContext(self)
         try:
             return self.pt_render(extra_context=bound_names)


=== Products/PageTemplates/TALES.py 1.21 => 1.22 ===
 class TALESError(Exception):
     __allow_access_to_unprotected_subobjects__ = 1
-    def __init__(self, expression, info=(None, None, None)):
+    def __init__(self, expression, info=(None, None, None),
+                 position=(None, None)):
         self.type, self.value, self.traceback = info
         self.expression = expression
+        self.setPosition(position)
+    def setPosition(self, position):
+        self.lineno = position[0]
+        self.offset = position[1]        
     def __str__(self):
-        if self.type is not None:
-            return '%s on %s in "%s"' % (self.type, self.value,
-                                         self.expression)
-        return self.expression
+        if self.type is None:
+            s = self.expression
+        else:
+            s = '%s on %s in %s' % (self.type, self.value,
+                                    `self.expression`)
+        if self.lineno is not None:
+            s = "%s, at line %d" % (s, self.lineno)
+        if self.offset is not None:
+            s = "%s, column %d" % (s, self.offset + 1)
+        return s
     def __nonzero__(self):
         return 0
 
 class Undefined(TALESError):
     '''Exception raised on traversal of an undefined path'''
     def __str__(self):
-        if self.type is not None:
-            return '"%s" not found in "%s"' % (self.value,
-                                               self.expression)
-        return self.expression
+        if self.type is None:
+            s = self.expression
+        else:
+            s = '%s not found in %s' % (self.value,
+                                        `self.expression`)
+        if self.lineno is not None:
+            s = "%s, at line %d" % (s, self.lineno)
+        if self.offset is not None:
+            s = "%s, column %d" % (s, self.offset + 1)
+        return s
 
 class RegistrationError(Exception):
     '''TALES Type Registration Error'''
@@ -221,6 +238,8 @@
                 kwcontexts = contexts
         return Context(self, kwcontexts)
 
+    def getCompilerError(self):
+        return CompilerError
 
 class Context:
     '''Expression Context
@@ -231,6 +250,7 @@
 
     _context_class = SafeMapping
     _nocatch = TALESError
+    position = (None, None)
 
     def __init__(self, engine, contexts):
         self._engine = engine
@@ -297,10 +317,14 @@
                 if hasattr(v, 'traceback'):
                     raise v, None, v.traceback
                 raise v
+        except TALESError, err:
+            err.setPosition(self.position)
+            raise err, None, sys.exc_info()[2]
         except self._nocatch:
             raise
         except:
-            raise TALESError, (`expression`, sys.exc_info()), sys.exc_info()[2]
+            raise TALESError, (`expression`, sys.exc_info(),
+                               self.position), sys.exc_info()[2]
         else:
             return v
 
@@ -329,6 +353,9 @@
 
     def getDefault(self):
         return Default
+
+    def setPosition(self, position):
+        self.position = position
 
 class SimpleExpr:
     '''Simple example of an expression type handler'''


=== Products/PageTemplates/ZopePageTemplate.py 1.18 => 1.19 ===
       'pt_editForm', 'manage_main', 'read',
       'ZScriptHTML_tryForm', 'PrincipiaSearchSource',
-      'document_src')
+      'document_src', 'source.html', 'source.xml')
 
     security.declareProtected('Change Page Templates',
       'pt_editAction', 'pt_setTitle', 'pt_edit',
@@ -310,6 +310,8 @@
 
         if RESPONSE is not None:
             RESPONSE.setHeader('Content-Type', self.content_type)
+        if REQUEST.get('raw'):
+            return self._text
         return self.read()
 
     def __setstate__(self, state):