[Checkins] SVN: zope.file/trunk/src/zope/file/ merged ajung-blobs branch providing a file implementation supporting

Andreas Jung andreas at andreas-jung.com
Tue Feb 27 10:04:03 EST 2007


Log message for revision 72878:
  merged ajung-blobs branch providing a file implementation supporting
  ZODB blobs
  

Changed:
  U   zope.file/trunk/src/zope/file/README.txt
  U   zope.file/trunk/src/zope/file/browser.txt
  U   zope.file/trunk/src/zope/file/configure.zcml
  U   zope.file/trunk/src/zope/file/download.py
  U   zope.file/trunk/src/zope/file/file.py
  U   zope.file/trunk/src/zope/file/interfaces.py

-=-
Modified: zope.file/trunk/src/zope/file/README.txt
===================================================================
--- zope.file/trunk/src/zope/file/README.txt	2007-02-27 14:54:21 UTC (rev 72877)
+++ zope.file/trunk/src/zope/file/README.txt	2007-02-27 15:04:01 UTC (rev 72878)
@@ -88,37 +88,28 @@
 the file object::
 
   >>> w.flush()
+
+We need to close the file first before determining its file size
+
+  >>> w.close()
   >>> f.size
   19
 
 We can now use a reader to see that the data has been written to the
 file::
 
-  >>> r = f.open("rb")
-  >>> r.read()
-  'some text more text'
-  >>> r.read()
-  ''
-  >>> r.tell()
-  19
-
-The writer can continue to be used to add data::
-
+  >>> w = f.open("w")
+  >>> w.write('some text more text')
   >>> w.write(" still more")
-  >>> w.flush()
+  >>> w.close()
   >>> f.size
   30
 
-The reader can now see the new data, and continue reading from where
-it was::
 
-  >>> r.read(6)
-  ' still'
-  >>> r.read()
-  ' more'
-  >>> r.read()
-  ''
+Now create a new reader and let's perform some seek operations.
 
+  >>> r = f.open()
+
 The reader also has a `seek()` method that can be used to back up or
 skip forward in the data stream.  Simply passing an offset argument,
 we see that the current position is moved to that offset from the
@@ -158,29 +149,13 @@
 
   >>> r.close()
 
-Using a new reader, we can see how `seek()` can be used to skip
-forward::
 
-  >>> r = f.open("r")
-  >>> r.seek(20)
-  >>> r.read()
-  'still more'
+Attempting to write to a closed writer raises an exception::
 
-Now, our writer is still useful, so let's add some more data and make
-sure we can seek into that with our reader.  We'll also see that
-closing the writer causes it to flush any buffered data::
 
-  >>> w.write(" woohoo!")
-  >>> w.close()
-  >>> f.size
-  38
+  >>> w = f.open('w')
+  >>> w.close()  
 
-  >>> r.seek(4, 1)
-  >>> r.read()
-  'hoo!'
-
-Attempting to write to the closed writer raises an exception::
-
   >>> w.write('foobar')
   Traceback (most recent call last):
   ValueError: I/O operation on closed file
@@ -197,37 +172,3 @@
   Traceback (most recent call last):
   ValueError: I/O operation on closed file
 
-The file object also supports the '+' mode--both reading and writing
-simultaneously.  This can be convenient for allowing it to be used with
-tools (such as the TIFF PIL plugin as of this writing) with features
-that expect files in this mode.
-
-  >>> rw = f.open('r+')
-  >>> rw.tell()
-  0L
-  >>> rw.read()
-  'some text more text still more woohoo!'
-  >>> rw.tell()
-  38
-  >>> rw.write(' yippee!')
-  >>> rw.seek(31)
-  >>> rw.read()
-  'woohoo! yippee!'
-  >>> rw.seek(31)
-  >>> rw.write('THE END')
-  >>> rw.seek(0)
-  >>> rw.read()
-  'some text more text still more THE END yippee!'
-  >>> rw.close()
-  >>> rw = f.open('w+')
-  >>> rw.tell()
-  0L
-  >>> rw.read()
-  ''
-  >>> rw.write('hi.')
-  >>> rw.tell()
-  3
-  >>> rw.seek(0)
-  >>> rw.read()
-  'hi.'
-  >>> rw.close()

Modified: zope.file/trunk/src/zope/file/browser.txt
===================================================================
--- zope.file/trunk/src/zope/file/browser.txt	2007-02-27 14:54:21 UTC (rev 72877)
+++ zope.file/trunk/src/zope/file/browser.txt	2007-02-27 15:04:01 UTC (rev 72878)
@@ -29,7 +29,7 @@
 
   >>> w = f.open('wb')
   >>> w.write("some text")
