[Zope3-checkins] SVN: Zope3/branches/ZopeX3-3.0/ Merge revisions 26722, 26726 from trunk.

Fred L. Drake, Jr. fred at zope.com
Fri Jul 23 17:19:07 EDT 2004


Log message for revision 26728:
  Merge revisions 26722, 26726 from trunk.
  
  Fixed issue 248.  Path expressions in page templates that contain
  empty segments now cause an error to be raised when the expression is
  compiled rather than when it is evaluated.  This has always been
  illegal according to the specification, and most often caused a
  runtime error before.  Template authors can now get an error up front,
  avoiding embarrasment when once an application is moved into
  production after insufficient testing.
  


Changed:
  U   Zope3/branches/ZopeX3-3.0/doc/CHANGES.txt
  U   Zope3/branches/ZopeX3-3.0/src/zope/tales/expressions.py
  U   Zope3/branches/ZopeX3-3.0/src/zope/tales/tests/test_expressions.py


-=-
Modified: Zope3/branches/ZopeX3-3.0/doc/CHANGES.txt
===================================================================
--- Zope3/branches/ZopeX3-3.0/doc/CHANGES.txt	2004-07-23 21:13:09 UTC (rev 26727)
+++ Zope3/branches/ZopeX3-3.0/doc/CHANGES.txt	2004-07-23 21:19:07 UTC (rev 26728)
@@ -35,6 +35,15 @@
 
     Bug fixes
 
+      - Fixed issue 248.  Path expressions in page templates that
+        contain empty segments now cause an error to be raised when
+        the expression is compiled rather than when it is evaluated.
+        This has always been illegal according to the specification,
+        and most often caused a runtime error before.  Template
+        authors can now get an error up front, avoiding embarrasment
+        when once an application is moved into production after
+        insufficient testing.
+
       - Fixed the default 'text/*' content type for file objects.
         Backport of the fix for bug 201.
 

Modified: Zope3/branches/ZopeX3-3.0/src/zope/tales/expressions.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/tales/expressions.py	2004-07-23 21:13:09 UTC (rev 26727)
+++ Zope3/branches/ZopeX3-3.0/src/zope/tales/expressions.py	2004-07-23 21:19:07 UTC (rev 26728)
@@ -18,8 +18,7 @@
 import re
 
 from zope.interface import implements
-from zope.tales.tales import CompilerError
-from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined 
+from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined
 from zope.tales.interfaces import ITALESExpression, ITALESFunctionNamespace
 
 __metaclass__ = type
@@ -54,33 +53,36 @@
         compiledpath = []
         currentpath = []
         for element in str(path).strip().split('/'):
+            if not element:
+                raise engine.getCompilerError()(
+                    'Path element may not be empty in %r' % path)
             if element.startswith('?'):
                 if currentpath:
                     compiledpath.append(tuple(currentpath))
-                    currentpath=[]
+                    currentpath = []
                 if not _valid_name(element[1:]):
-                    raise CompilerError('Invalid variable name "%s"'
-                                        % element[1:])
+                    raise engine.getCompilerError()(
+                        'Invalid variable name "%s"' % element[1:])
                 compiledpath.append(element[1:])
             else:
                 match = namespace_re.match(element)
                 if match:
                     if currentpath:
                         compiledpath.append(tuple(currentpath))
-                        currentpath=[]
+                        currentpath = []
                     namespace, functionname = match.groups()
                     if not _valid_name(namespace):
-                        raise CompilerError('Invalid namespace name "%s"'
-                                            % namespace)
+                        raise engine.getCompilerError()(
+                            'Invalid namespace name "%s"' % namespace)
                     if not _valid_name(functionname):
-                        raise CompilerError('Invalid function name "%s"'
-                                            % functionname)
+                        raise engine.getCompilerError()(
+                            'Invalid function name "%s"' % functionname)
                     try:
                         compiledpath.append(
                             self._engine.getFunctionNamespace(namespace))
                     except KeyError:
-                        raise CompilerError('Unknown namespace "%s"'
-                                            % namespace)
+                        raise engine.getCompilerError()(
+                            'Unknown namespace "%s"' % namespace)
                     currentpath.append(functionname)
                 else:
                     currentpath.append(element)
@@ -93,21 +95,22 @@
 
         if callable(first):
             # check for initial function
-            raise CompilerError(
+            raise engine.getCompilerError()(
                 'Namespace function specified in first subpath element')
         elif isinstance(first, basestring):
             # check for initial ?
-            raise CompilerError(
+            raise engine.getCompilerError()(
                 'Dynamic name specified in first subpath element')
 
         if base and not _valid_name(base):
-            raise CompilerError, 'Invalid variable name "%s"' % element
+            raise engine.getCompilerError()(
+                'Invalid variable name "%s"' % element)
         self._base = base
-        compiledpath[0]=first[1:]
+        compiledpath[0] = first[1:]
         self._compiled_path = tuple(compiledpath)
 
     def _eval(self, econtext,
-              list=list, isinstance=isinstance):
+              isinstance=isinstance):
         vars = econtext.vars
 
         compiled_path = self._compiled_path
@@ -238,7 +241,7 @@
                     exp = exp[m.end():]
                     m = _interp.search(exp)
                 if '$' in exp:
-                    raise CompilerError, (
+                    raise engine.getCompilerError()(
                         '$ must be doubled or followed by a simple path')
                 parts.append(exp)
             expr = ''.join(parts)

Modified: Zope3/branches/ZopeX3-3.0/src/zope/tales/tests/test_expressions.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/tales/tests/test_expressions.py	2004-07-23 21:13:09 UTC (rev 26727)
+++ Zope3/branches/ZopeX3-3.0/src/zope/tales/tests/test_expressions.py	2004-07-23 21:19:07 UTC (rev 26728)
@@ -135,7 +135,37 @@
         self.assertRaises(self.engine.getCompilerError(),
                           self.engine.compile, 'python: splat.0')
 
+    def testEmptyPathSegmentRaisesCompilerError(self):
+        CompilerError = self.engine.getCompilerError()
+        def check(expr):
+            self.assertRaises(CompilerError, self.engine.compile, expr)
 
+        # path expressions on their own:
+        check('/ab/cd | c/d | e/f')
+        check('ab//cd | c/d | e/f')
+        check('ab/cd/ | c/d | e/f')
+        check('ab/cd | /c/d | e/f')
+        check('ab/cd | c//d | e/f')
+        check('ab/cd | c/d/ | e/f')
+        check('ab/cd | c/d | /e/f')
+        check('ab/cd | c/d | e//f')
+        check('ab/cd | c/d | e/f/')
+
+        # path expressions embedded in string: expressions:
+        check('string:${/ab/cd}')
+        check('string:${ab//cd}')
+        check('string:${ab/cd/}')
+        check('string:foo${/ab/cd | c/d | e/f}bar')
+        check('string:foo${ab//cd | c/d | e/f}bar')
+        check('string:foo${ab/cd/ | c/d | e/f}bar')
+        check('string:foo${ab/cd | /c/d | e/f}bar')
+        check('string:foo${ab/cd | c//d | e/f}bar')
+        check('string:foo${ab/cd | c/d/ | e/f}bar')
+        check('string:foo${ab/cd | c/d | /e/f}bar')
+        check('string:foo${ab/cd | c/d | e//f}bar')
+        check('string:foo${ab/cd | c/d | e/f/}bar')
+
+
 class FunctionTests(ExpressionTestBase):
 
     def setUp(self):



More information about the Zope3-Checkins mailing list