[Checkins] SVN: zope.file/branches/ajung-blobs/src/zope/file/file.py re-added Reader/Writer classes...don't try to be smarter than Fred :-)

Andreas Jung andreas at andreas-jung.com
Mon Feb 26 15:06:03 EST 2007


Log message for revision 72837:
  re-added Reader/Writer classes...don't try to be smarter than Fred :-)
  
  

Changed:
  U   zope.file/branches/ajung-blobs/src/zope/file/file.py

-=-
Modified: zope.file/branches/ajung-blobs/src/zope/file/file.py
===================================================================
--- zope.file/branches/ajung-blobs/src/zope/file/file.py	2007-02-26 20:01:06 UTC (rev 72836)
+++ zope.file/branches/ajung-blobs/src/zope/file/file.py	2007-02-26 20:06:02 UTC (rev 72837)
@@ -22,9 +22,9 @@
 import zope.location.interfaces
 import zope.file.interfaces
 import zope.interface
+
 from ZODB.Blobs.Blob import Blob
 
-
 class File(persistent.Persistent):
 
     zope.interface.implements(
@@ -35,6 +35,9 @@
     __parent__ = None
     mimeType = None
 
+    _data = ""
+    size = 0
+
     def __init__(self, mimeType=None, parameters=None):
         self.mimeType = mimeType
         if parameters is None:
@@ -42,21 +45,135 @@
         else:
             parameters = dict(parameters)
         self.parameters = parameters
-        self._data = Blob()
 
     def open(self, mode="r"):
-        return self._data.open(mode)
+        if mode.startswith("r"):
+            return Reader(self, mode)
+        if mode.startswith("w"):
+            return Writer(self, mode)
+        raise ValueError("unsupported `mode` value")
 
     def openDetached(self):
         return self._data.openDetached()
 
-
     @property
     def size(self):
-        fp = self._data.open()
+        fp = self._data.open('r')
         fp.seek(0, 2)
-        size = fp.tell()
+        size = int(fp.tell())
         fp.close()
         return size
-            
 
+
+class Accessor(object):
+    """Base class for the reader and writer."""
+
+    _closed = False
+    _sio = None
+
+    # XXX Accessor objects need to have an __parent__ to support the
+    # security machinery, but they aren't ILocation instances since
+    # they aren't addressable via URL.
+    #
+    # There needs to be an interface for this in Zope 3, but that's a
+    # large task since it affects lots of Z3 code.  __parent__ should
+    # be defined by an interface from which ILocation is derived.
+
+    def __init__(self, file, mode):
+        self.__parent__ = file
+        self.mode = 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."""
+        cls = self.__class__
+        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 = Blob() # cStringIO creates immutable
+            fp = self._sio.open('w')
+            fp.write('')
+            # instance if you pass a string, unlike StringIO :-/
+            if not self._write:
+                fp.write(self._data)
+                fp.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 = Blob()
+            fp = self._sio.open('w')
+            fp.write(self._data)
+            fp.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 fp
+
+    def _close(self):
+        pass
+
+
+class Reader(Accessor):
+
+    zope.interface.implements(
+        zope.file.interfaces.IFileReader)
+
+    _data = File._data
+
+    def read(self, size=-1):
+        if self._closed:
+            raise ValueError("I/O operation on closed file")
+        return self._get_stream().read(size)
+
+    def seek(self, offset, whence=0):
+        if self._closed:
+            raise ValueError("I/O operation on closed file")
+        if whence not in (0, 1, 2):
+            raise ValueError("illegal value for `whence`")
+        self._get_stream().seek(offset, whence)
+
+    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()
+
+
+class Writer(Accessor):
+
+    zope.interface.implements(
+        zope.file.interfaces.IFileWriter)
+
+    _write = True
+
+    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
+            self._data = self.__parent__._data
+
+    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()
+



More information about the Checkins mailing list