Log message for revision 39550:
  Collector #1927:  Don't save rendered HTML / warnings as persistent 
attributes.

Changed:
  U   Zope/branches/Zope-2_8-branch/doc/CHANGES.txt
  U   Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/ZReST.py
  A   Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/
  A   Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/__init__.py
  A   
Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/test_ZReST.py

-=-
Modified: Zope/branches/Zope-2_8-branch/doc/CHANGES.txt
===================================================================
--- Zope/branches/Zope-2_8-branch/doc/CHANGES.txt       2005-10-21 13:31:50 UTC 
(rev 39549)
+++ Zope/branches/Zope-2_8-branch/doc/CHANGES.txt       2005-10-21 17:30:25 UTC 
(rev 39550)
@@ -26,6 +26,10 @@
 
     Bugs Fixed
 
+      - Collector #1927:  Modified ZReST not to store rendered / warnings
+        as persistent attributes, using volatile attributes instead as
+        a cache.
+
       - Collector #1926: fixed a typo in _doAddUser when password
         encryption is enabled.
 

Modified: Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/ZReST.py
===================================================================
--- Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/ZReST.py    
2005-10-21 13:31:50 UTC (rev 39549)
+++ Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/ZReST.py    
2005-10-21 17:30:25 UTC (rev 39550)
@@ -47,6 +47,7 @@
     '''
     meta_type =  'ReStructuredText Document'
     security = ClassSecurityInfo()
+    _v_formatted = _v_warnings = None
 
     def __init__(self, id,output_encoding=None,
                  input_encoding=None):
@@ -54,7 +55,7 @@
         self.title = id
         self.stylesheet = 'default.css'
         self.report_level = '2'
-        self.source = self.formatted = ''
+        self.source = ''
 
         from reStructuredText import default_output_encoding, \
                                      default_input_encoding
@@ -89,7 +90,7 @@
         '''
         if REQUEST is not None:
             REQUEST.RESPONSE.setHeader('content-type', 'text/html; charset=%s' 
% self.output_encoding)
-        return self.formatted
+        return self.render()
 
     security.declareProtected('View', 'source_txt')
     def source_txt(self, REQUEST=None):
@@ -113,7 +114,7 @@
             return self._er(data, SUBMIT, dtpref_cols, dtpref_rows, REQUEST)
         if data != self.source:
             self.source = data
-            self.render()
+            self._clear_cache()
 
         if REQUEST is not None:
             message="Saved changes."
@@ -142,6 +143,7 @@
         setCookie("dtpref_cols", cols, path='/', expires=e)
         REQUEST.other.update({"dtpref_cols":cols, "dtpref_rows":rows})
         return self.manage_main(self, REQUEST, __str__=self.quotedHTML(data))
