[Zope-Checkins] SVN: Zope/branches/2.12/ LP #246983: Unicode conflict resolution on variables inside 'string:' expressions

Leonardo Rochael Almeida leorochael at gmail.com
Tue Jan 5 20:31:21 EST 2010


Log message for revision 107725:
  LP #246983: Unicode conflict resolution on variables inside 'string:' expressions

Changed:
  U   Zope/branches/2.12/doc/CHANGES.rst
  U   Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py
  U   Zope/branches/2.12/src/Products/PageTemplates/Expressions.py
  U   Zope/branches/2.12/src/Products/PageTemplates/tests/testExpressions.py
  U   Zope/branches/2.12/src/Products/PageTemplates/tests/testZopePageTemplate.py

-=-
Modified: Zope/branches/2.12/doc/CHANGES.rst
===================================================================
--- Zope/branches/2.12/doc/CHANGES.rst	2010-01-05 22:37:00 UTC (rev 107724)
+++ Zope/branches/2.12/doc/CHANGES.rst	2010-01-06 01:31:21 UTC (rev 107725)
@@ -11,6 +11,9 @@
 Bugs Fixed
 ++++++++++
 
+- LP #246983: Enabled unicode conflict resolution on variables inside "string:"
+  expressions in TALES.
+
 - Fixed possible TypeError while sending multipart emails.
 
 - Also look for ZEXP imports within the clienthome directory. This

Modified: Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py
===================================================================
--- Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py	2010-01-05 22:37:00 UTC (rev 107724)
+++ Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py	2010-01-06 01:31:21 UTC (rev 107725)
@@ -37,13 +37,13 @@
         from zope.tales.expressions import DeferExpr
         from zope.tales.expressions import NotExpr
         from zope.tales.expressions import PathExpr
-        from zope.tales.expressions import StringExpr
         from zope.tales.expressions import Undefs
         from zope.tales.pythonexpr import PythonExpr
         from zope.contentprovider.tales import TALESProviderExpression
         from Products.PageTemplates.DeferExpr import LazyExpr
         from Products.PageTemplates.Expressions import TrustedZopePathExpr
         from Products.PageTemplates.Expressions import SecureModuleImporter
+        from Products.PageTemplates.Expressions import UnicodeAwareStringExpr
 
         vptf = self._makeOne('seagull.pt')
         engine = vptf.pt_getEngine()
@@ -51,7 +51,7 @@
         self.assertEqual(engine.types['path'], TrustedZopePathExpr)
         self.assertEqual(engine.types['exists'], TrustedZopePathExpr)
         self.assertEqual(engine.types['nocall'], TrustedZopePathExpr)
-        self.assertEqual(engine.types['string'], StringExpr)
+        self.assertEqual(engine.types['string'], UnicodeAwareStringExpr)
         self.assertEqual(engine.types['python'], PythonExpr)
         self.assertEqual(engine.types['not'], NotExpr)
         self.assertEqual(engine.types['defer'], DeferExpr)

Modified: Zope/branches/2.12/src/Products/PageTemplates/Expressions.py
===================================================================
--- Zope/branches/2.12/src/Products/PageTemplates/Expressions.py	2010-01-05 22:37:00 UTC (rev 107724)
+++ Zope/branches/2.12/src/Products/PageTemplates/Expressions.py	2010-01-06 01:31:21 UTC (rev 107725)
@@ -372,12 +372,26 @@
             return False
         return ob1 == ob2
 
+class UnicodeAwareStringExpr(StringExpr):
+
+    def __call__(self, econtext):
+        vvals = []
+        if isinstance(self._expr, unicode):
+            # coerce values through the Unicode Conflict Resolver
+            evaluate = econtext.evaluateText
+        else:
+            evaluate = econtext.evaluate
+        for var in self._vars:
+            v = evaluate(var)
+            vvals.append(v)
+        return self._expr % tuple(vvals)
+
 def createZopeEngine(zpe=ZopePathExpr):
     e = ZopeEngine()
     e.iteratorFactory = PathIterator
     for pt in zpe._default_type_names:
         e.registerType(pt, zpe)
-    e.registerType('string', StringExpr)
+    e.registerType('string', UnicodeAwareStringExpr)
     e.registerType('python', ZRPythonExpr.PythonExpr)
     e.registerType('not', NotExpr)
     e.registerType('defer', DeferExpr)

