[Checkins] SVN: z3c.blobfile/trunk/src/z3c/blobfile/ Changed the evolution strategy since the first naive attempt didn't work.

Uwe Oestermeier u.oestermeier at iwm-kmrc.de
Thu Nov 15 05:04:18 EST 2007


Log message for revision 81850:
  Changed the evolution strategy since the first naive attempt didn't work.

Changed:
  U   z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt
  U   z3c.blobfile/trunk/src/z3c/blobfile/file.py
  U   z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py
  U   z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py
  U   z3c.blobfile/trunk/src/z3c/blobfile/testing.py

-=-
Modified: z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt	2007-11-15 09:57:36 UTC (rev 81849)
+++ z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt	2007-11-15 10:04:17 UTC (rev 81850)
@@ -23,15 +23,11 @@
     
 Note that we cannot assume that these objects exist in isolation. Many of
 them probably are annotated, indexed, some even may be registered as utility
-etc.
+etc. The evolution step throws the standard events when the objects
+are replaced and it's up the application that this replacement is recognized
+accordingly. If your application has special needs you may subscribe to the
+FileReplacedEvent.
 
-Therefore we need a very conservative evolution strategy. We simply replace
-the __class__ attribute and the data section. 
-
-IMPORTANT: If your application needs to be aware of the hidden type change, 
-you must provide your own evolution procedure.
-
-
 We will not test all relations to all other objects, since this is largely 
 application dependent. Here we only take the ZopeDublinCore timestamps as 
 an example that our evolution step leaves as many things untouched as possible. 
@@ -52,11 +48,12 @@
     
     >>> from z3c.blobfile.generations.evolve1 import evolveZopeAppFile
     >>> evolveZopeAppFile(root)
-    
+    >>> transaction.commit()
+        
     >>> for record in log_handler.records:
     ...     print record.getMessage()
     Unknown ...interfaces.IFile implementation z3c.blobfile.testing.MyFile
-  
+
 After the evolution step the class types have changed to the z3c.blobfile
 implementations:
 
@@ -93,35 +90,7 @@
     >>> root[u'file']._data
     'A text file'
     
-    
-Adding Blob Files
------------------
 
-    >>> from zope.testbrowser.testing import Browser
-    >>> browser = Browser()
-    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-    >>> dn = 'z3c.blobfile.file.File'
-    >>> browser.open('http://localhost/@@+/action.html?type_name=' + dn)
-    
-    >>> ctrl = browser.getControl('Data')
-    >>> ctrl
-    <Control name='field.data' type='file'>
-
-    >>> import cStringIO
-
-    >>> ctrl.add_file(cStringIO.StringIO('File contents'),
-    ...               'text/plain', 'test.txt')
-
-    >>> browser.getControl('Add').click()
-    >>> 'test.txt' in browser.contents
-    True
-    
-    >>> fp = root['test.txt'].open('r')
-    >>> fp.read()
-    'File contents'
-    >>> fp.close()
-    
-
 Compatibility with zope.app.file.File
 -------------------------------------
 

Modified: z3c.blobfile/trunk/src/z3c/blobfile/file.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/file.py	2007-11-15 09:57:36 UTC (rev 81849)
+++ z3c.blobfile/trunk/src/z3c/blobfile/file.py	2007-11-15 10:04:17 UTC (rev 81850)
@@ -18,6 +18,7 @@
 import transaction
 from zope.interface import implements
 import zope.component
+import zope.component.interfaces
 import zope.app.publication.interfaces
 import zope.app.file.interfaces
 
@@ -92,3 +93,12 @@
 
     def write(self, data):
         self.context._setData(data)
+
+class FileReplacedEvent(zope.component.interfaces.ObjectEvent):
+    """Notifies about the replacement of a zope.app.file with a z3c.blobfile."""
+    
+    def __init__(self, object, blobfile):
+        super(FileReplacedEvent, self).__init__(object)
+        self.blobfile = blobfile
+
+    
\ No newline at end of file

Modified: z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py	2007-11-15 09:57:36 UTC (rev 81849)
+++ z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py	2007-11-15 10:04:17 UTC (rev 81850)
@@ -14,48 +14,39 @@
 import z3c.blobfile.image
 
 