+
     security.declarePrivate('quotedHTML')
     def quotedHTML(self,
                    text=None,
@@ -155,6 +157,18 @@
             if text.find(re) >= 0: text=name.join(text.split(re))
         return text
 
+    security.declarePrivate('_clear_cache')
+    def _clear_cache(self):
+        """ Forget results of rendering.
+        """
+        try:
+            del self._v_formatted
+        except AttributeError:
+            pass
+        try:
+            del self._v_warnings
+        except AttributeError:
+            pass
 
     # handle uploads too
     security.declareProtected('Edit ReStructuredText', 'manage_upload')
@@ -165,7 +179,7 @@
             self.source = file
         else:
             self.source = file.read()
-        self.render()
+        self._clear_cache()
 
         if REQUEST is not None:
             message="Saved changes."
@@ -175,57 +189,60 @@
     def render(self):
         ''' Render the source to HTML
         '''
-        # format with strings
-        pub = docutils.core.Publisher()
-        pub.set_reader('standalone', None, 'restructuredtext')
-        pub.set_writer('html')
+        if self._v_formatted is None:
+            # format with strings
+            pub = docutils.core.Publisher()
+            pub.set_reader('standalone', None, 'restructuredtext')
+            pub.set_writer('html')
 
-        # go with the defaults
-        pub.get_settings()
+            # go with the defaults
+            pub.get_settings()
 
-        # this is needed, but doesn't seem to do anything
-        pub.settings._destination = ''
+            # this is needed, but doesn't seem to do anything
+            pub.settings._destination = ''
 
-        # use the stylesheet chosen by the user
-        pub.settings.stylesheet = self.stylesheet
+            # use the stylesheet chosen by the user
+            pub.settings.stylesheet = self.stylesheet
 
-        # set the reporting level to something sane
-        pub.settings.report_level = int(self.report_level)
+            # set the reporting level to something sane
+            pub.settings.report_level = int(self.report_level)
 
-        # disallow use of the .. include directive for security reasons
-        pub.settings.file_insertion_enabled = 0
+            # disallow use of the .. include directive for security reasons
+            pub.settings.file_insertion_enabled = 0
 
-        # don't break if we get errors
-        pub.settings.halt_level = 6
+            # don't break if we get errors
+            pub.settings.halt_level = 6
 
-        # remember warnings
-        pub.settings.warning_stream = Warnings()
+            # remember warnings
+            pub.settings.warning_stream = Warnings()
 
-        pub.source = docutils.io.StringInput(
-            source=self.source, encoding=self.input_encoding)
+            pub.source = docutils.io.StringInput(
+                source=self.source, encoding=self.input_encoding)
 
-        # output - not that it's needed
-        pub.settings.output_encoding = self.output_encoding
-        pub.destination = docutils.io.StringOutput(
-            encoding=self.output_encoding)
+            # output - not that it's needed
+            pub.settings.output_encoding = self.output_encoding
+            pub.destination = docutils.io.StringOutput(
+                encoding=self.output_encoding)
 
-        # parse!
-        document = pub.reader.read(pub.source, pub.parser, pub.settings)
+            # parse!
+            document = pub.reader.read(pub.source, pub.parser, pub.settings)
 
-        # transform
-        pub.apply_transforms(document)
+            # transform
+            pub.apply_transforms(document)
 
-        self.warnings = ''.join(pub.settings.warning_stream.messages)
+            self._v_warnings = ''.join(pub.settings.warning_stream.messages)
 
-        if document.children:
-            item = document.children[0]
-            if item.tagname == 'title':
-                self.title = item.children[0].astext()
+            if document.children:
+                item = document.children[0]
+                if item.tagname == 'title':
+                    self.title = item.children[0].astext()
 
-        # do the format
-        self.formatted = pub.writer.write(document, pub.destination)
+            # do the format
+            self._v_formatted = pub.writer.write(document, pub.destination)
 
+        return self._v_formatted
 
+
     security.declareProtected('Edit ReStructuredText', 'PUT', 'manage_FTPput')
     def PUT(self, REQUEST, RESPONSE):
         ''' Handle HTTP PUT requests
@@ -247,7 +264,6 @@
                         pass # ignore
                 data = '\n'.join(new) + '\n'.join(data[i:])
             self.source = data
-            self.render()
         RESPONSE.setStatus(204)
         return RESPONSE        
 
@@ -263,9 +279,9 @@
             '.. stylesheet='+self.stylesheet,
             '.. report_level='+self.report_level
         ]
-        if self.warnings:
+        if self._v_warnings:
             s.append('.. ')
-            s.append('.. ' + '\n.. '.join(self.warnings.splitlines()))
+            s.append('.. ' + '\n.. '.join(self._v_warnings.splitlines()))
         s.append('.. ')
         return '\n'.join(s) + '\n' + self.source
 
@@ -290,7 +306,7 @@
     def manage_editProperties(self, REQUEST):
         """ re-render the page after changing the properties (encodings!!!) """
         result = PropertyManager.manage_editProperties(self, REQUEST)        
-        self.render()
+        self._clear_cache()
         return result
 
 

Added: Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/__init__.py
===================================================================
--- Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/__init__.py   
2005-10-21 13:31:50 UTC (rev 39549)
+++ Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/__init__.py   
2005-10-21 17:30:25 UTC (rev 39550)
@@ -0,0 +1,4 @@
+""" Unit tests for ZReST product.
+
+$Id$
+"""


Property changes on: 
Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: 
Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/test_ZReST.py
===================================================================
--- Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/test_ZReST.py 
2005-10-21 13:31:50 UTC (rev 39549)
+++ Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/test_ZReST.py 
2005-10-21 17:30:25 UTC (rev 39550)
@@ -0,0 +1,38 @@
+""" Unit tests for ZReST objects
+
+$Id$
+"""
+import unittest
+
+class TestZReST(unittest.TestCase):
+
+    def _getTargetClass(self):
+        from Products.ZReST.ZReST import ZReST
+        return ZReST
+
+    def _makeOne(self, id='test', *args, **kw):
+        return self._getTargetClass()(id=id, *args, **kw)
+
+    def test_empty(self):
+        empty = self._makeOne()
+
+        # New instances should not have non-volatile cache attributes
+        self.assertRaises(AttributeError, lambda: empty.formatted)
+        self.assertRaises(AttributeError, lambda: empty.warnings)
+
+        self.assertEqual(empty._v_formatted, None)
+        self.assertEqual(empty._v_formatted, None)
+
+    def test_formatted_ignored(self):
+        resty = self._makeOne()
+        resty.formatted = 'IGNORE ME'
+
+        self.failIf('IGNORE ME' in resty.index_html())
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestZReST))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultSuite='test_suite')


Property changes on: 
Zope/branches/Zope-2_8-branch/lib/python/Products/ZReST/tests/test_ZReST.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

_______________________________________________
Zope-Checkins maillist  -  Zope-Checkins@zope.org
http://mail.zope.org/mailman/listinfo/zope-checkins

Reply via email to