Modified: Zope/branches/2.12/src/Products/PageTemplates/tests/testExpressions.py
===================================================================
--- Zope/branches/2.12/src/Products/PageTemplates/tests/testExpressions.py	2010-01-05 22:37:00 UTC (rev 107724)
+++ Zope/branches/2.12/src/Products/PageTemplates/tests/testExpressions.py	2010-01-06 01:31:21 UTC (rev 107725)
@@ -25,12 +25,20 @@
             __allow_access_to_unprotected_subobjects__ = 1
             def __call__(self):
                 return 'dummy'
+            
+            management_page_charset = 'iso-8859-15'
 
         class DummyDocumentTemplate:
             __allow_access_to_unprotected_subobjects__ = 1
             isDocTemp = True
             def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw):
                 return 'dummy'
+            
+            def absolute_url(self, relative=0):
+                url = 'dummy'
+                if not relative:
+                    url = "http://server/" + url
+                return url
 
         _DEFAULT_BINDINGS = dict(
             one = 1,
@@ -38,6 +46,12 @@
             blank = '',
             dummy = Dummy(),
             dummy2 = DummyDocumentTemplate(),
+            eightbit = 'äüö',
+            # ZopeContext needs 'context' and 'template' keys for unicode
+            # conflict resolution, and 'context' needs a 
+            # 'management_page_charset'
+            context = Dummy(),
+            template = DummyDocumentTemplate(),
             )
 
         if bindings is None:
@@ -158,6 +172,34 @@
         ec = self._makeContext()
         self.assertEquals(ec.evaluate('  \n'), None)
 
+    def test_unicode(self):
+        # All our string expressions are unicode now
+        eng = self._makeEngine()
+        ec = self._makeContext()
+        # XXX: can't do ec.evaluate(u'string:x') directly because ZopeContext
+        # only bothers compiling true strings, not unicode strings
+        result = ec.evaluate(eng.compile(u'string:x'))
+        self.assertEqual(result, u'x')
+        self.failUnless(isinstance(result, unicode))
+
+    def test_mixed(self):
+        # 8-bit strings in unicode string expressions cause UnicodeDecodeErrors
+        eng = self._makeEngine()
+        ec = self._makeContext()
+        expr = eng.compile(u'string:$eightbit')
+        self.assertRaises(UnicodeDecodeError,
+                          ec.evaluate, expr)
+        # But registering an appropriate IUnicodeEncodingConflictResolver
+        # should fix it
+        from zope.component import provideUtility
+        from Products.PageTemplates.unicodeconflictresolver \
+            import StrictUnicodeEncodingConflictResolver
+        from Products.PageTemplates.interfaces \
+            import IUnicodeEncodingConflictResolver
+        provideUtility(StrictUnicodeEncodingConflictResolver, 
+                                      IUnicodeEncodingConflictResolver)        
+        self.assertEqual(ec.evaluate(expr), u'äüö')
+
 class UntrustedEngineTests(EngineTestsBase, unittest.TestCase):
 
     def _makeEngine(self):

Modified: Zope/branches/2.12/src/Products/PageTemplates/tests/testZopePageTemplate.py
===================================================================
--- Zope/branches/2.12/src/Products/PageTemplates/tests/testZopePageTemplate.py	2010-01-05 22:37:00 UTC (rev 107724)
+++ Zope/branches/2.12/src/Products/PageTemplates/tests/testZopePageTemplate.py	2010-01-06 01:31:21 UTC (rev 107725)
@@ -202,6 +202,26 @@
         state = cPickle.dumps(empty, protocol=1)
         clone = cPickle.loads(state)
 
+    def testBug246983(self):
+        # See https://bugs.launchpad.net/bugs/246983
+        self.app.REQUEST.set('HTTP_ACCEPT_CHARSET', 'utf-8')
+        self.app.REQUEST.set('data', u'üöä'.encode('utf-8'))
+        # Direct inclusion of encoded strings is hadled normally by the unicode
+        # conflict resolver
+        textDirect = """
+        <tal:block content="request/data" />
+        """.strip()
+        manage_addPageTemplate(self.app, 'test', text=textDirect)
+        zpt = self.app['test']
+        self.assertEquals(zpt.pt_render(), u'üöä')
+        # Indirect inclusion of encoded strings through String Expressions
+        # should be resolved as well.
+        textIndirect = """
+        <tal:block content="string:x ${request/data}" />
+        """.strip()
+        zpt.pt_edit(textIndirect, zpt.content_type)
+        self.assertEquals(zpt.pt_render(), u'x üöä')
+
     def testDebugFlags(self):
         # Test for bug 229549
         manage_addPageTemplate(self.app, 'test', 



More information about the Zope-Checkins mailing list