-def changeImplementation(file, klass):
-    file._blob = Blob()
-    _data = file.__dict__['_data']
-    del file.__dict__['_data']
-    file.__class__ = klass
-    fp = file.open('w')
-    if isinstance(_data, zope.app.file.file.FileChunk):
-        fp.write(_data._data)
-        del _data._data
-        _data = _data.next
-    else:
-        fp.write(_data)
-    del _data
-    fp.close()
-            
+def replace(file, klass):
+    """Replaces a file with it's blob counterpart."""
+    blobfile = klass(file._data)
+    blobfile.contentType = file.contentType
+    container = file.__parent__
+    name = file.__name__
     
-def evolveZopeAppFile(root):
-    """Replaces the classes and data of zope.app.file objects.
+    if hasattr(file, '__annotations__'):
+        blobfile.__annotations__ = file.__annotations__
+        
+    del container[name]
+    container[name] = blobfile
     
-    Leaves annotations, key references, int id etc. intact.
-    Doesn't throw an ObjectModify event.
-    """
-    for file in findObjectsProviding(root, IFile):
+    zope.event.notify(
+        z3c.blobfile.file.FileReplacedEvent(file, blobfile))
     
+def evolveZopeAppFile(root):
+    """Evolves all files in the containment hierarchy."""
+    for file in findObjectsProviding(root, IFile):
         if isinstance(file, zope.app.file.Image):
-            changeImplementation(file, z3c.blobfile.image.Image)
+            replace(file, z3c.blobfile.image.Image)
         elif isinstance(file, zope.app.file.File):
-            changeImplementation(file, z3c.blobfile.file.File)
+            replace(file, z3c.blobfile.file.File)
             
         else:
             logging.getLogger('z3c.blobfile.generations').warn(
             'Unknown zope.app.file.interfaces.IFile implementation %s.%s' % (
                 file.__class__.__module__,
                 file.__class__.__name__))
-         
+        file._p_changed = 1 # trigger persistence  
         transaction.savepoint(optimistic=True)
         
 def evolve(context):
-    """
-    Replaces all zope.app.file content objects with z3c.blobfile counterparts.
-    """
-
+    """Replaces all zope.app.file objects with z3c.blobfile counterparts."""
     root = getRootFolder(context)
-
     evolveZopeAppFile(root)

Modified: z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py	2007-11-15 09:57:36 UTC (rev 81849)
+++ z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py	2007-11-15 10:04:17 UTC (rev 81850)
@@ -18,7 +18,7 @@
 __docformat__ = 'restructuredtext'
 
 import zope.interface
-
+import zope.component.interfaces
 import zope.app.file.interfaces
 
 class IOpenable(zope.interface.Interface):
@@ -51,3 +51,5 @@
     """Data is not storable
     """
 
+class IFileReplacedEvent(zope.component.interfaces.IObjectEvent):
+    """A zope.app.file has been replaced by it's blobfile counterpart."""

Modified: z3c.blobfile/trunk/src/z3c/blobfile/testing.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/testing.py	2007-11-15 09:57:36 UTC (rev 81849)
+++ z3c.blobfile/trunk/src/z3c/blobfile/testing.py	2007-11-15 10:04:17 UTC (rev 81850)
@@ -91,6 +91,18 @@
             shutil.rmtree(self.temp_dir_name, True)
             self.temp_dir_name = None
         setSite(None)
+        
+    def closeDB(self):
+        if self.connection:
+            self.connection.close()
+            self.connection = None
+        self.db.close()
+        
+    def reopenDB(self):
+        storage = BlobStorage(temp_dir_name, storage)
+        self.db = self.app.db = DB(storage)
+        self.connection = None
+        
 
 
 class ZCMLLayer(zope.app.testing.functional.ZCMLLayer):
@@ -98,12 +110,6 @@
     def setUp(self):
         self.setup = FunctionalBlobTestSetup(self.config_file)
 
-
-class ZCMLLayer(zope.app.testing.functional.ZCMLLayer):
-
-    def setUp(self):
-        self.setup = FunctionalBlobTestSetup(self.config_file)
-
 def FunctionalBlobDocFileSuite(*paths, **kw):
     globs = kw.setdefault('globs', {})
     globs['http'] = zope.app.testing.functional.HTTPCaller()



More information about the Checkins mailing list