-  >>> w.flush()
+  >>> w.close()
 
 The sized adapter now reflects the updated size::
 
@@ -40,11 +40,12 @@
 
 Let's try again with a larger file size::
 
-  >>> w.write("x" * 1024*1024)
-  >>> w.flush()
+  >>> w = f.open('w')
+  >>> w.write("x" * (1024*1024+10))
+  >>> w.close()
 
   >>> s.sizeForSorting()
-  ('byte', 1048585)
+  ('byte', 1048586)
   >>> m = s.sizeForDisplay()
   >>> m
   u'${size} MB'
@@ -53,11 +54,12 @@
 
 And still a bigger size::
 
-  >>> w.write("x" * 512*1024)
+  >>> w = f.open('w')
+  >>> w.write("x" * 3*512*1024)
   >>> w.close()
 
   >>> s.sizeForSorting()
-  ('byte', 1572873)
+  ('byte', 1572864)
   >>> m = s.sizeForDisplay()
   >>> m
   u'${size} MB'

Modified: zope.file/trunk/src/zope/file/configure.zcml
===================================================================
--- zope.file/trunk/src/zope/file/configure.zcml	2007-02-27 14:54:21 UTC (rev 72877)
+++ zope.file/trunk/src/zope/file/configure.zcml	2007-02-27 15:04:01 UTC (rev 72878)
@@ -14,6 +14,10 @@
         permission="zope.ManageContent"
         set_attributes="mimeType parameters"
         />
+    <require
+        permission="zope.ManageContent"
+        attributes="openDetached"
+        />
     <implements
         interface="
           zope.annotation.interfaces.IAttributeAnnotatable
@@ -25,23 +29,22 @@
   <adapter factory=".adapters.ReadFileAdapter" />
   <adapter factory=".adapters.WriteFileAdapter" />
 
-  <!-- set up permissions for the accessor objects -->
-
-  <class class=".file.Reader">
+  <class class="ZODB.Blobs.Blob.BlobFile">
     <require
         permission="zope.View"
-        interface=".interfaces.IFileReader"
+        attributes="read openDetached"
         />
+    <require
+        permission="zope.ManageContent"
+        attributes="write close"
+        />
   </class>
 
+
   <class class=".file.Writer">
     <require
-        permission="zope.View"
-        attributes="mode"
-        />
-    <require
         permission="zope.ManageContent"
-        attributes="close flush write"
+        attributes="write close"
         />
   </class>
 

Modified: zope.file/trunk/src/zope/file/download.py
===================================================================
--- zope.file/trunk/src/zope/file/download.py	2007-02-27 14:54:21 UTC (rev 72877)
+++ zope.file/trunk/src/zope/file/download.py	2007-02-27 15:04:01 UTC (rev 72878)
@@ -21,6 +21,7 @@
 import zope.mimetype.interfaces
 import zope.publisher.browser
 import zope.publisher.http
+from zope.proxy import removeAllProxies
 
 
 class Download(zope.publisher.browser.BrowserView):
@@ -48,13 +49,7 @@
         zope.publisher.http.IResult)
 
     def getFile(self, context):
-        # This ensures that what's left has no connection to the
-        # application/database; ZODB BLOBs will provide a equivalent
-        # feature once available.
-        f = context.open('rb')
-        res = cStringIO.StringIO(f.read())
-        f.close()
-        return res
+        return removeAllProxies(context.openDetached())
 
     def __init__(self, context, contentType=None, downloadName=None,
                  contentDisposition=None, contentLength=None):

Modified: zope.file/trunk/src/zope/file/file.py
===================================================================
--- zope.file/trunk/src/zope/file/file.py	2007-02-27 14:54:21 UTC (rev 72877)
+++ zope.file/trunk/src/zope/file/file.py	2007-02-27 15:04:01 UTC (rev 72878)
@@ -15,6 +15,7 @@
 """
 __docformat__ = "reStructuredText"
 
+import sys
 import cStringIO
 
 import persistent
@@ -23,6 +24,7 @@
 import zope.file.interfaces
 import zope.interface
 
+from ZODB.Blobs.Blob import Blob
 
 class File(persistent.Persistent):
 
@@ -44,24 +46,39 @@
         else:
             parameters = dict(parameters)
         self.parameters = parameters
+        self._data = Blob()
+        fp = self._data.open('w')
+        fp.write('')
+        fp.close()
 
     def open(self, mode="r"):
-        if mode in ("r", "rb"):
+        if mode.startswith("r"):
             return Reader(self, mode)
-        if mode in ("w", "wb"):
+        if mode.startswith("w"):
             return Writer(self, mode)
-        if mode in ("r+", "r+b", "rb+"):
-            return ReaderPlus(self, mode)
-        if mode in ("w+", "w+b", "wb+"):
-            return WriterPlus(self, mode)
         raise ValueError("unsupported `mode` value")
 
+    def openDetached(self):
+        return self._data.openDetached()
 
+    @property
+    def size(self):
+        if self._data == "":
+            return 0
+        reader = self.open()
+        reader.seek(0,2)
+        size = int(reader.tell())
+        reader.close()
+        return size
+
+
 class Accessor(object):
     """Base class for the reader and writer."""
 
     _closed = False
     _sio = None
+    _write = False
+    mode = None
 
     # XXX Accessor objects need to have an __parent__ to support the
     # security machinery, but they aren't ILocation instances since
@@ -74,13 +91,12 @@
     def __init__(self, file, mode):
         self.__parent__ = file
         self.mode = mode
+        self._stream = self.__parent__._data.open(mode)
 
     def close(self):
         if not self._closed:
             self._close()
             self._closed = True
-            if "_sio" in self.__dict__:
-                del self._sio
 
     def __getstate__(self):
         """Make sure the accessors can't be stored in ZODB."""
@@ -88,29 +104,8 @@
         raise TypeError("%s.%s instance is not picklable"
                         % (cls.__module__, cls.__name__))
 
-    _write = False
-
     def _get_stream(self):
-        # get the right string io
-        if self._sio is None:
-            self._data = self.__parent__._data
-            # create if we don't have one yet
-            self._sio = cStringIO.StringIO() # cStringIO creates immutable
-            # instance if you pass a string, unlike StringIO :-/
-            if not self._write:
-                self._sio.write(self._data)
-                self._sio.seek(0)
-        elif self._data is not self.__parent__._data:
-            # if the data for the underlying object has changed,
-            # update our view of the data:
-            pos = self._sio.tell()
-            self._data = self.__parent__._data
-            self._sio = cStringIO.StringIO()
-            self._sio.write(self._data)
-            self._sio.seek(pos) # this may seek beyond EOF, but that appears to
-            # be how it is supposed to work, based on experiments.  Writing
-            # will insert NULLs in the previous positions.
-        return self._sio
+        return self._stream
 
     def _close(self):
         pass
@@ -138,12 +133,12 @@
     def tell(self):
         if self._closed:
             raise ValueError("I/O operation on closed file")
-        if self._sio is None:
-            return 0L
-        else:
-            return self._sio.tell()
+        return int(self._get_stream().tell())
 
+    def _close(self):
+        self._get_stream().close()
 
+
 class Writer(Accessor):
 
     zope.interface.implements(
@@ -154,22 +149,13 @@
     def flush(self):
         if self._closed:
             raise ValueError("I/O operation on closed file")
-        if self._sio is not None:
-            self.__parent__._data = self._sio.getvalue()
-            self.__parent__.size = len(self.__parent__._data)
-            self._data = self.__parent__._data
-
+        self._get_stream().flush()
+    
     def write(self, data):
         if self._closed:
             raise ValueError("I/O operation on closed file")
         self._get_stream().write(data)
 
     def _close(self):
-        self.flush()
+        self._get_stream().close()
 
-class WriterPlus(Writer, Reader):
-    pass
-
-class ReaderPlus(Writer, Reader):
-
-    _write = False

Modified: zope.file/trunk/src/zope/file/interfaces.py
===================================================================
--- zope.file/trunk/src/zope/file/interfaces.py	2007-02-27 14:54:21 UTC (rev 72877)
+++ zope.file/trunk/src/zope/file/interfaces.py	2007-02-27 15:04:01 UTC (rev 72878)
@@ -42,7 +42,23 @@
         All readers and writers operate in 'binary' mode.
 
         """
+    def open():
+        """Return an object providing access to the file data.
 
+        Allowed values for `mode` are 'r' and 'rb' (read); 'w' and
+        'wb' (write); and 'w+', 'w+b', 'wb+', 'r+', 'r+b', and 'rb+' (both).
+        Other values cause `ValueError` to be raised.
+
+        If the file is opened in read mode, an `IFileReader` is
+        returned; if opened in write mode, an `IFileWriter` is
+        returned; if in read/write, an object that implements both is
+        returned.
+
+        All readers and writers operate in 'binary' mode.
+
+        """
+
+
     size = zope.schema.Int(
         title=_("Size"),
         description=_("Size in bytes"),



More information about the Checkins mailing list